diff --git a/SOURCES/0001-kernel-install-add-fedora-specific-callouts-to-new-k.patch b/SOURCES/0001-kernel-install-add-fedora-specific-callouts-to-new-k.patch new file mode 100644 index 00000000..d35373b6 --- /dev/null +++ b/SOURCES/0001-kernel-install-add-fedora-specific-callouts-to-new-k.patch @@ -0,0 +1,60 @@ +From 139d2c57d86203e421b17a4b6ec168c49fcb9893 Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Tue, 14 Jan 2014 17:48:08 -0500 +Subject: [PATCH] kernel-install: add fedora specific callouts to + new-kernel-pkg + +--- + src/kernel-install/kernel-install | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + mode change 100644 => 100755 src/kernel-install/kernel-install + +diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install +old mode 100644 +new mode 100755 +index 3ae1d77e3..f1c74de27 +--- a/src/kernel-install/kernel-install ++++ b/src/kernel-install/kernel-install +@@ -71,6 +71,42 @@ fi + KERNEL_VERSION="$1" + KERNEL_IMAGE="$2" + ++if [[ -x /sbin/new-kernel-pkg ]]; then ++ KERNEL_DIR="${KERNEL_IMAGE%/*}" ++ if [[ "${KERNEL_DIR}" != "/boot" ]]; then ++ for i in \ ++ "$KERNEL_IMAGE" \ ++ "$KERNEL_DIR/.${KERNEL_IMAGE##*/}.hmac" \ ++ "$KERNEL_DIR"/System.map \ ++ "$KERNEL_DIR"/config \ ++ "$KERNEL_DIR"/zImage.stub \ ++ "$KERNEL_DIR"/dtb \ ++ ; do ++ [[ -e "$i" ]] || continue ++ cp -a "$i" "/boot/${i##*/}-${KERNEL_VERSION}" ++ done ++ fi ++ ++ [[ "$KERNEL_VERSION" == *\+* ]] && flavor=-"${KERNEL_VERSION##*+}" ++ case "$COMMAND" in ++ add) ++ /sbin/new-kernel-pkg --package "kernel${flavor}" --install "$KERNEL_VERSION" || exit $? ++ /sbin/new-kernel-pkg --package "kernel${flavor}" --mkinitrd --dracut --depmod --update "$KERNEL_VERSION" || exit $? ++ /sbin/new-kernel-pkg --package "kernel${flavor}" --rpmposttrans "$KERNEL_VERSION" || exit $? ++ ;; ++ remove) ++ /sbin/new-kernel-pkg --package "kernel${flavor+-$flavor}" --rminitrd --rmmoddep --remove "$KERNEL_VERSION" || exit $? ++ ;; ++ *) ++ ;; ++ esac ++ ++ # exit, if we can't find a boot loader spec conforming setup ++ if ! [[ -d /boot/loader/entries || -L /boot/loader/entries ]]; then ++ exit 0 ++ fi ++fi ++ + if [[ -f /etc/machine-id ]]; then + read MACHINE_ID < /etc/machine-id + fi diff --git a/SOURCES/0002-Revert-fsck-re-enable-fsck-l.patch b/SOURCES/0002-Revert-fsck-re-enable-fsck-l.patch new file mode 100644 index 00000000..8adaa526 --- /dev/null +++ b/SOURCES/0002-Revert-fsck-re-enable-fsck-l.patch @@ -0,0 +1,55 @@ +From 42026958cced6fe111bbaccad04d24d8ca3d6c55 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 14 Nov 2014 17:07:57 +0100 +Subject: [PATCH] Revert "fsck: re-enable fsck -l" + +This reverts commit 48d3e8d07f2978f001cc85b2dddb7f8ec9d07006. + +(We have older util-linux in rhel7)) + +Conflicts: + README +--- + README | 3 ++- + src/fsck/fsck.c | 13 +++++++++---- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/README b/README +index c72209262..5f5783a68 100644 +--- a/README ++++ b/README +@@ -135,7 +135,8 @@ REQUIREMENTS: + During runtime, you need the following additional + dependencies: + +- util-linux >= v2.25 required ++ util-linux >= v2.19 (requires fsck -l, agetty -s), ++ v2.21 required for tests in test/ + dbus >= 1.4.0 (strictly speaking optional, but recommended) + dracut (optional) + PolicyKit (optional) +diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c +index 78ceeb6fa..d8976809d 100644 +--- a/src/fsck/fsck.c ++++ b/src/fsck/fsck.c +@@ -323,11 +323,16 @@ int main(int argc, char *argv[]) { + cmdline[i++] = "-T"; + + /* +- * Since util-linux v2.25 fsck uses /run/fsck/.lock files. +- * The previous versions use flock for the device and conflict with +- * udevd, see https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5 ++ * Disable locking which conflict with udev's event ++ * ownershipi, until util-linux moves the flock ++ * synchronization file which prevents multiple fsck running ++ * on the same rotationg media, from the disk device ++ * node to a privately owned regular file. ++ * ++ * https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5 ++ * ++ * cmdline[i++] = "-l"; + */ +- cmdline[i++] = "-l"; + + if (!root_directory) + cmdline[i++] = "-M"; diff --git a/SOURCES/0003-sysctl-bring-back-etc-sysctl.conf.patch b/SOURCES/0003-sysctl-bring-back-etc-sysctl.conf.patch new file mode 100644 index 00000000..b1ba2d4c --- /dev/null +++ b/SOURCES/0003-sysctl-bring-back-etc-sysctl.conf.patch @@ -0,0 +1,25 @@ +From d2deeea1d5aa1d13139b9e9f70c6655abb589530 Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Mon, 11 Nov 2013 11:17:57 +0100 +Subject: [PATCH] sysctl: bring back /etc/sysctl.conf + +Read /etc/sysctl.conf as the last file, overwriting everything. +--- + src/sysctl/sysctl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c +index 275a5b74a..d007c932c 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -320,6 +320,10 @@ int main(int argc, char *argv[]) { + if (k < 0 && r == 0) + r = k; + } ++ ++ k = parse_file(sysctl_options, "/etc/sysctl.conf", true); ++ if (k < 0 && r == 0) ++ r = k; + } + + k = apply_all(sysctl_options); diff --git a/SOURCES/0004-remove-user-.service.patch b/SOURCES/0004-remove-user-.service.patch new file mode 100644 index 00000000..0ea024fc --- /dev/null +++ b/SOURCES/0004-remove-user-.service.patch @@ -0,0 +1,88 @@ +From cd37b8d217cc240074f8ff77f1986551f6c8834a Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 14 Nov 2014 17:32:10 +0100 +Subject: [PATCH] remove user@.service + +Conflicts: + Makefile.am +--- + Makefile.am | 2 -- + src/login/logind-user.c | 38 -------------------------------------- + 2 files changed, 40 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index bf04d3184..75459f74d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -535,7 +535,6 @@ nodist_systemunit_DATA = \ + units/systemd-sysctl.service \ + units/emergency.service \ + units/rescue.service \ +- units/user@.service \ + units/systemd-suspend.service \ + units/systemd-halt.service \ + units/systemd-poweroff.service \ +@@ -597,7 +596,6 @@ EXTRA_DIST += \ + units/systemd-fsck@.service.in \ + units/systemd-fsck-root.service.in \ + units/systemd-machine-id-commit.service.in \ +- units/user@.service.m4.in \ + units/debug-shell.service.in \ + units/systemd-suspend.service.in \ + units/quotaon.service.in \ +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index f4c4490e8..97eb4feca 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -399,39 +399,6 @@ static int user_start_slice(User *u) { + return 0; + } + +-static int user_start_service(User *u) { +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- char *job; +- int r; +- +- assert(u); +- +- if (!u->service) { +- char lu[DECIMAL_STR_MAX(uid_t) + 1], *service; +- sprintf(lu, UID_FMT, u->uid); +- +- service = unit_name_build("user", lu, ".service"); +- if (!service) +- return log_oom(); +- +- r = manager_start_unit(u->manager, service, &error, &job); +- if (r < 0) { +- log_error("Failed to start user service: %s", bus_error_message(&error, r)); +- free(service); +- } else { +- u->service = service; +- +- free(u->service_job); +- u->service_job = job; +- } +- } +- +- if (u->service) +- hashmap_put(u->manager->user_units, u->service, u); +- +- return 0; +-} +- + int user_start(User *u) { + int r; + +@@ -452,11 +419,6 @@ int user_start(User *u) { + if (r < 0) + return r; + +- /* Spawn user systemd */ +- r = user_start_service(u); +- if (r < 0) +- return r; +- + if (!dual_timestamp_is_set(&u->timestamp)) + dual_timestamp_get(&u->timestamp); + diff --git a/SOURCES/0005-logind-session-save-stopping-flag.patch b/SOURCES/0005-logind-session-save-stopping-flag.patch new file mode 100644 index 00000000..e478ac65 --- /dev/null +++ b/SOURCES/0005-logind-session-save-stopping-flag.patch @@ -0,0 +1,63 @@ +From 932ae09a155ef463d99d4b4e7cf04aafbcd78a19 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 2 Apr 2014 14:41:26 +0200 +Subject: [PATCH] logind-session: save stopping flag + +Conflicts: + src/login/logind-session.c +--- + src/login/logind-session.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index a02a537f7..d2e7b4012 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -181,12 +181,14 @@ int session_save(Session *s) { + "USER=%s\n" + "ACTIVE=%i\n" + "STATE=%s\n" +- "REMOTE=%i\n", +- s->user->uid, ++ "REMOTE=%i\n" ++ "STOPPING=%i\n", ++ (unsigned long) s->user->uid, + s->user->name, + session_is_active(s), + session_state_to_string(session_get_state(s)), +- s->remote); ++ s->remote, ++ s->stopping); + + if (s->type >= 0) + fprintf(f, "TYPE=%s\n", session_type_to_string(s->type)); +@@ -309,7 +311,8 @@ int session_load(Session *s) { + *uid = NULL, + *realtime = NULL, + *monotonic = NULL, +- *controller = NULL; ++ *controller = NULL, ++ *stopping = NULL; + + int k, r; + +@@ -337,6 +340,7 @@ int session_load(Session *s) { + "REALTIME", &realtime, + "MONOTONIC", &monotonic, + "CONTROLLER", &controller, ++ "STOPPING", &stopping, + NULL); + + if (r < 0) +@@ -453,6 +457,11 @@ int session_load(Session *s) { + session_restore_vt(s); + } + ++ if (stopping) { ++ k = parse_boolean(stopping); ++ if (k >= 0) ++ s->stopping = k; ++ } + return r; + } + diff --git a/SOURCES/0006-man-mention-System-Administrator-s-Guide-in-systemct.patch b/SOURCES/0006-man-mention-System-Administrator-s-Guide-in-systemct.patch new file mode 100644 index 00000000..e536cd86 --- /dev/null +++ b/SOURCES/0006-man-mention-System-Administrator-s-Guide-in-systemct.patch @@ -0,0 +1,33 @@ +From d4582346f47064de24470b5f92e418966004925f Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 28 Aug 2014 15:12:10 +0200 +Subject: [PATCH] man: mention System Administrator's Guide in systemctl + manpage + +Resolves: #978948 +--- + man/systemctl.xml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 338c1d328..6f30474c3 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -1713,6 +1713,17 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + + + ++ ++ Examples ++ ++ For examples how to use systemctl in comparsion ++ with old service and chkconfig command please see: ++ ++ Managing System Services ++ ++ ++ ++ + + See Also + diff --git a/SOURCES/0007-rules-automatically-online-hot-added-CPUs.patch b/SOURCES/0007-rules-automatically-online-hot-added-CPUs.patch new file mode 100644 index 00000000..df8ec5c6 --- /dev/null +++ b/SOURCES/0007-rules-automatically-online-hot-added-CPUs.patch @@ -0,0 +1,40 @@ +From cb0c7e5445624b7bc67fc4c10a91d5cf3dd6ce6f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 22 Sep 2014 07:41:06 +0200 +Subject: [PATCH] rules: automatically online hot-added CPUs + +RHEL-only patch + +Resolves: #968811 + +Conflicts: + Makefile.am +--- + Makefile.am | 3 ++- + rules/40-redhat.rules | 3 +++ + 2 files changed, 5 insertions(+), 1 deletion(-) + create mode 100644 rules/40-redhat.rules + +diff --git a/Makefile.am b/Makefile.am +index 75459f74d..a734e9c48 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3564,7 +3564,8 @@ dist_udevrules_DATA += \ + rules/75-tty-description.rules \ + rules/78-sound-card.rules \ + rules/80-net-setup-link.rules \ +- rules/95-udev-late.rules ++ rules/95-udev-late.rules \ ++ rules/40-redhat.rules + + nodist_udevrules_DATA += \ + rules/99-systemd.rules +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +new file mode 100644 +index 000000000..2b494e57c +--- /dev/null ++++ b/rules/40-redhat.rules +@@ -0,0 +1,3 @@ ++# do not edit this file, it will be overwritten on update ++ ++SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" diff --git a/SOURCES/0008-Revert-remove-references-of-readahead.patch b/SOURCES/0008-Revert-remove-references-of-readahead.patch new file mode 100644 index 00000000..264938b8 --- /dev/null +++ b/SOURCES/0008-Revert-remove-references-of-readahead.patch @@ -0,0 +1,54 @@ +From 1b83fbe90a241c6d5c4ab0dc8a3f97215fb277bf Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 19 Nov 2014 12:14:00 +0100 +Subject: [PATCH] Revert "remove references of readahead" + +This reverts commit 3b71c18d3e3906f8606c66bea98b327684394e61. +--- + .gitignore | 1 + + README | 1 + + TODO | 7 +++++++ + 3 files changed, 9 insertions(+) + +diff --git a/.gitignore b/.gitignore +index e8a4085a3..0360f7c6b 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -107,6 +107,7 @@ + /systemd-quotacheck + /systemd-random-seed + /systemd-rc-local-generator ++/systemd-readahead + /systemd-remount-api-vfs + /systemd-remount-fs + /systemd-reply-password +diff --git a/README b/README +index 5f5783a68..287d05c9b 100644 +--- a/README ++++ b/README +@@ -30,6 +30,7 @@ AUTHOR: + + LICENSE: + LGPLv2.1+ for all code ++ - except sd-readahead.[ch] which is MIT + - except src/shared/MurmurHash2.c which is Public Domain + - except src/shared/siphash24.c which is CC0 Public Domain + - except src/journal/lookup3.c which is Public Domain +diff --git a/TODO b/TODO +index 255a4f2d0..90b2c4b30 100644 +--- a/TODO ++++ b/TODO +@@ -786,6 +786,13 @@ Features: + + * and a dbus call to generate target from current state + ++* readahead: ++ - drop /.readahead on bigger upgrades with yum ++ - move readahead files into /var (look for them with .path units?) ++ - readahead: use BTRFS_IOC_DEFRAG_RANGE instead of BTRFS_IOC_DEFRAG ioctl, with START_IO ++ - readahead: when bumping /sys readahead variable save mtime and compare later to detect changes ++ - readahead: make use of EXT4_IOC_MOVE_EXT, as used by http://e4rat.sourceforge.net/ ++ + * GC unreferenced jobs (such as .device jobs) + + * write blog stories about: diff --git a/SOURCES/0009-Revert-missing-remove-fanotify.patch b/SOURCES/0009-Revert-missing-remove-fanotify.patch new file mode 100644 index 00000000..c5694646 --- /dev/null +++ b/SOURCES/0009-Revert-missing-remove-fanotify.patch @@ -0,0 +1,220 @@ +From 66d06bd0a577ddb2461e8d1e5c8c2fbf6845227d Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 19 Nov 2014 12:14:13 +0100 +Subject: [PATCH] Revert "missing: remove fanotify" + +This reverts commit c7e4a7bece7a5c4484d229dd5e8ff01a5d49c62e. + +Conflicts: + src/shared/missing.h +--- + Makefile.am | 1 + + configure.ac | 1 + + src/shared/linux/fanotify.h | 98 +++++++++++++++++++++++++++++++++++++++++++++ + src/shared/missing.h | 64 +++++++++++++++++++++++++++++ + 4 files changed, 164 insertions(+) + create mode 100644 src/shared/linux/fanotify.h + +diff --git a/Makefile.am b/Makefile.am +index a734e9c48..70e4fbc6d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -749,6 +749,7 @@ libsystemd_shared_la_SOURCES = \ + src/shared/capability.c \ + src/shared/capability.h \ + src/shared/linux/auto_dev-ioctl.h \ ++ src/shared/linux/fanotify.h \ + src/shared/ioprio.h \ + src/shared/missing.h \ + src/shared/initreq.h \ +diff --git a/configure.ac b/configure.ac +index 97a29d63f..3f50887a8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -310,6 +310,7 @@ RT_LIBS="$LIBS" + AC_SUBST(RT_LIBS) + LIBS="$save_LIBS" + ++AC_CHECK_FUNCS([fanotify_init fanotify_mark]) + AC_CHECK_FUNCS([memfd_create]) + AC_CHECK_FUNCS([__secure_getenv secure_getenv]) + AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, LO_FLAGS_PARTSCAN], +diff --git a/src/shared/linux/fanotify.h b/src/shared/linux/fanotify.h +new file mode 100644 +index 000000000..5cc1a7e67 +--- /dev/null ++++ b/src/shared/linux/fanotify.h +@@ -0,0 +1,98 @@ ++#ifndef _LINUX_FANOTIFY_H ++#define _LINUX_FANOTIFY_H ++ ++#include ++ ++/* the following events that user-space can register for */ ++#define FAN_ACCESS 0x00000001 /* File was accessed */ ++#define FAN_MODIFY 0x00000002 /* File was modified */ ++#define FAN_CLOSE_WRITE 0x00000008 /* Unwrittable file closed */ ++#define FAN_CLOSE_NOWRITE 0x00000010 /* Writtable file closed */ ++#define FAN_OPEN 0x00000020 /* File was opened */ ++ ++#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */ ++ ++/* FIXME currently Q's have no limit.... */ ++#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ ++ ++#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ ++#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ ++ ++/* helper events */ ++#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */ ++ ++/* flags used for fanotify_init() */ ++#define FAN_CLOEXEC 0x00000001 ++#define FAN_NONBLOCK 0x00000002 ++ ++#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK) ++ ++/* flags used for fanotify_modify_mark() */ ++#define FAN_MARK_ADD 0x00000001 ++#define FAN_MARK_REMOVE 0x00000002 ++#define FAN_MARK_DONT_FOLLOW 0x00000004 ++#define FAN_MARK_ONLYDIR 0x00000008 ++#define FAN_MARK_MOUNT 0x00000010 ++#define FAN_MARK_IGNORED_MASK 0x00000020 ++#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040 ++#define FAN_MARK_FLUSH 0x00000080 ++ ++#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ ++ FAN_MARK_REMOVE |\ ++ FAN_MARK_DONT_FOLLOW |\ ++ FAN_MARK_ONLYDIR |\ ++ FAN_MARK_MOUNT |\ ++ FAN_MARK_IGNORED_MASK |\ ++ FAN_MARK_IGNORED_SURV_MODIFY) ++ ++/* ++ * All of the events - we build the list by hand so that we can add flags in ++ * the future and not break backward compatibility. Apps will get only the ++ * events that they originally wanted. Be sure to add new events here! ++ */ ++#define FAN_ALL_EVENTS (FAN_ACCESS |\ ++ FAN_MODIFY |\ ++ FAN_CLOSE |\ ++ FAN_OPEN) ++ ++/* ++ * All events which require a permission response from userspace ++ */ ++#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\ ++ FAN_ACCESS_PERM) ++ ++#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\ ++ FAN_ALL_PERM_EVENTS |\ ++ FAN_Q_OVERFLOW) ++ ++#define FANOTIFY_METADATA_VERSION 2 ++ ++struct fanotify_event_metadata { ++ __u32 event_len; ++ __u32 vers; ++ __u64 mask; ++ __s32 fd; ++ __s32 pid; ++} __attribute__ ((packed)); ++ ++struct fanotify_response { ++ __s32 fd; ++ __u32 response; ++} __attribute__ ((packed)); ++ ++/* Legit userspace responses to a _PERM event */ ++#define FAN_ALLOW 0x01 ++#define FAN_DENY 0x02 ++ ++/* Helper functions to deal with fanotify_event_metadata buffers */ ++#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) ++ ++#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \ ++ (struct fanotify_event_metadata*)(((char *)(meta)) + \ ++ (meta)->event_len)) ++ ++#define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \ ++ (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \ ++ (long)(meta)->event_len <= (long)(len)) ++ ++#endif /* _LINUX_FANOTIFY_H */ +diff --git a/src/shared/missing.h b/src/shared/missing.h +index b33a70cb2..06a55769a 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -156,6 +156,70 @@ static inline int pivot_root(const char *new_root, const char *put_old) { + # endif + #endif + ++#ifdef __x86_64__ ++# ifndef __NR_fanotify_init ++# define __NR_fanotify_init 300 ++# endif ++# ifndef __NR_fanotify_mark ++# define __NR_fanotify_mark 301 ++# endif ++#elif defined _MIPS_SIM ++# if _MIPS_SIM == _MIPS_SIM_ABI32 ++# ifndef __NR_fanotify_init ++# define __NR_fanotify_init 4336 ++# endif ++# ifndef __NR_fanotify_mark ++# define __NR_fanotify_mark 4337 ++# endif ++# elif _MIPS_SIM == _MIPS_SIM_NABI32 ++# ifndef __NR_fanotify_init ++# define __NR_fanotify_init 6300 ++# endif ++# ifndef __NR_fanotify_mark ++# define __NR_fanotify_mark 6301 ++# endif ++# elif _MIPS_SIM == _MIPS_SIM_ABI64 ++# ifndef __NR_fanotify_init ++# define __NR_fanotify_init 5295 ++# endif ++# ifndef __NR_fanotify_mark ++# define __NR_fanotify_mark 5296 ++# endif ++# endif ++#else ++# ifndef __NR_fanotify_init ++# define __NR_fanotify_init 338 ++# endif ++# ifndef __NR_fanotify_mark ++# define __NR_fanotify_mark 339 ++# endif ++#endif ++ ++#ifndef HAVE_FANOTIFY_INIT ++static inline int fanotify_init(unsigned int flags, unsigned int event_f_flags) { ++ return syscall(__NR_fanotify_init, flags, event_f_flags); ++} ++#endif ++ ++#ifndef HAVE_FANOTIFY_MARK ++static inline int fanotify_mark(int fanotify_fd, unsigned int flags, uint64_t mask, ++ int dfd, const char *pathname) { ++#if defined _MIPS_SIM && _MIPS_SIM == _MIPS_SIM_ABI32 || defined __powerpc__ && !defined __powerpc64__ \ ++ || defined __arm__ && !defined __aarch64__ ++ union { ++ uint64_t _64; ++ uint32_t _32[2]; ++ } _mask; ++ _mask._64 = mask; ++ ++ return syscall(__NR_fanotify_mark, fanotify_fd, flags, ++ _mask._32[0], _mask._32[1], dfd, pathname); ++#else ++ return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname); ++#endif ++} ++#endif ++ + #ifndef HAVE_MEMFD_CREATE + static inline int memfd_create(const char *name, unsigned int flags) { + return syscall(__NR_memfd_create, name, flags); diff --git a/SOURCES/0010-Revert-readahead-wipe-out-readahead.patch b/SOURCES/0010-Revert-readahead-wipe-out-readahead.patch new file mode 100644 index 00000000..4970ed4c --- /dev/null +++ b/SOURCES/0010-Revert-readahead-wipe-out-readahead.patch @@ -0,0 +1,3376 @@ +From fff80c5a2aba519d1c58a1bfc7c0fa96b1e4c30c Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 19 Nov 2014 12:17:19 +0100 +Subject: [PATCH] Revert "readahead: wipe out readahead" + +This reverts commit d6bc8348d5be8576a475ac8ced2b0146e60fb71f. + +Conflicts: + units/systemd-firstboot.service.in + +Conflicts: + man/sd-daemon.xml + man/sd-login.xml + man/systemd-notify.xml + src/notify/notify.c +--- + Makefile-man.am | 31 ++ + Makefile.am | 54 +- + configure.ac | 9 + + man/sd-daemon.xml | 1 + + man/sd-login.xml | 1 + + man/sd-readahead.xml | 117 +++++ + man/sd_readahead.xml | 178 +++++++ + man/systemd-notify.xml | 11 + + man/systemd-readahead-replay.service.xml | 203 ++++++++ + po/POTFILES.skip | 1 + + shell-completion/zsh/_systemd | 3 +- + src/cryptsetup/cryptsetup-generator.c | 2 +- + src/gpt-auto-generator/gpt-auto-generator.c | 1 + + src/notify/notify.c | 20 +- + src/readahead/Makefile | 1 + + src/readahead/readahead-analyze.c | 146 ++++++ + src/readahead/readahead-collect.c | 650 ++++++++++++++++++++++++ + src/readahead/readahead-common.c | 398 +++++++++++++++ + src/readahead/readahead-common.h | 61 +++ + src/readahead/readahead-replay.c | 281 ++++++++++ + src/readahead/readahead.c | 163 ++++++ + src/readahead/sd-readahead.c | 89 ++++ + src/readahead/test-ssd.c | 41 ++ + src/systemd/sd-readahead.h | 73 +++ + system-preset/90-systemd.preset | 1 + + units/.gitignore | 3 + + units/ldconfig.service | 2 +- + units/quotaon.service.in | 2 +- + units/system-update.target | 2 +- + units/systemd-backlight@.service.in | 2 +- + units/systemd-binfmt.service.in | 2 +- + units/systemd-firstboot.service.in | 2 +- + units/systemd-fsck-root.service.in | 1 + + units/systemd-fsck@.service.in | 2 +- + units/systemd-hwdb-update.service.in | 2 +- + units/systemd-journal-catalog-update.service.in | 2 +- + units/systemd-modules-load.service.in | 1 + + units/systemd-quotacheck.service.in | 2 +- + units/systemd-random-seed.service.in | 2 +- + units/systemd-readahead-collect.service.in | 28 + + units/systemd-readahead-done.service.in | 22 + + units/systemd-readahead-done.timer | 22 + + units/systemd-readahead-drop.service | 19 + + units/systemd-readahead-replay.service.in | 26 + + units/systemd-remount-fs.service.in | 2 +- + units/systemd-rfkill@.service.in | 2 +- + units/systemd-sysctl.service.in | 1 + + units/systemd-sysusers.service.in | 2 +- + units/systemd-tmpfiles-clean.service.in | 2 +- + units/systemd-tmpfiles-setup-dev.service.in | 2 +- + units/systemd-tmpfiles-setup.service.in | 2 +- + units/systemd-update-done.service.in | 2 +- + units/systemd-update-utmp.service.in | 2 +- + units/systemd-vconsole-setup.service.in | 1 + + 54 files changed, 2675 insertions(+), 23 deletions(-) + create mode 100644 man/sd-readahead.xml + create mode 100644 man/sd_readahead.xml + create mode 100644 man/systemd-readahead-replay.service.xml + create mode 120000 src/readahead/Makefile + create mode 100644 src/readahead/readahead-analyze.c + create mode 100644 src/readahead/readahead-collect.c + create mode 100644 src/readahead/readahead-common.c + create mode 100644 src/readahead/readahead-common.h + create mode 100644 src/readahead/readahead-replay.c + create mode 100644 src/readahead/readahead.c + create mode 100644 src/readahead/sd-readahead.c + create mode 100644 src/readahead/test-ssd.c + create mode 100644 src/systemd/sd-readahead.h + create mode 100644 units/systemd-readahead-collect.service.in + create mode 100644 units/systemd-readahead-done.service.in + create mode 100644 units/systemd-readahead-done.timer + create mode 100644 units/systemd-readahead-drop.service + create mode 100644 units/systemd-readahead-replay.service.in + +diff --git a/Makefile-man.am b/Makefile-man.am +index d0fb9aa1a..ac6f69af7 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -1234,6 +1234,34 @@ man/systemd-random-seed.html: man/systemd-random-seed.service.html + + endif + ++if ENABLE_READAHEAD ++MANPAGES += \ ++ man/sd-readahead.3 \ ++ man/sd_readahead.3 \ ++ man/systemd-readahead-replay.service.8 ++MANPAGES_ALIAS += \ ++ man/systemd-readahead-collect.service.8 \ ++ man/systemd-readahead-done.service.8 \ ++ man/systemd-readahead-done.timer.8 \ ++ man/systemd-readahead.8 ++man/systemd-readahead-collect.service.8: man/systemd-readahead-replay.service.8 ++man/systemd-readahead-done.service.8: man/systemd-readahead-replay.service.8 ++man/systemd-readahead-done.timer.8: man/systemd-readahead-replay.service.8 ++man/systemd-readahead.8: man/systemd-readahead-replay.service.8 ++man/systemd-readahead-collect.service.html: man/systemd-readahead-replay.service.html ++ $(html-alias) ++ ++man/systemd-readahead-done.service.html: man/systemd-readahead-replay.service.html ++ $(html-alias) ++ ++man/systemd-readahead-done.timer.html: man/systemd-readahead-replay.service.html ++ $(html-alias) ++ ++man/systemd-readahead.html: man/systemd-readahead-replay.service.html ++ $(html-alias) ++ ++endif ++ + if ENABLE_RESOLVED + MANPAGES += \ + man/resolved.conf.5 \ +@@ -1660,6 +1688,7 @@ EXTRA_DIST += \ + man/sd-id128.xml \ + man/sd-journal.xml \ + man/sd-login.xml \ ++ man/sd-readahead.xml \ + man/sd_booted.xml \ + man/sd_bus_creds_get_pid.xml \ + man/sd_bus_creds_new_from_pid.xml \ +@@ -1707,6 +1736,7 @@ EXTRA_DIST += \ + man/sd_machine_get_class.xml \ + man/sd_notify.xml \ + man/sd_pid_get_session.xml \ ++ man/sd_readahead.xml \ + man/sd_seat_get_active.xml \ + man/sd_session_is_active.xml \ + man/sd_uid_get_state.xml \ +@@ -1766,6 +1796,7 @@ EXTRA_DIST += \ + man/systemd-path.xml \ + man/systemd-quotacheck.service.xml \ + man/systemd-random-seed.service.xml \ ++ man/systemd-readahead-replay.service.xml \ + man/systemd-remount-fs.service.xml \ + man/systemd-resolved.service.xml \ + man/systemd-rfkill@.service.xml \ +diff --git a/Makefile.am b/Makefile.am +index 70e4fbc6d..b0e4b5a42 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2603,7 +2603,8 @@ systemctl_LDADD = \ + + # ------------------------------------------------------------------------------ + systemd_notify_SOURCES = \ +- src/notify/notify.c ++ src/notify/notify.c \ ++ src/readahead/sd-readahead.c + + systemd_notify_LDADD = \ + libsystemd-internal.la \ +@@ -4735,6 +4736,57 @@ EXTRA_DIST += \ + src/vconsole/90-vconsole.rules.in \ + units/systemd-vconsole-setup.service.in + ++# ------------------------------------------------------------------------------ ++if ENABLE_READAHEAD ++systemd_readahead_SOURCES = \ ++ src/readahead/readahead.c \ ++ src/readahead/readahead-collect.c \ ++ src/readahead/readahead-replay.c \ ++ src/readahead/readahead-analyze.c \ ++ src/readahead/readahead-common.c \ ++ src/readahead/readahead-common.h ++ ++systemd_readahead_LDADD = \ ++ libsystemd-internal.la \ ++ libudev-internal.la \ ++ libsystemd-shared.la ++ ++dist_doc_DATA += \ ++ src/readahead/sd-readahead.c \ ++ src/systemd/sd-readahead.h ++ ++rootlibexec_PROGRAMS += \ ++ systemd-readahead ++ ++dist_systemunit_DATA += \ ++ units/systemd-readahead-drop.service \ ++ units/systemd-readahead-done.timer ++ ++nodist_systemunit_DATA += \ ++ units/systemd-readahead-collect.service \ ++ units/systemd-readahead-replay.service \ ++ units/systemd-readahead-done.service ++ ++manual_tests += \ ++ test-ssd ++ ++test_ssd_SOURCES = \ ++ src/readahead/test-ssd.c \ ++ src/readahead/readahead-common.c \ ++ src/readahead/readahead-common.h ++ ++test_ssd_LDADD = \ ++ libsystemd-internal.la \ ++ libudev-internal.la \ ++ libsystemd-shared.la ++ ++endif ++ ++EXTRA_DIST += \ ++ units/systemd-readahead-collect.service.in \ ++ units/systemd-readahead-replay.service.in \ ++ units/systemd-readahead-done.service.in ++ + # ------------------------------------------------------------------------------ + if ENABLE_BOOTCHART + systemd_bootchart_SOURCES = \ +diff --git a/configure.ac b/configure.ac +index 3f50887a8..f701bcf71 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -930,6 +930,14 @@ if test "x$enable_vconsole" != "xno"; then + fi + AM_CONDITIONAL(ENABLE_VCONSOLE, [test "$have_vconsole" = "yes"]) + ++# ------------------------------------------------------------------------------ ++have_readahead=no ++AC_ARG_ENABLE(readahead, AS_HELP_STRING([--disable-readahead], [disable readahead tools])) ++if test "x$enable_readahead" != "xno"; then ++ have_readahead=yes ++fi ++AM_CONDITIONAL(ENABLE_READAHEAD, [test "$have_readahead" = "yes"]) ++ + # ------------------------------------------------------------------------------ + have_bootchart=no + AC_ARG_ENABLE(bootchart, AS_HELP_STRING([--disable-bootchart], [disable bootchart tool])) +@@ -1474,6 +1482,7 @@ AC_MSG_RESULT([ + ELFUTILS: ${have_elfutils} + binfmt: ${have_binfmt} + vconsole: ${have_vconsole} ++ readahead: ${have_readahead} + bootchart: ${have_bootchart} + quotacheck: ${have_quotacheck} + tmpfiles: ${have_tmpfiles} +diff --git a/man/sd-daemon.xml b/man/sd-daemon.xml +index b7ba36365..b12abe2dc 100644 +--- a/man/sd-daemon.xml ++++ b/man/sd-daemon.xml +@@ -137,6 +137,7 @@ + systemd.service5, + systemd.socket5, + fprintf3, ++ sd-readahead3, + pkg-config1 + + +diff --git a/man/sd-login.xml b/man/sd-login.xml +index 328f71164..abcdb99f6 100644 +--- a/man/sd-login.xml ++++ b/man/sd-login.xml +@@ -128,6 +128,7 @@ + sd_get_seats3, + sd_login_monitor_new3, + sd-daemon3, ++ sd-readahead3, + pkg-config1 + + +diff --git a/man/sd-readahead.xml b/man/sd-readahead.xml +new file mode 100644 +index 000000000..bcc46b24d +--- /dev/null ++++ b/man/sd-readahead.xml +@@ -0,0 +1,117 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd-readahead ++ systemd ++ ++ ++ ++ Developer ++ Lennart ++ Poettering ++ lennart@poettering.net ++ ++ ++ ++ ++ ++ sd-readahead ++ 3 ++ ++ ++ ++ sd-readahead ++ Reference implementation of APIs for ++ controlling boot-time read-ahead ++ ++ ++ ++ ++ #include "sd-readahead.h" ++ ++ ++ ++ ++ Description ++ ++ sd-readahead.c and ++ sd-readahead.h provide a ++ reference implementation for APIs for controlling boot-time ++ read-ahead, as implemented by the read-ahead subsystem ++ of the ++ systemd1 ++ init system. ++ ++ See ++ sd_readahead3 ++ for more information about the function ++ implemented. ++ ++ ++ ++ Notes ++ ++ This interface is provided by the reference ++ implementation of APIs for controlling boot-time ++ read-ahead and distributed with the systemd ++ package. The algorithms it implements are simple, and ++ can easily be reimplemented in daemons if it is ++ important to support this interface without using the ++ reference implementation. See the respective function ++ man pages for details. ++ ++ In addition, for details about the algorithms, ++ check the liberally licensed reference implementation ++ sources: ++ ++ and ++ ++ These APIs are implemented in the reference ++ implementation's drop-in ++ sd-readahead.c and ++ sd-readahead.h files. It is ++ recommended that applications consuming these APIs copy ++ the implementation into their source tree, either ++ verbatim or in excerpts. These interfaces are ++ currently not available in a dynamic library. ++ ++ The functions provided by this interface become ++ NOPs when -DDISABLE_SYSTEMD is set during ++ compilation. In addition, if ++ sd-readhead.c is compiled on ++ non-Linux systems it becomes NOPs. ++ ++ ++ ++ See Also ++ ++ systemd1, ++ sd_readahead3, ++ sd-daemon3 ++ ++ ++ ++ +diff --git a/man/sd_readahead.xml b/man/sd_readahead.xml +new file mode 100644 +index 000000000..98272997c +--- /dev/null ++++ b/man/sd_readahead.xml +@@ -0,0 +1,178 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd_readahead ++ systemd ++ ++ ++ ++ Developer ++ Lennart ++ Poettering ++ lennart@poettering.net ++ ++ ++ ++ ++ ++ sd_readahead ++ 3 ++ ++ ++ ++ sd_readahead ++ Control ongoing disk boot-time read-ahead operations ++ ++ ++ ++ ++ #include "sd-readahead.h" ++ ++ ++ int sd_readahead ++ const char *action ++ ++ ++ ++ ++ ++ Description ++ sd_readahead() may be ++ called by programs involved with early boot-up to ++ control ongoing boot-time disk read-ahead operations. It may be ++ used to terminate read-ahead operations in case an ++ uncommon disk access pattern is to be expected and ++ hence read-ahead replay or collection is unlikely to ++ have the desired speed-up effect on the current or ++ future boot-ups. ++ ++ The action should be one ++ of the following strings: ++ ++ ++ ++ cancel ++ ++ Terminates read-ahead ++ data collection, and drops all ++ read-ahead data collected during this ++ boot-up. ++ ++ ++ ++ done ++ ++ Terminates read-ahead ++ data collection, but keeps all ++ read-ahead data collected during this ++ boot-up around for use during ++ subsequent boot-ups. ++ ++ ++ ++ noreplay ++ ++ Terminates read-ahead ++ replay. ++ ++ ++ ++ ++ ++ ++ ++ Return Value ++ ++ On failure, these calls return a negative ++ errno-style error code. It is generally recommended to ++ ignore the return value of this call. ++ ++ ++ ++ Notes ++ ++ This function is provided by the reference ++ implementation of APIs for controlling boot-time ++ read-ahead and distributed with the systemd ++ package. The algorithm it implements is simple, and ++ can easily be reimplemented in daemons if it is ++ important to support this interface without using the ++ reference implementation. ++ ++ Internally, this function creates a file in ++ /run/systemd/readahead/ which is ++ then used as flag file to notify the read-ahead ++ subsystem. ++ ++ For details about the algorithm check the ++ liberally licensed reference implementation sources: ++ ++ and ++ ++ sd_readahead() is ++ implemented in the reference implementation's drop-in ++ sd-readahead.c and ++ sd-readahead.h files. It is ++ recommended that applications consuming this API copy ++ the implementation into their source tree. For more ++ details about the reference implementation, see ++ sd-readahead3 ++ ++ If -DDISABLE_SYSTEMD is set during compilation, ++ this function will always return 0 and otherwise ++ become a NOP. ++ ++ ++ ++ Examples ++ ++ ++ Cancelling all read-ahead operations ++ ++ During boots where SELinux has to ++ relabel the file system hierarchy, it will ++ create a large amount of disk accesses that ++ are not necessary during normal boots. Hence ++ it is a good idea to disable both read-ahead replay and read-ahead collection. ++ ++ ++ sd_readahead("cancel"); ++sd_readahead("noreplay"); ++ ++ ++ ++ ++ ++ See Also ++ ++ systemd1, ++ sd-readahead3, ++ daemon7 ++ ++ ++ ++ +diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml +index 06d5ae531..46ede1ab8 100644 +--- a/man/systemd-notify.xml ++++ b/man/systemd-notify.xml +@@ -127,6 +127,17 @@ + sd_booted3. + + ++ ++ ++ ++ Controls disk ++ read-ahead operations. The argument ++ must be a string, and either "cancel", ++ "done" or "noreplay". For details ++ about the semantics of this option see ++ sd_readahead3. ++ ++ + + + +diff --git a/man/systemd-readahead-replay.service.xml b/man/systemd-readahead-replay.service.xml +new file mode 100644 +index 000000000..669fe7894 +--- /dev/null ++++ b/man/systemd-readahead-replay.service.xml +@@ -0,0 +1,203 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ systemd-readahead-replay.service ++ systemd ++ ++ ++ ++ Developer ++ Lennart ++ Poettering ++ lennart@poettering.net ++ ++ ++ ++ ++ ++ systemd-readahead-replay.service ++ 8 ++ ++ ++ ++ systemd-readahead-replay.service ++ systemd-readahead-collect.service ++ systemd-readahead-done.service ++ systemd-readahead-done.timer ++ systemd-readahead ++ Disk read ahead logic ++ ++ ++ ++ systemd-readahead-replay.service ++ systemd-readahead-collect.service ++ systemd-readahead-done.service ++ systemd-readahead-done.timer ++ ++ /usr/lib/systemd/systemd-readahead/systemd-readahead ++ OPTIONS ++ COMMAND ++ DIRECTORY | FILE ++ ++ ++ ++ ++ Description ++ ++ systemd-readahead-collect.service ++ is a service that collects disk usage patterns at boot ++ time. systemd-readahead-replay.service ++ is a service that replays this access data collected ++ at the subsequent boot. Since disks tend to be ++ magnitudes slower than RAM, this is intended to improve ++ boot speeds by pre-loading early at boot all data on ++ disk that is known to be read for the complete boot ++ process. ++ ++ systemd-readahead-done.service ++ is executed a short while after boot completed and signals ++ systemd-readahead-collect.service ++ to end data collection. On this signal, this service ++ will then sort the collected disk accesses and store ++ information about them in ++ /.readahead. ++ ++ Normally, both ++ systemd-readahead-collect.service ++ and ++ systemd-readahead-replay.service ++ are activated at boot so that access patterns from the ++ preceding boot are replayed and new data collected ++ for the subsequent boot. However, on read-only media ++ where the collected data cannot be stored, it might ++ be a good idea to disable ++ systemd-readahead-collect.service. ++ ++ On rotating media, when replaying disk accesses ++ at early boot, ++ systemd-readahead-replay.service ++ will order read requests by their location on disk. On ++ non-rotating media, they will be ordered by their ++ original access timestamp. If the file system supports ++ it, ++ systemd-readahead-collect.service ++ will also defragment and rearrange files on disk to ++ optimize subsequent boot times. ++ ++ ++ ++ Options ++ ++ systemd-readahead understands ++ the following options: ++ ++ ++ ++ ++ ++ Maximum number of ++ files to read ahead. Only valid ++ for thes collect ++ command. ++ ++ ++ ++ ++ ++ Maximum size of files ++ in bytes to read ahead. Only valid ++ for the collect ++ and replay ++ commands. ++ ++ ++ ++ ++ ++ Maximum time in microseconds ++ to spend collecting data. Only valid ++ for the collect ++ command. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Commands ++ ++ The following commands are understood by ++ systemd-readahead: ++ ++ collect ++ [DIRECTORY] ++ ++ Collect read-ahead data on ++ early boot. When terminating, it will ++ write out a pack file to the indicated ++ directory containing the read-ahead ++ data. ++ ++ ++ ++ ++ replay ++ [DIRECTORY] ++ ++ Perform read-ahead on the ++ specified directory tree. ++ ++ ++ ++ ++ analyze ++ [FILE] ++ ++ Dumps the content of the ++ read-ahead pack file to the ++ terminal. For each file, the ++ output lists approximately how ++ much will be read ahead by ++ the replay ++ command. ++ ++ ++ ++ ++ ++ ++ ++ See Also ++ ++ systemd1 ++ ++ ++ ++ +diff --git a/po/POTFILES.skip b/po/POTFILES.skip +index 51254ec53..b552029b8 100644 +--- a/po/POTFILES.skip ++++ b/po/POTFILES.skip +@@ -17,5 +17,6 @@ src/hostname/hostnamed.c + src/locale/localed.c + src/core/org.freedesktop.systemd1.policy.in + src/timedate/timedated.c ++units/systemd-readahead-done.service.in + units/user@.service.in + units/debug-shell.service.in +diff --git a/shell-completion/zsh/_systemd b/shell-completion/zsh/_systemd +index 58b1c7b4e..06f03bd1e 100644 +--- a/shell-completion/zsh/_systemd ++++ b/shell-completion/zsh/_systemd +@@ -63,7 +63,8 @@ case "$service" in + '--ready[Inform the init system about service start-up completion.]' \ + '--pid=[Inform the init system about the main PID of the daemon]' \ + '--status=[Send a free-form status string for the daemon to the init systemd]' \ +- '--booted[Returns 0 if the system was booted up with systemd]' ++ '--booted[Returns 0 if the system was booted up with systemd]' \ ++ '--readahead=[Controls disk read-ahead operations]:arguments:(cancel done noreply)' + ;; + systemd-tty-ask-password-agent) + _arguments \ +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index 05061c070..dfbca8754 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -111,7 +111,7 @@ static int create_disk( + "Conflicts=umount.target\n" + "BindsTo=dev-mapper-%i.device\n" + "IgnoreOnIsolate=true\n" +- "After=cryptsetup-pre.target\n", ++ "After=systemd-readahead-collect.service systemd-readahead-replay.service cryptsetup-pre.target\n", + f); + + if (!nofail) +diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c +index 5c58b58f8..7d5a6c650 100644 +--- a/src/gpt-auto-generator/gpt-auto-generator.c ++++ b/src/gpt-auto-generator/gpt-auto-generator.c +@@ -133,6 +133,7 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi + "Before=umount.target cryptsetup.target\n" + "After=%s\n" + "IgnoreOnIsolate=true\n" ++ "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n" + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" +diff --git a/src/notify/notify.c b/src/notify/notify.c +index f98075d51..e4a128b0b 100644 +--- a/src/notify/notify.c ++++ b/src/notify/notify.c +@@ -31,6 +31,7 @@ + #include "strv.h" + #include "util.h" + #include "log.h" ++#include "sd-readahead.h" + #include "build.h" + #include "env-util.h" + +@@ -38,6 +39,7 @@ static bool arg_ready = false; + static pid_t arg_pid = 0; + static const char *arg_status = NULL; + static bool arg_booted = false; ++static const char *arg_readahead = NULL; + + static void help(void) { + printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n" +@@ -48,6 +50,7 @@ static void help(void) { + " --pid[=PID] Set main pid of daemon\n" + " --status=TEXT Set status text\n" + " --booted Check if the system was booted up with systemd\n", ++ " --readahead=ACTION Controls read-ahead operations\n", + program_invocation_short_name); + } + +@@ -59,6 +62,7 @@ static int parse_argv(int argc, char *argv[]) { + ARG_PID, + ARG_STATUS, + ARG_BOOTED, ++ ARG_READAHEAD + }; + + static const struct option options[] = { +@@ -68,6 +72,7 @@ static int parse_argv(int argc, char *argv[]) { + { "pid", optional_argument, NULL, ARG_PID }, + { "status", required_argument, NULL, ARG_STATUS }, + { "booted", no_argument, NULL, ARG_BOOTED }, ++ { "readahead", required_argument, NULL, ARG_READAHEAD }, + {} + }; + +@@ -113,6 +118,10 @@ static int parse_argv(int argc, char *argv[]) { + arg_booted = true; + break; + ++ case ARG_READAHEAD: ++ arg_readahead = optarg; ++ break; ++ + case '?': + return -EINVAL; + +@@ -125,7 +134,8 @@ static int parse_argv(int argc, char *argv[]) { + !arg_ready && + !arg_status && + !arg_pid && +- !arg_booted) { ++ !arg_booted && ++ !arg_readahead) { + help(); + return -EINVAL; + } +@@ -150,6 +160,14 @@ int main(int argc, char* argv[]) { + if (arg_booted) + return sd_booted() <= 0; + ++ if (arg_readahead) { ++ r = sd_readahead(arg_readahead); ++ if (r < 0) { ++ log_error("Failed to issue read-ahead control command: %s", strerror(-r)); ++ goto finish; ++ } ++ } ++ + if (arg_ready) + our_env[i++] = (char*) "READY=1"; + +diff --git a/src/readahead/Makefile b/src/readahead/Makefile +new file mode 120000 +index 000000000..d0b0e8e00 +--- /dev/null ++++ b/src/readahead/Makefile +@@ -0,0 +1 @@ ++../Makefile +\ No newline at end of file +diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c +new file mode 100644 +index 000000000..76db3cb7e +--- /dev/null ++++ b/src/readahead/readahead-analyze.c +@@ -0,0 +1,146 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2012 Auke Kok ++ ++ 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 ++#include ++#include ++#include ++#include ++ ++#include "readahead-common.h" ++ ++int main_analyze(const char *pack_path) { ++ char line[LINE_MAX]; ++ _cleanup_fclose_ FILE *pack = NULL; ++ int a; ++ int missing = 0; ++ size_t tsize = 0; ++ ++ if (!pack_path) ++ pack_path = "/.readahead"; ++ ++ pack = fopen(pack_path, "re"); ++ if (!pack) { ++ log_error("Pack file missing."); ++ goto fail; ++ } ++ ++ if (!fgets(line, sizeof(line), pack)) { ++ log_error("Pack file corrupt."); ++ goto fail; ++ } ++ ++ char_array_0(line); ++ ++ if (!endswith(line, READAHEAD_PACK_FILE_VERSION)) { ++ log_error("Pack file version incompatible with this parser."); ++ goto fail; ++ } ++ ++ if ((a = getc(pack)) == EOF) { ++ log_error("Pack file corrupt."); ++ goto fail; ++ } ++ ++ fputs(" pct sections size: path\n" ++ " === ======== ====: ====\n", stdout); ++ ++ for (;;) { ++ char path[PATH_MAX]; ++ struct stat st; ++ uint64_t inode; ++ int pages = 0; ++ int sections = 0; ++ ++ if (!fgets(path, sizeof(path), pack)) ++ break; /* done */ ++ ++ path[strlen(path)-1] = 0; ++ ++ if (fread(&inode, sizeof(inode), 1, pack) != 1) { ++ log_error("Pack file corrupt."); ++ goto fail; ++ } ++ ++ for (;;) { ++ uint32_t b, c; ++ ++ if (fread(&b, sizeof(b), 1, pack) != 1 || ++ fread(&c, sizeof(c), 1, pack) != 1) { ++ log_error("Pack file corrupt."); ++ goto fail; ++ } ++ if ((b == 0) && (c == 0)) ++ break; ++ ++ /* Uncomment this to get all the chunks separately ++ printf(" %d: %d %d\n", sections, b, c); ++ */ ++ ++ pages += (c - b); ++ sections++; ++ } ++ ++ if (stat(path, &st) == 0) { ++ off_t size; ++ ++ if (sections == 0) ++ size = st.st_size; ++ else ++ size = pages * page_size(); ++ ++ tsize += size; ++ ++ printf(" %4jd%% (%2d) %12jd: %s\n", ++ (intmax_t) (sections && st.st_size ? size * 100 / st.st_size : 100), ++ sections ? sections : 1, ++ (intmax_t) size, ++ path); ++ } else { ++ printf(" %4dp (%2d) %12s: %s (MISSING)\n", ++ sections ? pages : -1, ++ sections ? sections : 1, ++ "???", ++ path); ++ missing++; ++ } ++ ++ } ++ ++ printf("\nHOST: %s" ++ "TYPE: %c\n" ++ "MISSING: %d\n" ++ "TOTAL: %zu\n", ++ line, ++ a, ++ missing, ++ tsize); ++ ++ return EXIT_SUCCESS; ++ ++fail: ++ return EXIT_FAILURE; ++} +diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c +new file mode 100644 +index 000000000..822a803a4 +--- /dev/null ++++ b/src/readahead/readahead-collect.c +@@ -0,0 +1,650 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2010 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_LINUX_BTRFS_H ++#include ++#endif ++ ++#ifdef HAVE_FANOTIFY_INIT ++#include ++#endif ++ ++#include "systemd/sd-daemon.h" ++ ++#include "missing.h" ++#include "util.h" ++#include "set.h" ++#include "ioprio.h" ++#include "readahead-common.h" ++#include "virt.h" ++ ++/* fixme: ++ * ++ * - detect ssd on btrfs/lvm... ++ * - read ahead directories ++ * - gzip? ++ * - remount rw? ++ * - handle files where nothing is in mincore ++ * - does ioprio_set work with fadvise()? ++ */ ++ ++static ReadaheadShared *shared = NULL; ++static usec_t starttime; ++ ++/* Avoid collisions with the NULL pointer */ ++#define SECTOR_TO_PTR(s) ULONG_TO_PTR((s)+1) ++#define PTR_TO_SECTOR(p) (PTR_TO_ULONG(p)-1) ++ ++static int btrfs_defrag(int fd) { ++ struct btrfs_ioctl_vol_args data = { .fd = fd }; ++ ++ return ioctl(fd, BTRFS_IOC_DEFRAG, &data); ++} ++ ++static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { ++ struct stat st; ++ void *start = MAP_FAILED; ++ uint8_t *vec; ++ uint32_t b, c; ++ uint64_t inode; ++ size_t l, pages; ++ bool mapped; ++ int r = 0, fd = -1, k; ++ ++ assert(pack); ++ assert(fn); ++ ++ fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW); ++ if (fd < 0) { ++ ++ if (errno == ENOENT) ++ return 0; ++ ++ if (errno == EPERM || errno == EACCES) ++ return 0; ++ ++ log_warning("open(%s) failed: %m", fn); ++ r = -errno; ++ goto finish; ++ } ++ ++ k = file_verify(fd, fn, arg_file_size_max, &st); ++ if (k <= 0) { ++ r = k; ++ goto finish; ++ } ++ ++ if (on_btrfs) ++ btrfs_defrag(fd); ++ ++ l = PAGE_ALIGN(st.st_size); ++ start = mmap(NULL, l, PROT_READ, MAP_SHARED, fd, 0); ++ if (start == MAP_FAILED) { ++ log_warning("mmap(%s) failed: %m", fn); ++ r = -errno; ++ goto finish; ++ } ++ ++ pages = l / page_size(); ++ vec = alloca0(pages); ++ if (mincore(start, l, vec) < 0) { ++ log_warning("mincore(%s) failed: %m", fn); ++ r = -errno; ++ goto finish; ++ } ++ ++ fputs(fn, pack); ++ fputc('\n', pack); ++ ++ /* Store the inode, so that we notice when the file is deleted */ ++ inode = (uint64_t) st.st_ino; ++ fwrite(&inode, sizeof(inode), 1, pack); ++ ++ mapped = false; ++ for (c = 0; c < pages; c++) { ++ bool new_mapped = !!(vec[c] & 1); ++ ++ if (!mapped && new_mapped) ++ b = c; ++ else if (mapped && !new_mapped) { ++ fwrite(&b, sizeof(b), 1, pack); ++ fwrite(&c, sizeof(c), 1, pack); ++ ++ log_debug("%s: page %u to %u", fn, b, c); ++ } ++ ++ mapped = new_mapped; ++ } ++ ++ /* We don't write any range data if we should read the entire file */ ++ if (mapped && b > 0) { ++ fwrite(&b, sizeof(b), 1, pack); ++ fwrite(&c, sizeof(c), 1, pack); ++ ++ log_debug("%s: page %u to %u", fn, b, c); ++ } ++ ++ /* End marker */ ++ b = 0; ++ fwrite(&b, sizeof(b), 1, pack); ++ fwrite(&b, sizeof(b), 1, pack); ++ ++finish: ++ if (start != MAP_FAILED) ++ munmap(start, l); ++ ++ safe_close(fd); ++ ++ return r; ++} ++ ++static unsigned long fd_first_block(int fd) { ++ struct { ++ struct fiemap fiemap; ++ struct fiemap_extent extent; ++ } data = { ++ .fiemap.fm_length = ~0ULL, ++ .fiemap.fm_extent_count = 1, ++ }; ++ ++ if (ioctl(fd, FS_IOC_FIEMAP, &data) < 0) ++ return 0; ++ ++ if (data.fiemap.fm_mapped_extents <= 0) ++ return 0; ++ ++ if (data.fiemap.fm_extents[0].fe_flags & FIEMAP_EXTENT_UNKNOWN) ++ return 0; ++ ++ return (unsigned long) data.fiemap.fm_extents[0].fe_physical; ++} ++ ++struct item { ++ const char *path; ++ unsigned long block; ++ unsigned long bin; ++}; ++ ++static int qsort_compare(const void *a, const void *b) { ++ const struct item *i, *j; ++ ++ i = a; ++ j = b; ++ ++ /* sort by bin first */ ++ if (i->bin < j->bin) ++ return -1; ++ if (i->bin > j->bin) ++ return 1; ++ ++ /* then sort by sector */ ++ if (i->block < j->block) ++ return -1; ++ if (i->block > j->block) ++ return 1; ++ ++ return strcmp(i->path, j->path); ++} ++ ++static int collect(const char *root) { ++ enum { ++ FD_FANOTIFY, /* Get the actual fs events */ ++ FD_SIGNAL, ++ FD_INOTIFY, /* We get notifications to quit early via this fd */ ++ _FD_MAX ++ }; ++ struct pollfd pollfd[_FD_MAX] = {}; ++ int fanotify_fd = -1, signal_fd = -1, inotify_fd = -1, r = 0; ++ pid_t my_pid; ++ Hashmap *files = NULL; ++ Iterator i; ++ char *p, *q; ++ sigset_t mask; ++ FILE *pack = NULL; ++ char *pack_fn_new = NULL, *pack_fn = NULL; ++ bool on_ssd, on_btrfs; ++ struct statfs sfs; ++ usec_t not_after; ++ uint64_t previous_block_readahead; ++ bool previous_block_readahead_set = false; ++ ++ assert(root); ++ ++ if (asprintf(&pack_fn, "%s/.readahead", root) < 0) { ++ r = log_oom(); ++ goto finish; ++ } ++ ++ starttime = now(CLOCK_MONOTONIC); ++ ++ /* If there's no pack file yet we lower the kernel readahead ++ * so that mincore() is accurate. If there is a pack file ++ * already we assume it is accurate enough so that kernel ++ * readahead is never triggered. */ ++ previous_block_readahead_set = ++ access(pack_fn, F_OK) < 0 && ++ block_get_readahead(root, &previous_block_readahead) >= 0 && ++ block_set_readahead(root, 8*1024) >= 0; ++ ++ if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0) ++ log_warning("Failed to set IDLE IO priority class: %m"); ++ ++ assert_se(sigemptyset(&mask) == 0); ++ sigset_add_many(&mask, SIGINT, SIGTERM, -1); ++ assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); ++ ++ if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { ++ log_error("signalfd(): %m"); ++ r = -errno; ++ goto finish; ++ } ++ ++ files = hashmap_new(&string_hash_ops); ++ if (!files) { ++ log_error("Failed to allocate set."); ++ r = -ENOMEM; ++ goto finish; ++ } ++ ++ fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME); ++ if (fanotify_fd < 0) { ++ log_error("Failed to create fanotify object: %m"); ++ r = -errno; ++ goto finish; ++ } ++ ++ if (fanotify_mark(fanotify_fd, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_OPEN, AT_FDCWD, root) < 0) { ++ log_error("Failed to mark %s: %m", root); ++ r = -errno; ++ goto finish; ++ } ++ ++ inotify_fd = open_inotify(); ++ if (inotify_fd < 0) { ++ r = inotify_fd; ++ goto finish; ++ } ++ ++ not_after = now(CLOCK_MONOTONIC) + arg_timeout; ++ ++ my_pid = getpid(); ++ ++ pollfd[FD_FANOTIFY].fd = fanotify_fd; ++ pollfd[FD_FANOTIFY].events = POLLIN; ++ pollfd[FD_SIGNAL].fd = signal_fd; ++ pollfd[FD_SIGNAL].events = POLLIN; ++ pollfd[FD_INOTIFY].fd = inotify_fd; ++ pollfd[FD_INOTIFY].events = POLLIN; ++ ++ sd_notify(0, ++ "READY=1\n" ++ "STATUS=Collecting readahead data"); ++ ++ log_debug("Collecting..."); ++ ++ if (access("/run/systemd/readahead/cancel", F_OK) >= 0) { ++ log_debug("Collection canceled"); ++ r = -ECANCELED; ++ goto finish; ++ } ++ ++ if (access("/run/systemd/readahead/done", F_OK) >= 0) { ++ log_debug("Got termination request"); ++ goto done; ++ } ++ ++ for (;;) { ++ union { ++ struct fanotify_event_metadata metadata; ++ char buffer[4096]; ++ } data; ++ ssize_t n; ++ struct fanotify_event_metadata *m; ++ usec_t t; ++ int h; ++ ++ if (hashmap_size(files) > arg_files_max) { ++ log_debug("Reached maximum number of read ahead files, ending collection."); ++ break; ++ } ++ ++ t = now(CLOCK_MONOTONIC); ++ if (t >= not_after) { ++ log_debug("Reached maximum collection time, ending collection."); ++ break; ++ } ++ ++ if ((h = poll(pollfd, _FD_MAX, (int) ((not_after - t) / USEC_PER_MSEC))) < 0) { ++ ++ if (errno == EINTR) ++ continue; ++ ++ log_error("poll(): %m"); ++ r = -errno; ++ goto finish; ++ } ++ ++ if (h == 0) { ++ log_debug("Reached maximum collection time, ending collection."); ++ break; ++ } ++ ++ if (pollfd[FD_SIGNAL].revents) { ++ log_debug("Got signal."); ++ break; ++ } ++ ++ if (pollfd[FD_INOTIFY].revents) { ++ uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; ++ struct inotify_event *e; ++ ++ if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ ++ log_error("Failed to read inotify event: %m"); ++ r = -errno; ++ goto finish; ++ } ++ ++ e = (struct inotify_event*) inotify_buffer; ++ while (n > 0) { ++ size_t step; ++ ++ if ((e->mask & IN_CREATE) && streq(e->name, "cancel")) { ++ log_debug("Collection canceled"); ++ r = -ECANCELED; ++ goto finish; ++ } ++ ++ if ((e->mask & IN_CREATE) && streq(e->name, "done")) { ++ log_debug("Got termination request"); ++ goto done; ++ } ++ ++ step = sizeof(struct inotify_event) + e->len; ++ assert(step <= (size_t) n); ++ ++ e = (struct inotify_event*) ((uint8_t*) e + step); ++ n -= step; ++ } ++ } ++ ++ n = read(fanotify_fd, &data, sizeof(data)); ++ if (n < 0) { ++ ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ ++ /* fanotify sometimes returns EACCES on read() ++ * where it shouldn't. For now let's just ++ * ignore it here (which is safe), but ++ * eventually this should be ++ * dropped when the kernel is fixed. ++ * ++ * https://bugzilla.redhat.com/show_bug.cgi?id=707577 */ ++ if (errno == EACCES) ++ continue; ++ ++ log_error("Failed to read event: %m"); ++ r = -errno; ++ goto finish; ++ } ++ ++ for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) { ++ char fn[sizeof("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; ++ int k; ++ ++ if (m->fd < 0) ++ goto next_iteration; ++ ++ if (m->pid == my_pid) ++ goto next_iteration; ++ ++ __sync_synchronize(); ++ if (m->pid == shared->replay) ++ goto next_iteration; ++ ++ snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd); ++ k = readlink_malloc(fn, &p); ++ if (k >= 0) { ++ if (startswith(p, "/tmp") || ++ endswith(p, " (deleted)") || ++ hashmap_get(files, p)) ++ /* Not interesting, or ++ * already read */ ++ free(p); ++ else { ++ unsigned long ul; ++ usec_t entrytime; ++ struct item *entry; ++ ++ entry = new0(struct item, 1); ++ if (!entry) { ++ r = log_oom(); ++ goto finish; ++ } ++ ++ ul = fd_first_block(m->fd); ++ ++ entrytime = now(CLOCK_MONOTONIC); ++ ++ entry->block = ul; ++ entry->path = strdup(p); ++ if (!entry->path) { ++ free(entry); ++ r = log_oom(); ++ goto finish; ++ } ++ entry->bin = (entrytime - starttime) / 2000000; ++ ++ k = hashmap_put(files, p, entry); ++ if (k < 0) { ++ log_warning("hashmap_put() failed: %s", strerror(-k)); ++ free(p); ++ } ++ } ++ ++ } else ++ log_warning("readlink(%s) failed: %s", fn, strerror(-k)); ++ ++ next_iteration: ++ safe_close(m->fd); ++ } ++ } ++ ++done: ++ fanotify_fd = safe_close(fanotify_fd); ++ ++ log_debug("Writing Pack File..."); ++ ++ on_ssd = fs_on_ssd(root) > 0; ++ log_debug("On SSD: %s", yes_no(on_ssd)); ++ ++ on_btrfs = statfs(root, &sfs) >= 0 && F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); ++ log_debug("On btrfs: %s", yes_no(on_btrfs)); ++ ++ if (asprintf(&pack_fn_new, "%s/.readahead.new", root) < 0) { ++ r = log_oom(); ++ goto finish; ++ } ++ ++ pack = fopen(pack_fn_new, "we"); ++ if (!pack) { ++ log_error("Failed to open pack file: %m"); ++ r = -errno; ++ goto finish; ++ } ++ ++ fputs(CANONICAL_HOST READAHEAD_PACK_FILE_VERSION, pack); ++ putc(on_ssd ? 'S' : 'R', pack); ++ ++ if (on_ssd || on_btrfs) { ++ ++ /* On SSD or on btrfs, just write things out in the ++ * order the files were accessed. */ ++ ++ HASHMAP_FOREACH_KEY(q, p, files, i) ++ pack_file(pack, p, on_btrfs); ++ } else { ++ unsigned n; ++ ++ /* On rotating media, order things by the block ++ * numbers */ ++ ++ log_debug("Ordering..."); ++ ++ n = hashmap_size(files); ++ if (n) { ++ _cleanup_free_ struct item *ordered; ++ struct item *j; ++ unsigned k; ++ ++ ordered = new(struct item, n); ++ if (!ordered) { ++ r = log_oom(); ++ goto finish; ++ } ++ ++ j = ordered; ++ HASHMAP_FOREACH_KEY(q, p, files, i) { ++ memcpy(j, q, sizeof(struct item)); ++ j++; ++ } ++ ++ assert(ordered + n == j); ++ ++ qsort(ordered, n, sizeof(struct item), qsort_compare); ++ ++ for (k = 0; k < n; k++) ++ pack_file(pack, ordered[k].path, on_btrfs); ++ } else ++ log_warning("No pack files"); ++ } ++ ++ log_debug("Finalizing..."); ++ ++ fflush(pack); ++ ++ if (ferror(pack)) { ++ log_error("Failed to write pack file."); ++ r = -EIO; ++ goto finish; ++ } ++ ++ if (rename(pack_fn_new, pack_fn) < 0) { ++ log_error("Failed to rename readahead file: %m"); ++ r = -errno; ++ goto finish; ++ } ++ ++ fclose(pack); ++ pack = NULL; ++ ++ log_debug("Done."); ++ ++finish: ++ safe_close(fanotify_fd); ++ safe_close(signal_fd); ++ safe_close(inotify_fd); ++ ++ if (pack) { ++ fclose(pack); ++ unlink(pack_fn_new); ++ } ++ free(pack_fn_new); ++ free(pack_fn); ++ ++ while ((p = hashmap_steal_first_key(files))) ++ free(p); ++ ++ hashmap_free(files); ++ ++ if (previous_block_readahead_set) { ++ uint64_t bytes; ++ ++ /* Restore the original kernel readahead setting if we ++ * changed it, and nobody has overwritten it since ++ * yet. */ ++ if (block_get_readahead(root, &bytes) >= 0 && bytes == 8*1024) ++ block_set_readahead(root, previous_block_readahead); ++ } ++ ++ return r; ++} ++ ++int main_collect(const char *root) { ++ ++ if (!root) ++ root = "/"; ++ ++ /* Skip this step on read-only media. Note that we check the ++ * underlying block device here, not he read-only flag of the ++ * file system on top, since that one is most likely mounted ++ * read-only anyway at boot, even if the underlying block ++ * device is theoretically writable. */ ++ if (fs_on_read_only(root) > 0) { ++ log_info("Disabling readahead collector due to read-only media."); ++ return EXIT_SUCCESS; ++ } ++ ++ if (!enough_ram()) { ++ log_info("Disabling readahead collector due to low memory."); ++ return EXIT_SUCCESS; ++ } ++ ++ shared = shared_get(); ++ if (!shared) ++ return EXIT_FAILURE; ++ ++ shared->collect = getpid(); ++ __sync_synchronize(); ++ ++ if (collect(root) < 0) ++ return EXIT_FAILURE; ++ ++ return EXIT_SUCCESS; ++} +diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c +new file mode 100644 +index 000000000..3ca48a725 +--- /dev/null ++++ b/src/readahead/readahead-common.c +@@ -0,0 +1,398 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2010 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 ++#include ++#include ++#include ++ ++#include "log.h" ++#include "readahead-common.h" ++#include "util.h" ++#include "missing.h" ++#include "fileio.h" ++#include "libudev.h" ++#include "udev-util.h" ++ ++int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) { ++ assert(fd >= 0); ++ assert(fn); ++ assert(st); ++ ++ if (fstat(fd, st) < 0) { ++ log_warning("fstat(%s) failed: %m", fn); ++ return -errno; ++ } ++ ++ if (!S_ISREG(st->st_mode)) { ++ log_debug("Not preloading special file %s", fn); ++ return 0; ++ } ++ ++ if (st->st_size <= 0 || st->st_size > file_size_max) { ++ assert_cc(sizeof(st->st_size) == 8); ++ log_debug("Not preloading file %s with size out of bounds %"PRIu64, ++ fn, st->st_size); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int fs_on_ssd(const char *p) { ++ struct stat st; ++ _cleanup_udev_unref_ struct udev *udev = NULL; ++ _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; ++ struct udev_device *look_at = NULL; ++ const char *devtype, *rotational, *model, *id; ++ int r; ++ ++ assert(p); ++ ++ if (stat(p, &st) < 0) ++ return -errno; ++ ++ if (major(st.st_dev) == 0) { ++ _cleanup_fclose_ FILE *f = NULL; ++ int mount_id; ++ union file_handle_union h = { .handle.handle_bytes = MAX_HANDLE_SZ, }; ++ ++ /* Might be btrfs, which exposes "ssd" as mount flag if it is on ssd. ++ * ++ * We first determine the mount ID here, if we can, ++ * and then lookup the mount ID in mountinfo to find ++ * the mount options. */ ++ ++ r = name_to_handle_at(AT_FDCWD, p, &h.handle, &mount_id, AT_SYMLINK_FOLLOW); ++ if (r < 0) ++ return false; ++ ++ f = fopen("/proc/self/mountinfo", "re"); ++ if (!f) ++ return false; ++ ++ for (;;) { ++ char line[LINE_MAX], *e; ++ _cleanup_free_ char *opts = NULL; ++ int mid; ++ ++ if (!fgets(line, sizeof(line), f)) ++ return false; ++ ++ truncate_nl(line); ++ ++ if (sscanf(line, "%i", &mid) != 1) ++ continue; ++ ++ if (mid != mount_id) ++ continue; ++ ++ e = strstr(line, " - "); ++ if (!e) ++ continue; ++ ++ if (sscanf(e+3, "%*s %*s %ms", &opts) != 1) ++ continue; ++ ++ if (streq(opts, "ssd") || startswith(opts, "ssd,") || endswith(opts, ",ssd") || strstr(opts, ",ssd,")) ++ return true; ++ } ++ ++ return false; ++ } ++ ++ udev = udev_new(); ++ if (!udev) ++ return -ENOMEM; ++ ++ udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); ++ if (!udev_device) ++ return false; ++ ++ devtype = udev_device_get_property_value(udev_device, "DEVTYPE"); ++ if (devtype && streq(devtype, "partition")) ++ look_at = udev_device_get_parent(udev_device); ++ else ++ look_at = udev_device; ++ ++ if (!look_at) ++ return false; ++ ++ /* First, try high-level property */ ++ id = udev_device_get_property_value(look_at, "ID_SSD"); ++ if (id) ++ return streq(id, "1"); ++ ++ /* Second, try kernel attribute */ ++ rotational = udev_device_get_sysattr_value(look_at, "queue/rotational"); ++ if (rotational) ++ return streq(rotational, "0"); ++ ++ /* Finally, fallback to heuristics */ ++ look_at = udev_device_get_parent(look_at); ++ if (!look_at) ++ return false; ++ ++ model = udev_device_get_sysattr_value(look_at, "model"); ++ if (model) ++ return !!strstr(model, "SSD"); ++ ++ return false; ++} ++ ++int fs_on_read_only(const char *p) { ++ struct stat st; ++ _cleanup_udev_unref_ struct udev *udev = NULL; ++ _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; ++ const char *read_only; ++ ++ assert(p); ++ ++ if (stat(p, &st) < 0) ++ return -errno; ++ ++ if (major(st.st_dev) == 0) ++ return false; ++ ++ udev = udev_new(); ++ if (!udev) ++ return -ENOMEM; ++ ++ udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); ++ if (!udev_device) ++ return false; ++ ++ read_only = udev_device_get_sysattr_value(udev_device, "ro"); ++ if (read_only) ++ return streq(read_only, "1"); ++ ++ return false; ++} ++ ++bool enough_ram(void) { ++ struct sysinfo si; ++ ++ assert_se(sysinfo(&si) >= 0); ++ ++ /* Enable readahead only with at least 128MB memory */ ++ return si.totalram > 127 * 1024*1024 / si.mem_unit; ++} ++ ++static void mkdirs(void) { ++ if (mkdir("/run/systemd", 0755) && errno != EEXIST) ++ log_warning("Failed to create /run/systemd: %m"); ++ if (mkdir("/run/systemd/readahead", 0755) && errno != EEXIST) ++ log_warning("Failed to create /run/systemd: %m"); ++} ++ ++int open_inotify(void) { ++ int fd; ++ ++ fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); ++ if (fd < 0) { ++ log_error("Failed to create inotify handle: %m"); ++ return -errno; ++ } ++ ++ mkdirs(); ++ ++ if (inotify_add_watch(fd, "/run/systemd/readahead", IN_CREATE) < 0) { ++ log_error("Failed to watch /run/systemd/readahead: %m"); ++ safe_close(fd); ++ return -errno; ++ } ++ ++ return fd; ++} ++ ++ReadaheadShared *shared_get(void) { ++ _cleanup_close_ int fd = -1; ++ ReadaheadShared *m = NULL; ++ ++ mkdirs(); ++ ++ fd = open("/run/systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644); ++ if (fd < 0) { ++ log_error("Failed to create shared memory segment: %m"); ++ return NULL; ++ } ++ ++ if (ftruncate(fd, sizeof(ReadaheadShared)) < 0) { ++ log_error("Failed to truncate shared memory segment: %m"); ++ return NULL; ++ } ++ ++ m = mmap(NULL, sizeof(ReadaheadShared), PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); ++ if (m == MAP_FAILED) { ++ log_error("Failed to mmap shared memory segment: %m"); ++ return NULL; ++ } ++ ++ return m; ++} ++ ++/* We use 20K instead of the more human digestable 16K here. Why? ++ Simply so that it is more unlikely that users end up picking this ++ value too so that we can recognize better whether the user changed ++ the value while we had it temporarily bumped. */ ++#define BUMP_REQUEST_NR (20*1024u) ++ ++int block_bump_request_nr(const char *p) { ++ struct stat st; ++ uint64_t u; ++ char *ap = NULL, *line = NULL; ++ int r; ++ dev_t d; ++ ++ assert(p); ++ ++ if (stat(p, &st) < 0) ++ return -errno; ++ ++ if (major(st.st_dev) == 0) ++ return 0; ++ ++ d = st.st_dev; ++ block_get_whole_disk(d, &d); ++ ++ if (asprintf(&ap, "/sys/dev/block/%u:%u/queue/nr_requests", major(d), minor(d)) < 0) { ++ r= -ENOMEM; ++ goto finish; ++ } ++ ++ r = read_one_line_file(ap, &line); ++ if (r < 0) { ++ if (r == -ENOENT) ++ r = 0; ++ goto finish; ++ } ++ ++ r = safe_atou64(line, &u); ++ if (r >= 0 && u >= BUMP_REQUEST_NR) { ++ r = 0; ++ goto finish; ++ } ++ ++ free(line); ++ line = NULL; ++ ++ if (asprintf(&line, "%u", BUMP_REQUEST_NR) < 0) { ++ r = -ENOMEM; ++ goto finish; ++ } ++ ++ r = write_string_file(ap, line); ++ if (r < 0) ++ goto finish; ++ ++ log_info("Bumped block_nr parameter of %u:%u to %u. This is a temporary hack and should be removed one day.", major(d), minor(d), BUMP_REQUEST_NR); ++ r = 1; ++ ++finish: ++ free(ap); ++ free(line); ++ ++ return r; ++} ++ ++int block_get_readahead(const char *p, uint64_t *bytes) { ++ struct stat st; ++ char *ap = NULL, *line = NULL; ++ int r; ++ dev_t d; ++ uint64_t u; ++ ++ assert(p); ++ assert(bytes); ++ ++ if (stat(p, &st) < 0) ++ return -errno; ++ ++ if (major(st.st_dev) == 0) ++ return 0; ++ ++ d = st.st_dev; ++ block_get_whole_disk(d, &d); ++ ++ if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) { ++ r = -ENOMEM; ++ goto finish; ++ } ++ ++ r = read_one_line_file(ap, &line); ++ if (r < 0) ++ goto finish; ++ ++ r = safe_atou64(line, &u); ++ if (r < 0) ++ goto finish; ++ ++ *bytes = u * 1024ULL; ++ ++finish: ++ free(ap); ++ free(line); ++ ++ return r; ++} ++ ++int block_set_readahead(const char *p, uint64_t bytes) { ++ struct stat st; ++ char *ap = NULL, *line = NULL; ++ int r; ++ dev_t d; ++ ++ assert(p); ++ assert(bytes); ++ ++ if (stat(p, &st) < 0) ++ return -errno; ++ ++ if (major(st.st_dev) == 0) ++ return 0; ++ ++ d = st.st_dev; ++ block_get_whole_disk(d, &d); ++ ++ if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) { ++ r = -ENOMEM; ++ goto finish; ++ } ++ ++ if (asprintf(&line, "%llu", bytes / 1024ULL) < 0) { ++ r = -ENOMEM; ++ goto finish; ++ } ++ ++ r = write_string_file(ap, line); ++ if (r < 0) ++ goto finish; ++ ++finish: ++ free(ap); ++ free(line); ++ ++ return r; ++} +diff --git a/src/readahead/readahead-common.h b/src/readahead/readahead-common.h +new file mode 100644 +index 000000000..b34f3aadd +--- /dev/null ++++ b/src/readahead/readahead-common.h +@@ -0,0 +1,61 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++#pragma once ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2010 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 "macro.h" ++#include "util.h" ++ ++#define READAHEAD_FILE_SIZE_MAX (10*1024*1024) ++ ++#define READAHEAD_PACK_FILE_VERSION ";VERSION=2\n" ++ ++extern unsigned arg_files_max; ++extern off_t arg_file_size_max; ++extern usec_t arg_timeout; ++ ++int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st); ++ ++int fs_on_ssd(const char *p); ++int fs_on_read_only(const char *p); ++ ++bool enough_ram(void); ++ ++int open_inotify(void); ++ ++typedef struct ReadaheadShared { ++ pid_t collect; ++ pid_t replay; ++} _packed_ ReadaheadShared; ++ ++ReadaheadShared *shared_get(void); ++ ++int block_bump_request_nr(const char *p); ++ ++int block_get_readahead(const char *p, uint64_t *bytes); ++int block_set_readahead(const char *p, uint64_t bytes); ++ ++int main_collect(const char *root); ++int main_replay(const char *root); ++int main_analyze(const char *pack_path); +diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c +new file mode 100644 +index 000000000..f81e0fe55 +--- /dev/null ++++ b/src/readahead/readahead-replay.c +@@ -0,0 +1,281 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2010 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "systemd/sd-daemon.h" ++ ++#include "missing.h" ++#include "util.h" ++#include "set.h" ++#include "ioprio.h" ++#include "readahead-common.h" ++#include "virt.h" ++ ++static ReadaheadShared *shared = NULL; ++ ++static int unpack_file(FILE *pack) { ++ _cleanup_close_ int fd = -1; ++ char fn[PATH_MAX]; ++ bool any = false; ++ struct stat st; ++ uint64_t inode; ++ ++ assert(pack); ++ ++ if (!fgets(fn, sizeof(fn), pack)) ++ return 0; ++ ++ char_array_0(fn); ++ truncate_nl(fn); ++ ++ fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW); ++ if (fd < 0) { ++ if (errno != ENOENT && errno != EPERM && errno != EACCES && errno != ELOOP) ++ log_warning("open(%s) failed: %m", fn); ++ ++ } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) ++ fd = safe_close(fd); ++ ++ if (fread(&inode, sizeof(inode), 1, pack) != 1) { ++ log_error("Premature end of pack file."); ++ return -EIO; ++ } ++ ++ if (fd >= 0) { ++ /* If the inode changed the file got deleted, so just ++ * ignore this entry */ ++ if (st.st_ino != (uint64_t) inode) ++ fd = safe_close(fd); ++ } ++ ++ for (;;) { ++ uint32_t b, c; ++ ++ if (fread(&b, sizeof(b), 1, pack) != 1 || ++ fread(&c, sizeof(c), 1, pack) != 1) { ++ log_error("Premature end of pack file."); ++ return -EIO; ++ } ++ ++ if (b == 0 && c == 0) ++ break; ++ ++ if (c <= b) { ++ log_error("Invalid pack file."); ++ return -EIO; ++ } ++ ++ log_debug("%s: page %u to %u", fn, b, c); ++ ++ any = true; ++ ++ if (fd >= 0) { ++ if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) { ++ log_warning("posix_fadvise() failed: %m"); ++ return -errno; ++ } ++ } ++ } ++ ++ if (!any && fd >= 0) { ++ /* if no range is encoded in the pack file this is ++ * intended to mean that the whole file shall be ++ * read */ ++ ++ if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) { ++ log_warning("posix_fadvise() failed: %m"); ++ return -errno; ++ } ++ } ++ ++ return 0; ++} ++ ++static int replay(const char *root) { ++ _cleanup_close_ int inotify_fd = -1; ++ _cleanup_free_ char *pack_fn = NULL; ++ _cleanup_fclose_ FILE *pack = NULL; ++ bool on_ssd, ready = false; ++ char line[LINE_MAX]; ++ int prio, c; ++ ++ assert(root); ++ ++ block_bump_request_nr(root); ++ ++ if (asprintf(&pack_fn, "%s/.readahead", root) < 0) ++ return log_oom(); ++ ++ pack = fopen(pack_fn, "re"); ++ if (!pack) { ++ if (errno == ENOENT) { ++ log_debug("No pack file found."); ++ return 0; ++ } ++ ++ log_error("Failed to open pack file: %m"); ++ return -errno; ++ } ++ ++ posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED); ++ ++ inotify_fd = open_inotify(); ++ if (inotify_fd < 0) ++ return inotify_fd; ++ ++ if (!fgets(line, sizeof(line), pack)) { ++ log_error("Premature end of pack file."); ++ return -EIO; ++ } ++ ++ char_array_0(line); ++ ++ if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) { ++ log_debug("Pack file host or version type mismatch."); ++ goto done; ++ } ++ ++ c = getc(pack); ++ if (c == EOF) { ++ log_debug("Premature end of pack file."); ++ return -EIO; ++ } ++ ++ /* We do not retest SSD here, so that we can start replaying ++ * before udev is up.*/ ++ on_ssd = c == 'S'; ++ log_debug("On SSD: %s", yes_no(on_ssd)); ++ ++ if (on_ssd) ++ prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0); ++ else ++ /* We are not using RT here, since we'd starve IO that ++ we didn't record (which is for example blkid, since ++ its disk accesses go directly to the block device and ++ are thus not visible in fallocate) to death. However, ++ we do ask for an IO prio that is slightly higher than ++ the default (which is BE. 4) */ ++ prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2); ++ ++ if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0) ++ log_warning("Failed to set IDLE IO priority class: %m"); ++ ++ sd_notify(0, "STATUS=Replaying readahead data"); ++ ++ log_debug("Replaying..."); ++ ++ if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) { ++ log_debug("Got termination request"); ++ goto done; ++ } ++ ++ while (!feof(pack) && !ferror(pack)) { ++ uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; ++ int k; ++ ssize_t n; ++ ++ n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer)); ++ if (n < 0) { ++ if (errno != EINTR && errno != EAGAIN) { ++ log_error("Failed to read inotify event: %m"); ++ return -errno; ++ } ++ } else { ++ struct inotify_event *e = (struct inotify_event*) inotify_buffer; ++ ++ while (n > 0) { ++ size_t step; ++ ++ if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) { ++ log_debug("Got termination request"); ++ goto done; ++ } ++ ++ step = sizeof(struct inotify_event) + e->len; ++ assert(step <= (size_t) n); ++ ++ e = (struct inotify_event*) ((uint8_t*) e + step); ++ n -= step; ++ } ++ } ++ ++ k = unpack_file(pack); ++ if (k < 0) ++ return k; ++ ++ if (!ready) { ++ /* We delay the ready notification until we ++ * queued at least one read */ ++ sd_notify(0, "READY=1"); ++ ready = true; ++ } ++ } ++ ++done: ++ if (ferror(pack)) { ++ log_error("Failed to read pack file."); ++ return -EIO; ++ } ++ ++ if (!ready) ++ sd_notify(0, "READY=1"); ++ ++ log_debug("Done."); ++ return 0; ++} ++ ++int main_replay(const char *root) { ++ ++ if (!root) ++ root = "/"; ++ ++ if (!enough_ram()) { ++ log_info("Disabling readahead replay due to low memory."); ++ return EXIT_SUCCESS; ++ } ++ ++ shared = shared_get(); ++ if (!shared) ++ return EXIT_FAILURE; ++ ++ shared->replay = getpid(); ++ __sync_synchronize(); ++ ++ if (replay(root) < 0) ++ return EXIT_FAILURE; ++ ++ return EXIT_SUCCESS; ++} +diff --git a/src/readahead/readahead.c b/src/readahead/readahead.c +new file mode 100644 +index 000000000..35176e937 +--- /dev/null ++++ b/src/readahead/readahead.c +@@ -0,0 +1,163 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2012 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 ++#include ++#include ++ ++#include "util.h" ++#include "def.h" ++#include "build.h" ++#include "readahead-common.h" ++ ++unsigned arg_files_max = 16*1024; ++off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX; ++usec_t arg_timeout = 2*USEC_PER_MINUTE; ++ ++static void help(void) { ++ printf("%1$s [OPTIONS...] collect [DIRECTORY]\n\n" ++ "Collect read-ahead data on early boot.\n\n" ++ " -h --help Show this help\n" ++ " --version Show package version\n" ++ " --files-max=INT Maximum number of files to read ahead\n" ++ " --file-size-max=BYTES Maximum size of files to read ahead\n" ++ " --timeout=USEC Maximum time to spend collecting data\n" ++ "\n\n" ++ "%1$s [OPTIONS...] replay [DIRECTORY]\n\n" ++ "Replay collected read-ahead data on early boot.\n\n" ++ " -h --help Show this help\n" ++ " --version Show package version\n" ++ " --file-size-max=BYTES Maximum size of files to read ahead\n" ++ "\n\n" ++ "%1$s [OPTIONS...] analyze [PACK-FILE]\n\n" ++ "Analyze collected read-ahead data.\n\n" ++ " -h --help Show this help\n" ++ " --version Show package version\n", ++ program_invocation_short_name); ++} ++ ++static int parse_argv(int argc, char *argv[]) { ++ ++ enum { ++ ARG_VERSION = 0x100, ++ ARG_FILES_MAX, ++ ARG_FILE_SIZE_MAX, ++ ARG_TIMEOUT ++ }; ++ ++ static const struct option options[] = { ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, ARG_VERSION }, ++ { "files-max", required_argument, NULL, ARG_FILES_MAX }, ++ { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX }, ++ { "timeout", required_argument, NULL, ARG_TIMEOUT }, ++ {} ++ }; ++ ++ int c; ++ ++ assert(argc >= 0); ++ assert(argv); ++ ++ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) ++ ++ switch (c) { ++ ++ case 'h': ++ help(); ++ return 0; ++ ++ case ARG_VERSION: ++ puts(PACKAGE_STRING); ++ puts(SYSTEMD_FEATURES); ++ return 0; ++ ++ case ARG_FILES_MAX: ++ if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) { ++ log_error("Failed to parse maximum number of files %s.", optarg); ++ return -EINVAL; ++ } ++ break; ++ ++ case ARG_FILE_SIZE_MAX: { ++ unsigned long long ull; ++ ++ if (safe_atollu(optarg, &ull) < 0 || ull <= 0) { ++ log_error("Failed to parse maximum file size %s.", optarg); ++ return -EINVAL; ++ } ++ ++ arg_file_size_max = (off_t) ull; ++ break; ++ } ++ ++ case ARG_TIMEOUT: ++ if (parse_sec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) { ++ log_error("Failed to parse timeout %s.", optarg); ++ return -EINVAL; ++ } ++ ++ break; ++ ++ case '?': ++ return -EINVAL; ++ ++ default: ++ assert_not_reached("Unhandled option"); ++ } ++ ++ if (optind != argc-1 && ++ optind != argc-2) { ++ log_error("%s: wrong number of arguments.", ++ program_invocation_short_name); ++ return -EINVAL; ++ } ++ ++ return 1; ++} ++ ++int main(int argc, char *argv[]) { ++ int r; ++ ++ log_set_target(LOG_TARGET_SAFE); ++ log_parse_environment(); ++ log_open(); ++ ++ umask(0022); ++ ++ r = parse_argv(argc, argv); ++ if (r <= 0) ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++ ++ if (streq(argv[optind], "collect")) ++ return main_collect(argv[optind+1]); ++ else if (streq(argv[optind], "replay")) ++ return main_replay(argv[optind+1]); ++ else if (streq(argv[optind], "analyze")) ++ return main_analyze(argv[optind+1]); ++ ++ log_error("Unknown verb %s.", argv[optind]); ++ return EXIT_FAILURE; ++} +diff --git a/src/readahead/sd-readahead.c b/src/readahead/sd-readahead.c +new file mode 100644 +index 000000000..675d82cdd +--- /dev/null ++++ b/src/readahead/sd-readahead.c +@@ -0,0 +1,89 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ Copyright 2010 Lennart Poettering ++ ++ Permission is hereby granted, free of charge, to any person ++ obtaining a copy of this software and associated documentation files ++ (the "Software"), to deal in the Software without restriction, ++ including without limitation the rights to use, copy, modify, merge, ++ publish, distribute, sublicense, and/or sell copies of the Software, ++ and to permit persons to whom the Software is furnished to do so, ++ subject to the following conditions: ++ ++ The above copyright notice and this permission notice shall be ++ included in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ SOFTWARE. ++***/ ++ ++#ifndef _GNU_SOURCE ++# define _GNU_SOURCE ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sd-readahead.h" ++ ++#if (__GNUC__ >= 4) ++# ifdef SD_EXPORT_SYMBOLS ++/* Export symbols */ ++# define _sd_export_ __attribute__ ((visibility("default"))) ++# else ++/* Don't export the symbols */ ++# define _sd_export_ __attribute__ ((visibility("hidden"))) ++# endif ++#else ++# define _sd_export_ ++#endif ++ ++static int touch(const char *path) { ++ ++#if !defined(DISABLE_SYSTEMD) && defined(__linux__) ++ int fd; ++ ++ mkdir("/run/systemd", 0755); ++ mkdir("/run/systemd/readahead", 0755); ++ ++ fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666); ++ if (fd < 0) ++ return -errno; ++ ++ for (;;) { ++ if (close(fd) >= 0) ++ break; ++ ++ if (errno != EINTR) ++ return -errno; ++ } ++ ++#endif ++ return 0; ++} ++ ++_sd_export_ int sd_readahead(const char *action) { ++ ++ if (!action) ++ return -EINVAL; ++ ++ if (strcmp(action, "cancel") == 0) ++ return touch("/run/systemd/readahead/cancel"); ++ else if (strcmp(action, "done") == 0) ++ return touch("/run/systemd/readahead/done"); ++ else if (strcmp(action, "noreplay") == 0) ++ return touch("/run/systemd/readahead/noreplay"); ++ ++ return -EINVAL; ++} +diff --git a/src/readahead/test-ssd.c b/src/readahead/test-ssd.c +new file mode 100644 +index 000000000..808faf359 +--- /dev/null ++++ b/src/readahead/test-ssd.c +@@ -0,0 +1,41 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2014 Zbigniew Jędrzejewski-Szmek ++ ++ 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 "readahead-common.h" ++ ++int main(int argc, char *argv[]) { ++ int i; ++ ++ for (i = 1; i < argc; i++) { ++ char *name = argv[i]; ++ int r; ++ ++ r = fs_on_ssd(name); ++ if (r < 0) { ++ log_error("%s: %s", name, strerror(-r)); ++ return EXIT_FAILURE; ++ } ++ ++ log_info("%s: %s", name, r ? "SSD" : "---"); ++ } ++ ++ return EXIT_SUCCESS; ++} +diff --git a/src/systemd/sd-readahead.h b/src/systemd/sd-readahead.h +new file mode 100644 +index 000000000..bb30f9a45 +--- /dev/null ++++ b/src/systemd/sd-readahead.h +@@ -0,0 +1,73 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++#ifndef foosdreadaheadhfoo ++#define foosdreadaheadhfoo ++ ++/*** ++ Copyright 2010 Lennart Poettering ++ ++ Permission is hereby granted, free of charge, to any person ++ obtaining a copy of this software and associated documentation files ++ (the "Software"), to deal in the Software without restriction, ++ including without limitation the rights to use, copy, modify, merge, ++ publish, distribute, sublicense, and/or sell copies of the Software, ++ and to permit persons to whom the Software is furnished to do so, ++ subject to the following conditions: ++ ++ The above copyright notice and this permission notice shall be ++ included in all copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ SOFTWARE. ++***/ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ Reference implementation of a few boot read-ahead-related ++ interfaces. These interfaces are trivial to implement. To simplify ++ porting, we provide this reference implementation. Applications are ++ welcome to reimplement the algorithms described here if they do not ++ want to include these two source files. ++ ++ You may compile this with -DDISABLE_SYSTEMD to disable systemd ++ support. This makes all calls NOPs. ++ ++ Because this is drop-in code, we don't want any of our symbols to be ++ exported in any case. Hence, we declare hidden visibility for all of ++ them. ++ ++ You may find an up-to-date version of these source files online: ++ ++ http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-readahead.h ++ http://cgit.freedesktop.org/systemd/systemd/plain/src/readahead/sd-readahead.c ++ ++ This should compile on non-Linux systems too, but all functions ++ will become NOPs. ++ ++ See sd-readahead(3) for more information. ++*/ ++ ++/* ++ Controls on-going disk read-ahead operations during boot-up. The argument ++ must be one of the following strings: "cancel", "done", or "noreplay". ++ ++ cancel = terminate read-ahead data collection, and drop collected information ++ done = terminate read-ahead data collection, and keep collected information ++ noreplay = terminate read-ahead replay ++*/ ++int sd_readahead(const char *action); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/system-preset/90-systemd.preset b/system-preset/90-systemd.preset +index ee1b864bc..24963f062 100644 +--- a/system-preset/90-systemd.preset ++++ b/system-preset/90-systemd.preset +@@ -12,6 +12,7 @@ enable remote-fs.target + enable machines.target + + enable getty@.service ++enable systemd-readahead-* + enable systemd-timesyncd.service + enable systemd-networkd.service + enable systemd-resolved.service +diff --git a/units/.gitignore b/units/.gitignore +index 6fdb629c3..638a7abc4 100644 +--- a/units/.gitignore ++++ b/units/.gitignore +@@ -52,6 +52,9 @@ + /systemd-poweroff.service + /systemd-quotacheck.service + /systemd-random-seed.service ++/systemd-readahead-collect.service ++/systemd-readahead-done.service ++/systemd-readahead-replay.service + /systemd-reboot.service + /systemd-remount-fs.service + /systemd-resolved.service +diff --git a/units/ldconfig.service b/units/ldconfig.service +index f9691e2f2..43c145b72 100644 +--- a/units/ldconfig.service ++++ b/units/ldconfig.service +@@ -10,7 +10,7 @@ Description=Rebuild Dynamic Linker Cache + Documentation=man:ldconfig(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=sysinit.target shutdown.target systemd-update-done.service + ConditionNeedsUpdate=/etc + +diff --git a/units/quotaon.service.in b/units/quotaon.service.in +index 7d59a4019..49a50a7fe 100644 +--- a/units/quotaon.service.in ++++ b/units/quotaon.service.in +@@ -9,7 +9,7 @@ + Description=Enable File System Quotas + Documentation=man:quotaon(8) + DefaultDependencies=no +-After=systemd-quotacheck.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-quotacheck.service + Before=local-fs.target shutdown.target + ConditionPathExists=@QUOTAON@ + +diff --git a/units/system-update.target b/units/system-update.target +index 48d46fcbd..d0f847f95 100644 +--- a/units/system-update.target ++++ b/units/system-update.target +@@ -10,7 +10,7 @@ Description=System Update + Documentation=http://freedesktop.org/wiki/Software/systemd/SystemUpdates + Documentation=man:systemd.special(7) man:systemd-system-update-generator(8) + Requires=sysinit.target +-Conflicts=shutdown.target ++Conflicts=shutdown.target systemd-readahead-collect.service systemd-readahead-replay.service + After=sysinit.target + Before=shutdown.target + AllowIsolate=yes +diff --git a/units/systemd-backlight@.service.in b/units/systemd-backlight@.service.in +index 5e6706c11..b146e30f2 100644 +--- a/units/systemd-backlight@.service.in ++++ b/units/systemd-backlight@.service.in +@@ -11,7 +11,7 @@ Documentation=man:systemd-backlight@.service(8) + DefaultDependencies=no + RequiresMountsFor=/var/lib/systemd/backlight + Conflicts=shutdown.target +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=sysinit.target shutdown.target + + [Service] +diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in +index 34a5d5237..02dfe774d 100644 +--- a/units/systemd-binfmt.service.in ++++ b/units/systemd-binfmt.service.in +@@ -11,7 +11,7 @@ Documentation=man:systemd-binfmt.service(8) man:binfmt.d(5) + Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt + DefaultDependencies=no + Conflicts=shutdown.target +-After=proc-sys-fs-binfmt_misc.automount ++After=systemd-readahead-collect.service systemd-readahead-replay.service proc-sys-fs-binfmt_misc.automount + Before=sysinit.target shutdown.target + ConditionPathIsReadWrite=/proc/sys/ + ConditionDirectoryNotEmpty=|/lib/binfmt.d +diff --git a/units/systemd-firstboot.service.in b/units/systemd-firstboot.service.in +index 405c6f3fd..89fa7e1dd 100644 +--- a/units/systemd-firstboot.service.in ++++ b/units/systemd-firstboot.service.in +@@ -10,7 +10,7 @@ Description=First Boot Wizard + Documentation=man:systemd-firstboot(1) + DefaultDependencies=no + Conflicts=shutdown.target +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=systemd-sysusers.service sysinit.target shutdown.target + ConditionPathIsReadWrite=/etc + ConditionFirstBoot=yes +diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in +index 6d7657853..26cce5131 100644 +--- a/units/systemd-fsck-root.service.in ++++ b/units/systemd-fsck-root.service.in +@@ -9,6 +9,7 @@ + Description=File System Check on Root Device + Documentation=man:systemd-fsck-root.service(8) + DefaultDependencies=no ++After=systemd-readahead-collect.service systemd-readahead-replay.service + Before=local-fs.target shutdown.target + ConditionPathIsReadWrite=!/ + +diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in +index 857e62567..d2cda6a46 100644 +--- a/units/systemd-fsck@.service.in ++++ b/units/systemd-fsck@.service.in +@@ -10,7 +10,7 @@ Description=File System Check on %f + Documentation=man:systemd-fsck@.service(8) + DefaultDependencies=no + BindsTo=%i.device +-After=%i.device systemd-fsck-root.service local-fs-pre.target ++After=systemd-readahead-collect.service systemd-readahead-replay.service %i.device systemd-fsck-root.service local-fs-pre.target + Before=shutdown.target + + [Service] +diff --git a/units/systemd-hwdb-update.service.in b/units/systemd-hwdb-update.service.in +index 791528e2b..4bed482f8 100644 +--- a/units/systemd-hwdb-update.service.in ++++ b/units/systemd-hwdb-update.service.in +@@ -10,7 +10,7 @@ Description=Rebuild Hardware Database + Documentation=man:hwdb(7) man:systemd-hwdb(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=sysinit.target shutdown.target systemd-update-done.service + ConditionNeedsUpdate=/etc + ConditionPathExists=|!@udevlibexecdir@/hwdb.bin +diff --git a/units/systemd-journal-catalog-update.service.in b/units/systemd-journal-catalog-update.service.in +index 6370dd478..5b85889dd 100644 +--- a/units/systemd-journal-catalog-update.service.in ++++ b/units/systemd-journal-catalog-update.service.in +@@ -10,7 +10,7 @@ Description=Rebuild Journal Catalog + Documentation=man:systemd-journald.service(8) man:journald.conf(5) + DefaultDependencies=no + Conflicts=shutdown.target +-After=local-fs.target ++After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target + Before=sysinit.target shutdown.target systemd-update-done.service + ConditionNeedsUpdate=/etc + +diff --git a/units/systemd-modules-load.service.in b/units/systemd-modules-load.service.in +index 040a0febe..32deb52e2 100644 +--- a/units/systemd-modules-load.service.in ++++ b/units/systemd-modules-load.service.in +@@ -10,6 +10,7 @@ Description=Load Kernel Modules + Documentation=man:systemd-modules-load.service(8) man:modules-load.d(5) + DefaultDependencies=no + Conflicts=shutdown.target ++After=systemd-readahead-collect.service systemd-readahead-replay.service + Before=sysinit.target shutdown.target + ConditionCapability=CAP_SYS_MODULE + ConditionDirectoryNotEmpty=|/lib/modules-load.d +diff --git a/units/systemd-quotacheck.service.in b/units/systemd-quotacheck.service.in +index 5cb9bc3bc..f726ea1bc 100644 +--- a/units/systemd-quotacheck.service.in ++++ b/units/systemd-quotacheck.service.in +@@ -9,7 +9,7 @@ + Description=File System Quota Check + Documentation=man:systemd-quotacheck.service(8) + DefaultDependencies=no +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=local-fs.target shutdown.target + ConditionPathExists=@QUOTACHECK@ + +diff --git a/units/systemd-random-seed.service.in b/units/systemd-random-seed.service.in +index b55844b36..1879b2f24 100644 +--- a/units/systemd-random-seed.service.in ++++ b/units/systemd-random-seed.service.in +@@ -11,7 +11,7 @@ Documentation=man:systemd-random-seed.service(8) man:random(4) + DefaultDependencies=no + RequiresMountsFor=@RANDOM_SEED@ + Conflicts=shutdown.target +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=sysinit.target shutdown.target + + [Service] +diff --git a/units/systemd-readahead-collect.service.in b/units/systemd-readahead-collect.service.in +new file mode 100644 +index 000000000..d4b8e6793 +--- /dev/null ++++ b/units/systemd-readahead-collect.service.in +@@ -0,0 +1,28 @@ ++# 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=Collect Read-Ahead Data ++Documentation=man:systemd-readahead-replay.service(8) ++DefaultDependencies=no ++Wants=systemd-readahead-done.timer ++Conflicts=shutdown.target ++Before=sysinit.target shutdown.target ++ConditionPathExists=!/run/systemd/readahead/cancel ++ConditionPathExists=!/run/systemd/readahead/done ++ConditionVirtualization=no ++ ++[Service] ++Type=notify ++ExecStart=@rootlibexecdir@/systemd-readahead collect ++RemainAfterExit=yes ++StandardOutput=null ++OOMScoreAdjust=1000 ++ ++[Install] ++WantedBy=default.target ++Also=systemd-readahead-drop.service +diff --git a/units/systemd-readahead-done.service.in b/units/systemd-readahead-done.service.in +new file mode 100644 +index 000000000..e0d957944 +--- /dev/null ++++ b/units/systemd-readahead-done.service.in +@@ -0,0 +1,22 @@ ++# 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=Stop Read-Ahead Data Collection ++Documentation=man:systemd-readahead-replay.service(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=default.target ++Before=shutdown.target ++ConditionVirtualization=no ++ ++[Service] ++Type=oneshot ++ExecStart=@SYSTEMD_NOTIFY@ --readahead=done ++ ++[Install] ++Also=systemd-readahead-collect.service +diff --git a/units/systemd-readahead-done.timer b/units/systemd-readahead-done.timer +new file mode 100644 +index 000000000..c58e09616 +--- /dev/null ++++ b/units/systemd-readahead-done.timer +@@ -0,0 +1,22 @@ ++# 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=Stop Read-Ahead Data Collection 10s After Completed Startup ++Documentation=man:systemd-readahead-replay.service(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=default.target ++Before=shutdown.target ++ConditionVirtualization=no ++ ++[Timer] ++OnActiveSec=30s ++AccuracySec=1s ++ ++[Install] ++Also=systemd-readahead-collect.service +diff --git a/units/systemd-readahead-drop.service b/units/systemd-readahead-drop.service +new file mode 100644 +index 000000000..d9d12bc53 +--- /dev/null ++++ b/units/systemd-readahead-drop.service +@@ -0,0 +1,19 @@ ++# 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=Drop Read-Ahead Data ++Documentation=man:systemd-readahead-replay.service(8) ++ConditionPathExists=/.readahead ++ ++[Service] ++Type=oneshot ++ExecStart=/bin/rm -f /.readahead ++ ++[Install] ++WantedBy=system-update.target ++Also=systemd-readahead-collect.service +diff --git a/units/systemd-readahead-replay.service.in b/units/systemd-readahead-replay.service.in +new file mode 100644 +index 000000000..c64a533e4 +--- /dev/null ++++ b/units/systemd-readahead-replay.service.in +@@ -0,0 +1,26 @@ ++# 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=Replay Read-Ahead Data ++Documentation=man:systemd-readahead-replay.service(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++Before=sysinit.target shutdown.target ++ConditionPathExists=!/run/systemd/readahead/noreplay ++ConditionPathExists=/.readahead ++ConditionVirtualization=no ++ ++[Service] ++Type=notify ++ExecStart=@rootlibexecdir@/systemd-readahead replay ++RemainAfterExit=yes ++StandardOutput=null ++OOMScoreAdjust=1000 ++ ++[Install] ++WantedBy=default.target +diff --git a/units/systemd-remount-fs.service.in b/units/systemd-remount-fs.service.in +index 8d9daacaa..70e1a8680 100644 +--- a/units/systemd-remount-fs.service.in ++++ b/units/systemd-remount-fs.service.in +@@ -11,7 +11,7 @@ Documentation=man:systemd-remount-fs.service(8) + Documentation=http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems + DefaultDependencies=no + Conflicts=shutdown.target +-After=systemd-fsck-root.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-fsck-root.service + Before=local-fs-pre.target local-fs.target shutdown.target + Wants=local-fs-pre.target + ConditionPathExists=/etc/fstab +diff --git a/units/systemd-rfkill@.service.in b/units/systemd-rfkill@.service.in +index b48efe5d9..0d2757d61 100644 +--- a/units/systemd-rfkill@.service.in ++++ b/units/systemd-rfkill@.service.in +@@ -12,7 +12,7 @@ DefaultDependencies=no + BindsTo=sys-subsystem-rfkill-devices-%i.device + RequiresMountsFor=/var/lib/systemd/rfkill + Conflicts=shutdown.target +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=sysinit.target shutdown.target + + [Service] +diff --git a/units/systemd-sysctl.service.in b/units/systemd-sysctl.service.in +index fa72085f9..ade9dc300 100644 +--- a/units/systemd-sysctl.service.in ++++ b/units/systemd-sysctl.service.in +@@ -10,6 +10,7 @@ Description=Apply Kernel Variables + Documentation=man:systemd-sysctl.service(8) man:sysctl.d(5) + DefaultDependencies=no + Conflicts=shutdown.target ++After=systemd-readahead-collect.service systemd-readahead-replay.service + After=systemd-modules-load.service + Before=sysinit.target shutdown.target + ConditionPathIsReadWrite=/proc/sys/ +diff --git a/units/systemd-sysusers.service.in b/units/systemd-sysusers.service.in +index ffd6d7747..69fea11fb 100644 +--- a/units/systemd-sysusers.service.in ++++ b/units/systemd-sysusers.service.in +@@ -10,7 +10,7 @@ Description=Create System Users + Documentation=man:sysusers.d(5) man:systemd-sysusers.service(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=systemd-remount-fs.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service + Before=sysinit.target shutdown.target systemd-update-done.service + ConditionNeedsUpdate=/etc + +diff --git a/units/systemd-tmpfiles-clean.service.in b/units/systemd-tmpfiles-clean.service.in +index 133c8c94c..31b237841 100644 +--- a/units/systemd-tmpfiles-clean.service.in ++++ b/units/systemd-tmpfiles-clean.service.in +@@ -10,7 +10,7 @@ Description=Cleanup of Temporary Directories + Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=local-fs.target time-sync.target ++After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target time-sync.target + Before=shutdown.target + + [Service] +diff --git a/units/systemd-tmpfiles-setup-dev.service.in b/units/systemd-tmpfiles-setup-dev.service.in +index 0123a030e..0b66c53fe 100644 +--- a/units/systemd-tmpfiles-setup-dev.service.in ++++ b/units/systemd-tmpfiles-setup-dev.service.in +@@ -10,7 +10,7 @@ Description=Create Static Device Nodes in /dev + Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=systemd-sysusers.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-sysusers.service + Before=sysinit.target local-fs-pre.target systemd-udevd.service shutdown.target + ConditionCapability=CAP_SYS_MODULE + +diff --git a/units/systemd-tmpfiles-setup.service.in b/units/systemd-tmpfiles-setup.service.in +index e895cda0e..72ab083d5 100644 +--- a/units/systemd-tmpfiles-setup.service.in ++++ b/units/systemd-tmpfiles-setup.service.in +@@ -10,7 +10,7 @@ Description=Create Volatile Files and Directories + Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=local-fs.target systemd-sysusers.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target systemd-sysusers.service + Before=sysinit.target shutdown.target + RefuseManualStop=yes + +diff --git a/units/systemd-update-done.service.in b/units/systemd-update-done.service.in +index ec7d90639..7031bff61 100644 +--- a/units/systemd-update-done.service.in ++++ b/units/systemd-update-done.service.in +@@ -10,7 +10,7 @@ Description=Update is Completed + Documentation=man:systemd-update-done.service(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=local-fs.target ++After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target + Before=sysinit.target shutdown.target + ConditionNeedsUpdate=|/etc + ConditionNeedsUpdate=|/var +diff --git a/units/systemd-update-utmp.service.in b/units/systemd-update-utmp.service.in +index 163eccd91..da7dda76b 100644 +--- a/units/systemd-update-utmp.service.in ++++ b/units/systemd-update-utmp.service.in +@@ -11,7 +11,7 @@ Documentation=man:systemd-update-utmp.service(8) man:utmp(5) + DefaultDependencies=no + RequiresMountsFor=/var/log/wtmp + Conflicts=shutdown.target +-After=systemd-remount-fs.service systemd-tmpfiles-setup.service auditd.service ++After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service systemd-tmpfiles-setup.service auditd.service + Before=sysinit.target shutdown.target + + [Service] +diff --git a/units/systemd-vconsole-setup.service.in b/units/systemd-vconsole-setup.service.in +index 616036187..18faa63f2 100644 +--- a/units/systemd-vconsole-setup.service.in ++++ b/units/systemd-vconsole-setup.service.in +@@ -10,6 +10,7 @@ Description=Setup Virtual Console + Documentation=man:systemd-vconsole-setup.service(8) man:vconsole.conf(5) + DefaultDependencies=no + Conflicts=shutdown.target ++After=systemd-readahead-collect.service systemd-readahead-replay.service + Before=sysinit.target shutdown.target + ConditionPathExists=/dev/tty0 + diff --git a/SOURCES/0011-rules-add-rule-for-naming-Dell-iDRAC-USB-Virtual-NIC.patch b/SOURCES/0011-rules-add-rule-for-naming-Dell-iDRAC-USB-Virtual-NIC.patch new file mode 100644 index 00000000..224549ea --- /dev/null +++ b/SOURCES/0011-rules-add-rule-for-naming-Dell-iDRAC-USB-Virtual-NIC.patch @@ -0,0 +1,41 @@ +From 2411be37e26457c5e6734dbf08feb4b8375c13a2 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 22 Sep 2014 07:53:52 +0200 +Subject: [PATCH] rules: add rule for naming Dell iDRAC USB Virtual NIC as + 'idrac' + +RHEL-only patch + +Resolves: #1054477 +--- + Makefile.am | 3 ++- + rules/73-idrac.rules | 6 ++++++ + 2 files changed, 8 insertions(+), 1 deletion(-) + create mode 100644 rules/73-idrac.rules + +diff --git a/Makefile.am b/Makefile.am +index b0e4b5a42..9e64d6f98 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3567,7 +3567,8 @@ dist_udevrules_DATA += \ + rules/78-sound-card.rules \ + rules/80-net-setup-link.rules \ + rules/95-udev-late.rules \ +- rules/40-redhat.rules ++ rules/40-redhat.rules \ ++ rules/73-idrac.rules + + nodist_udevrules_DATA += \ + rules/99-systemd.rules +diff --git a/rules/73-idrac.rules b/rules/73-idrac.rules +new file mode 100644 +index 000000000..d67fc425b +--- /dev/null ++++ b/rules/73-idrac.rules +@@ -0,0 +1,6 @@ ++# do not edit this file, it will be overwritten on update ++ ++# On Dell PowerEdge systems, the iDRAC7 and later support a USB Virtual NIC ++# with terminates in the iDRAC. Help identify this with 'idrac' ++ ++ACTION=="add", SUBSYSTEM=="net", SUBSYSTEMS=="usb", ATTRS{idVendor}=="413c", ATTRS{idProduct}=="a102", NAME="idrac" diff --git a/SOURCES/0012-udev-net_id-correctly-name-netdevs-based-on-dev_port.patch b/SOURCES/0012-udev-net_id-correctly-name-netdevs-based-on-dev_port.patch new file mode 100644 index 00000000..8f2ca1ff --- /dev/null +++ b/SOURCES/0012-udev-net_id-correctly-name-netdevs-based-on-dev_port.patch @@ -0,0 +1,91 @@ +From 74b66951fcd54e6ab51023f60cc021fe355be1a8 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 25 Oct 2014 17:10:11 +0200 +Subject: [PATCH] udev: net_id - correctly name netdevs based on dev_port when + set + +Upstream, dev_id was replaced by dev_port, and the same happened for some kernel +drivers. This logic is not in the RHEL7 kernel, except for one new driver which +uses dev_port, but never used dev_id in the past. + +To give proper names to these devices, fall back to using dev_port when dev_id +is not set. This does not affect any existing drivers. + +(rhel only) + +Resolves: #1155996 + +Conflicts: + src/udev/udev-builtin-net_id.c + +Conflicts: + src/udev/udev-builtin-net_id.c +--- + src/udev/udev-builtin-net_id.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 37ff1b800..99caa0a2a 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -38,7 +38,7 @@ + * o -- on-board device index number + * s[f][d] -- hotplug slot index number + * x -- MAC address +- * [P]ps[f][d] ++ * [P]ps[f][d/] + * -- PCI geographical location + * [P]ps[f][u][..][c][i] + * -- USB port number chain +@@ -169,7 +169,7 @@ static bool is_pci_multifunction(struct udev_device *dev) { + + static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + struct udev *udev = udev_device_get_udev(names->pcidev); +- unsigned domain, bus, slot, func, dev_port = 0; ++ unsigned domain, bus, slot, func, dev_id = 0; + size_t l; + char *s; + const char *attr; +@@ -183,9 +183,15 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + return -ENOENT; + + /* kernel provided multi-device index */ +- attr = udev_device_get_sysattr_value(dev, "dev_port"); +- if (attr) +- dev_port = strtol(attr, NULL, 10); ++ attr = udev_device_get_sysattr_value(dev, "dev_id"); ++ if (attr) { ++ dev_id = strtol(attr, NULL, 16); ++ if (dev_id == 0) { ++ attr = udev_device_get_sysattr_value(dev, "dev_port"); ++ if (attr) ++ dev_id = strtol(attr, NULL, 16); ++ } ++ } + + /* compose a name based on the raw kernel's PCI bus, slot numbers */ + s = names->pci_path; +@@ -194,9 +200,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + l = strpcpyf(&s, l, "P%u", domain); + l = strpcpyf(&s, l, "p%us%u", bus, slot); + if (func > 0 || is_pci_multifunction(names->pcidev)) +- l = strpcpyf(&s, l, "f%u", func); +- if (dev_port > 0) +- l = strpcpyf(&s, l, "d%u", dev_port); ++ l = strpcpyf(&s, l, "f%d", func); ++ if (dev_id > 0) ++ l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_path[0] = '\0'; + +@@ -245,8 +251,8 @@ 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 (dev_port > 0) +- l = strpcpyf(&s, l, "d%d", dev_port); ++ if (dev_id > 0) ++ l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_path[0] = '\0'; + } diff --git a/SOURCES/0013-Revert-blkid-Warn-when-rejecting-a-superblock-with-a.patch b/SOURCES/0013-Revert-blkid-Warn-when-rejecting-a-superblock-with-a.patch new file mode 100644 index 00000000..f43c2782 --- /dev/null +++ b/SOURCES/0013-Revert-blkid-Warn-when-rejecting-a-superblock-with-a.patch @@ -0,0 +1,77 @@ +From f1faa24b260222e70d38492e5e3f126700dbd9f8 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 4 Mar 2015 16:10:36 +0100 +Subject: [PATCH] Revert "blkid: Warn when rejecting a superblock with a bad + csum" + +This reverts commit d47f6ca5f9b7a0b400d8bdb050151a0284fb4bdb. +--- + README | 2 +- + configure.ac | 2 +- + src/udev/udev-builtin-blkid.c | 13 +------------ + 3 files changed, 3 insertions(+), 14 deletions(-) + +diff --git a/README b/README +index 287d05c9b..ac2a81c0c 100644 +--- a/README ++++ b/README +@@ -115,7 +115,7 @@ REQUIREMENTS: + libcap + libmount >= 2.20 (from util-linux) + libseccomp >= 1.0.0 (optional) +- libblkid >= 2.24 (from util-linux) (optional) ++ libblkid >= 2.20 (from util-linux) (optional) + libkmod >= 15 (optional) + PAM >= 1.1.2 (optional) + libcryptsetup (optional) +diff --git a/configure.ac b/configure.ac +index f701bcf71..9c25c3c6f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -437,7 +437,7 @@ AM_CONDITIONAL(HAVE_XKBCOMMON, [test "$have_xkbcommon" = "yes"]) + have_blkid=no + AC_ARG_ENABLE(blkid, AS_HELP_STRING([--disable-blkid], [disable blkid support])) + if test "x$enable_blkid" != "xno"; then +- PKG_CHECK_MODULES(BLKID, [ blkid >= 2.24 ], ++ PKG_CHECK_MODULES(BLKID, [ blkid >= 2.20 ], + [AC_DEFINE(HAVE_BLKID, 1, [Define if blkid is available]) have_blkid=yes], have_blkid=no) + if test "x$have_blkid" = xno -a "x$enable_blkid" = xyes; then + AC_MSG_ERROR([*** blkid support requested but libraries not found]) +diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c +index 03e3dc286..89995831b 100644 +--- a/src/udev/udev-builtin-blkid.c ++++ b/src/udev/udev-builtin-blkid.c +@@ -221,7 +221,6 @@ static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool t + blkid_probe pr; + const char *data; + const char *name; +- const char *prtype = NULL; + int nvals; + int i; + int err = 0; +@@ -257,8 +256,7 @@ static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool t + blkid_probe_set_superblocks_flags(pr, + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | +- BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION | +- BLKID_SUBLKS_BADCSUM); ++ BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION); + + if (noraid) + blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID); +@@ -280,15 +278,6 @@ static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool t + err = probe_superblocks(pr); + if (err < 0) + goto out; +- if (blkid_probe_has_value(pr, "SBBADCSUM")) { +- if (!blkid_probe_lookup_value(pr, "TYPE", &prtype, NULL)) +- log_warning("incorrect %s checksum on %s", +- prtype, udev_device_get_devnode(dev)); +- else +- log_warning("incorrect checksum on %s", +- udev_device_get_devnode(dev)); +- goto out; +- } + + /* If we are a partition then our parent passed on the root + * partition UUID to us */ diff --git a/SOURCES/0014-journald-audit-exit-gracefully-in-the-case-we-can-t-.patch b/SOURCES/0014-journald-audit-exit-gracefully-in-the-case-we-can-t-.patch new file mode 100644 index 00000000..74d8ed27 --- /dev/null +++ b/SOURCES/0014-journald-audit-exit-gracefully-in-the-case-we-can-t-.patch @@ -0,0 +1,27 @@ +From 9b5e05005e534fc7fb6dc56c94e3296bb17fe122 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 6 Mar 2015 12:41:20 +0100 +Subject: [PATCH] journald-audit: exit gracefully in the case we can't join + audit multicast group + +--- + src/journal/journald-audit.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c +index c2f1545cc..151097a6e 100644 +--- a/src/journal/journald-audit.c ++++ b/src/journal/journald-audit.c +@@ -529,8 +529,10 @@ int server_open_audit(Server *s) { + } + + r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl)); +- if (r < 0) +- return log_error_errno(errno, "Failed to join audit multicast group: %m"); ++ if (r < 0) { ++ log_warning_errno(errno, "Failed to join audit multicast group, ignoring: %m"); ++ return 0; ++ } + } else + fd_nonblock(s->audit_fd, 1); + diff --git a/SOURCES/0015-fedora-disable-resolv.conf-symlink.patch b/SOURCES/0015-fedora-disable-resolv.conf-symlink.patch new file mode 100644 index 00000000..12ce6da1 --- /dev/null +++ b/SOURCES/0015-fedora-disable-resolv.conf-symlink.patch @@ -0,0 +1,24 @@ +From 634aa6447d365af61b6cd78651eb80c32da966dc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 21:34:14 -0400 +Subject: [PATCH] fedora: disable resolv.conf symlink + +Conflicts: + tmpfiles.d/etc.conf.m4 +--- + tmpfiles.d/etc.conf.m4 | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/tmpfiles.d/etc.conf.m4 b/tmpfiles.d/etc.conf.m4 +index 9b0e080e6..125d6e0a1 100644 +--- a/tmpfiles.d/etc.conf.m4 ++++ b/tmpfiles.d/etc.conf.m4 +@@ -10,8 +10,5 @@ + L /etc/os-release - - - - ../usr/lib/os-release + L /etc/localtime - - - - ../usr/share/zoneinfo/UTC + L+ /etc/mtab - - - - ../proc/self/mounts +-m4_ifdef(`ENABLE_RESOLVED', +-L /etc/resolv.conf - - - - ../run/systemd/resolve/resolv.conf +-)m4_dnl + C /etc/nsswitch.conf - - - - + C /etc/pam.d - - - - diff --git a/SOURCES/0016-Revert-timedated-manage-systemd-timesyncd-directly-i.patch b/SOURCES/0016-Revert-timedated-manage-systemd-timesyncd-directly-i.patch new file mode 100644 index 00000000..25d8aa61 --- /dev/null +++ b/SOURCES/0016-Revert-timedated-manage-systemd-timesyncd-directly-i.patch @@ -0,0 +1,358 @@ +From 1a3dd33f98312421e0f3d654e8f5d56554557a8c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 21:34:14 -0400 +Subject: [PATCH] Revert "timedated: manage systemd-timesyncd directly instead + of lists of alternatives" + +This reverts commit b72ddf0f4f552dd53d6404b6ddbc9f17d02b8e12. + +Conflicts: + Makefile.am + NEWS + src/timedate/timedated.c +--- + Makefile.am | 9 ++ + src/timedate/timedated.c | 252 ++++++++++++++++++++++++++++++----------------- + 2 files changed, 170 insertions(+), 91 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 9e64d6f98..bf65b2406 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -111,6 +111,7 @@ catalogdir=$(prefix)/lib/systemd/catalog + kernelinstalldir = $(prefix)/lib/kernel/install.d + factory_etcdir = $(prefix)/share/factory/etc + factory_pamdir = $(prefix)/share/factory/etc/pam.d ++ntpunitsdir=$(prefix)/lib/systemd/ntp-units.d + + # And these are the special ones for / + rootprefix=@rootprefix@ +@@ -5101,6 +5102,10 @@ dist_systemunit_DATA_busnames += \ + polkitpolicy_files += \ + src/timedate/org.freedesktop.timedate1.policy + ++INSTALL_DIRS += \ ++ $(prefix)/lib/systemd/ntp-units.d \ ++ $(sysconfdir)/systemd/ntp-units.d ++ + SYSTEM_UNIT_ALIASES += \ + systemd-timedated.service dbus-org.freedesktop.timedate1.service + +@@ -5177,6 +5182,10 @@ EXTRA_DIST += \ + + CLEANFILES += \ + src/timesync/timesyncd.conf ++ ++dist_ntpunits_DATA = \ ++ src/timesync/90-systemd.list ++ + endif + + # ------------------------------------------------------------------------------ +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index 753c3d1d6..66097ef74 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -186,141 +186,211 @@ static int context_write_data_local_rtc(Context *c) { + return write_string_file_atomic_label("/etc/adjtime", w); + } + ++static char** get_ntp_services(void) { ++ _cleanup_strv_free_ char **r = NULL, **files = NULL; ++ char **i; ++ int k; ++ ++ k = conf_files_list(&files, ".list", NULL, ++ "/etc/systemd/ntp-units.d", ++ "/run/systemd/ntp-units.d", ++ "/usr/local/lib/systemd/ntp-units.d", ++ "/usr/lib/systemd/ntp-units.d", ++ NULL); ++ if (k < 0) ++ return NULL; ++ ++ STRV_FOREACH(i, files) { ++ _cleanup_fclose_ FILE *f; ++ ++ f = fopen(*i, "re"); ++ if (!f) ++ continue; ++ ++ for (;;) { ++ char line[PATH_MAX], *l; ++ ++ if (!fgets(line, sizeof(line), f)) { ++ if (ferror(f)) ++ log_error("Failed to read NTP unit file: %m"); ++ ++ break; ++ } ++ ++ l = strstrip(line); ++ if (l[0] == 0 || l[0] == '#') ++ continue; ++ ++ if (strv_extend(&r, l) < 0) { ++ log_oom(); ++ return NULL; ++ } ++ } ++ } ++ ++ i = r; ++ r = NULL; /* avoid cleanup */ ++ ++ return strv_uniq(i); ++} ++ + static int context_read_ntp(Context *c, sd_bus *bus) { +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- sd_bus_message *reply = NULL; +- const char *s; ++ _cleanup_strv_free_ char **l; ++ char **i; + int r; + + assert(c); + assert(bus); + +- r = sd_bus_call_method( +- bus, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "GetUnitFileState", +- &error, +- &reply, +- "s", +- "systemd-timesyncd.service"); ++ l = get_ntp_services(); ++ STRV_FOREACH(i, l) { ++ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ sd_bus_message *reply = NULL; ++ const char *s; + +- if (r < 0) { +- if (sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND) || +- sd_bus_error_has_name(&error, "org.freedesktop.systemd1.LoadFailed") || +- sd_bus_error_has_name(&error, "org.freedesktop.systemd1.NoSuchUnit")) +- return 0; ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ "GetUnitFileState", ++ &error, ++ &reply, ++ "s", ++ *i); + +- return r; +- } ++ if (r < 0) { ++ /* This implementation does not exist. Try the next one. */ ++ if (sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND)) ++ continue; + +- r = sd_bus_message_read(reply, "s", &s); +- if (r < 0) +- return r; ++ return r; ++ } ++ ++ r = sd_bus_message_read(reply, "s", &s); ++ if (r < 0) ++ return r; + +- c->can_ntp = true; +- c->use_ntp = STR_IN_SET(s, "enabled", "enabled-runtime"); ++ c->can_ntp = true; ++ c->use_ntp = STR_IN_SET(s, "enabled", "enabled-runtime"); ++ ++ return 0; ++ } + + return 0; + } + + static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) { ++ _cleanup_strv_free_ char **l = NULL; ++ char **i; + int r; + + assert(c); + assert(bus); + assert(error); + +- if (c->use_ntp) +- r = sd_bus_call_method( +- bus, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "StartUnit", +- error, +- NULL, +- "ss", +- "systemd-timesyncd.service", +- "replace"); +- else +- r = sd_bus_call_method( +- bus, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "StopUnit", +- error, +- NULL, +- "ss", +- "systemd-timesyncd.service", +- "replace"); ++ l = get_ntp_services(); ++ STRV_FOREACH(i, l) { ++ ++ if (c->use_ntp) ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ "StartUnit", ++ error, ++ NULL, ++ "ss", *i, "replace"); ++ else ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ "StopUnit", ++ error, ++ NULL, ++ "ss", *i, "replace"); ++ ++ if (r < 0) { ++ if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) || ++ sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") || ++ sd_bus_error_has_name(error, "org.freedesktop.systemd1.NoSuchUnit")) { ++ /* This implementation does not exist. Try the next one. */ ++ sd_bus_error_free(error); ++ continue; ++ } + +- if (r < 0) { +- if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) || +- sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") || +- sd_bus_error_has_name(error, "org.freedesktop.systemd1.NoSuchUnit")) +- return sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported."); ++ return r; ++ } + +- return r; ++ return 1; + } + +- return 0; ++ sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported."); ++ return -ENOTSUP; + } + + static int context_enable_ntp(Context*c, sd_bus *bus, sd_bus_error *error) { ++ _cleanup_strv_free_ char **l = NULL; ++ char **i; + int r; + + assert(c); + assert(bus); + assert(error); + +- if (c->use_ntp) +- r = sd_bus_call_method( +- bus, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "EnableUnitFiles", +- error, +- NULL, +- "asbb", 1, +- "systemd-timesyncd.service", +- false, true); +- else ++ l = get_ntp_services(); ++ STRV_FOREACH(i, l) { ++ if (c->use_ntp) ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ "EnableUnitFiles", ++ error, ++ NULL, ++ "asbb", 1, *i, false, true); ++ else ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ "DisableUnitFiles", ++ error, ++ NULL, ++ "asb", 1, *i, false); ++ ++ if (r < 0) { ++ if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND)) { ++ /* This implementation does not exist. Try the next one. */ ++ sd_bus_error_free(error); ++ continue; ++ } ++ ++ return r; ++ } ++ + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", +- "DisableUnitFiles", ++ "Reload", + error, + NULL, +- "asb", 1, +- "systemd-timesyncd.service", +- false); +- +- if (r < 0) { +- if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND)) +- return sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported."); ++ NULL); ++ if (r < 0) ++ return r; + +- return r; ++ return 1; + } + +- r = sd_bus_call_method( +- bus, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "Reload", +- error, +- NULL, +- NULL); +- if (r < 0) +- return r; +- +- return 0; ++ sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported."); ++ return -ENOTSUP; + } + + static int property_get_rtc_time( diff --git a/SOURCES/0017-journal-remote-fix-certificate-status-memory-leak.patch b/SOURCES/0017-journal-remote-fix-certificate-status-memory-leak.patch new file mode 100644 index 00000000..9d0405cf --- /dev/null +++ b/SOURCES/0017-journal-remote-fix-certificate-status-memory-leak.patch @@ -0,0 +1,28 @@ +From fb1115e5738b798bb99e5a699838395ca463e29d Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Tue, 17 Feb 2015 10:33:01 +0100 +Subject: [PATCH] journal-remote: fix certificate status memory leak + +The output of gnutls_certificate_verification_status_print() needs to be +freed. + +Noticed this while staring at verify_cert_authorized() to see what could +possibly confuse gcc5 on armv7hl to segfault during compilation. + +(cherry picked from commit 9c3cf9693ac5c0a332ba376f99e6adea28b1bb0d) +--- + src/journal-remote/microhttpd-util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c +index 34d93379d..de9c6ab32 100644 +--- a/src/journal-remote/microhttpd-util.c ++++ b/src/journal-remote/microhttpd-util.c +@@ -179,6 +179,7 @@ static int verify_cert_authorized(gnutls_session_t session) { + return log_error_errno(r, "gnutls_certificate_verification_status_print failed: %m"); + + log_info("Certificate status: %s", out.data); ++ gnutls_free(out.data); + + return status == 0 ? 0 : -EPERM; + } diff --git a/SOURCES/0018-journal-remote-fix-client_cert-memory-leak.patch b/SOURCES/0018-journal-remote-fix-client_cert-memory-leak.patch new file mode 100644 index 00000000..11dbfd4e --- /dev/null +++ b/SOURCES/0018-journal-remote-fix-client_cert-memory-leak.patch @@ -0,0 +1,32 @@ +From 0488761858a3bfbf06a25fbf3bc0e28fdfc28234 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Tue, 17 Feb 2015 10:36:57 +0100 +Subject: [PATCH] journal-remote: fix client_cert memory leak + +Found by Valgrind while testing the previous memory leak fix. + +(cherry picked from commit 32c3d7144cf9a5c8c03761d7f198142ca0f5f7b8) +--- + src/journal-remote/microhttpd-util.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c +index de9c6ab32..a95fff18f 100644 +--- a/src/journal-remote/microhttpd-util.c ++++ b/src/journal-remote/microhttpd-util.c +@@ -239,10 +239,14 @@ static int get_auth_dn(gnutls_x509_crt_t client_cert, char **buf) { + return 0; + } + ++static inline void gnutls_x509_crt_deinitp(gnutls_x509_crt_t *p) { ++ gnutls_x509_crt_deinit(*p); ++} ++ + int check_permissions(struct MHD_Connection *connection, int *code, char **hostname) { + const union MHD_ConnectionInfo *ci; + gnutls_session_t session; +- gnutls_x509_crt_t client_cert; ++ _cleanup_(gnutls_x509_crt_deinitp) gnutls_x509_crt_t client_cert = NULL; + _cleanup_free_ char *buf = NULL; + int r; + diff --git a/SOURCES/0019-tmpfiles-Fix-parse_acl-error-message.patch b/SOURCES/0019-tmpfiles-Fix-parse_acl-error-message.patch new file mode 100644 index 00000000..7df522b3 --- /dev/null +++ b/SOURCES/0019-tmpfiles-Fix-parse_acl-error-message.patch @@ -0,0 +1,25 @@ +From 3d9f88326fefe4bf8f5ed4b1210c6b563a3eecff Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Tue, 17 Feb 2015 12:47:51 +0100 +Subject: [PATCH] tmpfiles: Fix parse_acl error message + +parse_acl() returns the error instead of setting errno. + +(cherry picked from commit 484adfd914504cd7e95867cea20ca7af71b888f2) +--- + src/tmpfiles/tmpfiles.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index c948d4d21..88ba7e46a 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -689,7 +689,7 @@ static int get_acls_from_arg(Item *item) { + * 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(errno, "Failed to parse ACL \"%s\": %m. Ignoring", ++ log_warning_errno(r, "Failed to parse ACL \"%s\": %m. Ignoring", + item->argument); + #else + log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring"); diff --git a/SOURCES/0020-test-utf8-fix-utf16-tests-on-BE-machines.patch b/SOURCES/0020-test-utf8-fix-utf16-tests-on-BE-machines.patch new file mode 100644 index 00000000..f1536268 --- /dev/null +++ b/SOURCES/0020-test-utf8-fix-utf16-tests-on-BE-machines.patch @@ -0,0 +1,23 @@ +From c49cced2ef923522398695531363de2eb3940273 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 18 Feb 2015 14:33:50 +0100 +Subject: [PATCH] test: utf8 - fix utf16 tests on BE machines + +(cherry picked from commit 502184de0f95d3a124d4d4c77ae7a88747a0fac2) +--- + src/test/test-utf8.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c +index befa38575..346f8524c 100644 +--- a/src/test/test-utf8.c ++++ b/src/test/test-utf8.c +@@ -95,7 +95,7 @@ static void test_utf8_escaping_printable(void) { + + static void test_utf16_to_utf8(void) { + char *a = NULL; +- const uint16_t utf16[] = { 'a', 0xd800, 'b', 0xdc00, 'c', 0xd801, 0xdc37 }; ++ const uint16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) }; + const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7, 0 }; + + a = utf16_to_utf8(utf16, 14); diff --git a/SOURCES/0021-tmpfiles-avoid-creating-duplicate-acl-entries.patch b/SOURCES/0021-tmpfiles-avoid-creating-duplicate-acl-entries.patch new file mode 100644 index 00000000..a93fca42 --- /dev/null +++ b/SOURCES/0021-tmpfiles-avoid-creating-duplicate-acl-entries.patch @@ -0,0 +1,128 @@ +From c7d4f7a5a6cef5a46f905141e2ac27da3c96d2b7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 23 Feb 2015 23:19:54 -0500 +Subject: [PATCH] tmpfiles: avoid creating duplicate acl entries + +https://bugs.freedesktop.org/show_bug.cgi?id=89202 +https://bugs.debian.org/778656 + +Status quo ante can be restored with: + getfacl -p /var/log/journal/`cat /etc/machine-id`|grep -v '^#'|sort -u|sudo setfacl --set-file=- /var/log/journal/`cat /etc/machine-id` + +(cherry picked from commit 1c73f3bc29111a00738569c9d40a989b161a0624) +--- + src/shared/acl-util.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++-- + src/shared/acl-util.h | 4 +++ + 2 files changed, 81 insertions(+), 2 deletions(-) + +diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c +index a4ff1ab87..cbe09d7ab 100644 +--- a/src/shared/acl-util.c ++++ b/src/shared/acl-util.c +@@ -282,6 +282,77 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) + return 0; + } + ++static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { ++ acl_tag_t tag_a, tag_b; ++ ++ if (acl_get_tag_type(a, &tag_a) < 0) ++ return -errno; ++ ++ if (acl_get_tag_type(b, &tag_b) < 0) ++ return -errno; ++ ++ if (tag_a != tag_b) ++ return false; ++ ++ switch (tag_a) { ++ case ACL_USER_OBJ: ++ case ACL_GROUP_OBJ: ++ case ACL_MASK: ++ case ACL_OTHER: ++ /* can have only one of those */ ++ return true; ++ case ACL_USER: { ++ _cleanup_(acl_free_uid_tpp) uid_t *uid_a, *uid_b; ++ ++ uid_a = acl_get_qualifier(a); ++ if (!uid_a) ++ return -errno; ++ ++ uid_b = acl_get_qualifier(b); ++ if (!uid_b) ++ return -errno; ++ ++ return *uid_a == *uid_b; ++ } ++ case ACL_GROUP: { ++ _cleanup_(acl_free_gid_tpp) gid_t *gid_a, *gid_b; ++ ++ gid_a = acl_get_qualifier(a); ++ if (!gid_a) ++ return -errno; ++ ++ gid_b = acl_get_qualifier(b); ++ if (!gid_b) ++ return -errno; ++ ++ return *gid_a == *gid_b; ++ } ++ default: ++ assert_not_reached("Unknown acl tag type"); ++ } ++} ++ ++static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) { ++ acl_entry_t i; ++ int r; ++ ++ for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); ++ r > 0; ++ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { ++ ++ r = acl_entry_equal(i, entry); ++ if (r < 0) ++ return r; ++ if (r > 0) { ++ *out = i; ++ return 1; ++ } ++ } ++ if (r < 0) ++ return -errno; ++ return 0; ++} ++ + int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { + _cleanup_(acl_freep) acl_t old; + acl_entry_t i; +@@ -297,8 +368,12 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { + + acl_entry_t j; + +- if (acl_create_entry(&old, &j) < 0) +- return -errno; ++ r = find_acl_entry(old, i, &j); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ if (acl_create_entry(&old, &j) < 0) ++ return -errno; + + if (acl_copy_entry(j, i) < 0) + return -errno; +diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h +index 90e88ffa2..fdb90063f 100644 +--- a/src/shared/acl-util.h ++++ b/src/shared/acl-util.h +@@ -41,5 +41,9 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); + DEFINE_TRIVIAL_CLEANUP_FUNC(acl_t, acl_free); + #define acl_free_charp acl_free + DEFINE_TRIVIAL_CLEANUP_FUNC(char*, acl_free_charp); ++#define acl_free_uid_tp acl_free ++DEFINE_TRIVIAL_CLEANUP_FUNC(uid_t*, acl_free_uid_tp); ++#define acl_free_gid_tp acl_free ++DEFINE_TRIVIAL_CLEANUP_FUNC(gid_t*, acl_free_gid_tp); + + #endif diff --git a/SOURCES/0022-shared-time-util-fix-gcc5-warning.patch b/SOURCES/0022-shared-time-util-fix-gcc5-warning.patch new file mode 100644 index 00000000..c88d977c --- /dev/null +++ b/SOURCES/0022-shared-time-util-fix-gcc5-warning.patch @@ -0,0 +1,29 @@ +From 15bfa13aa624e1f2a15571ad5278acec643c0489 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 24 Feb 2015 13:26:09 +0100 +Subject: [PATCH] shared/time-util: fix gcc5 warning + + CC src/shared/libsystemd_shared_la-time-util.lo +src/shared/time-util.c: In function 'parse_nsec': +src/shared/time-util.c:789:25: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] + if (!*s != 0) + ^ + +(cherry picked from commit 8e8933ca0f06bae19cb6db601e83b33f8ac80f2a) +--- + src/shared/time-util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/time-util.c b/src/shared/time-util.c +index 947ac1fcf..1c36c577c 100644 +--- a/src/shared/time-util.c ++++ b/src/shared/time-util.c +@@ -786,7 +786,7 @@ int parse_nsec(const char *t, nsec_t *nsec) { + s = startswith(p, "infinity"); + if (s) { + s += strspn(s, WHITESPACE); +- if (!*s != 0) ++ if (*s != 0) + return -EINVAL; + + *nsec = NSEC_INFINITY; diff --git a/SOURCES/0023-test-time-test-infinity-parsing-in-nanoseconds.patch b/SOURCES/0023-test-time-test-infinity-parsing-in-nanoseconds.patch new file mode 100644 index 00000000..32071ee2 --- /dev/null +++ b/SOURCES/0023-test-time-test-infinity-parsing-in-nanoseconds.patch @@ -0,0 +1,33 @@ +From 33d01e64bc4e286e4eb772de8b3781686c2d3a3a Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 24 Feb 2015 13:27:10 +0100 +Subject: [PATCH] test-time: test "infinity" parsing in nanoseconds + +(cherry picked from commit fdd30a1530810b659345c565e97beef06b7af2fd) +--- + src/test/test-time.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/test/test-time.c b/src/test/test-time.c +index 8cfc4cc4f..3840fff06 100644 +--- a/src/test/test-time.c ++++ b/src/test/test-time.c +@@ -78,12 +78,18 @@ static void test_parse_nsec(void) { + assert_se(u == 2); + assert_se(parse_nsec(".7", &u) >= 0); + assert_se(u == 0); ++ assert_se(parse_nsec("infinity", &u) >= 0); ++ assert_se(u == NSEC_INFINITY); ++ assert_se(parse_nsec(" infinity ", &u) >= 0); ++ assert_se(u == NSEC_INFINITY); + + assert_se(parse_nsec(" xyz ", &u) < 0); + assert_se(parse_nsec("", &u) < 0); + assert_se(parse_nsec(" . ", &u) < 0); + assert_se(parse_nsec(" 5. ", &u) < 0); + assert_se(parse_nsec(".s ", &u) < 0); ++ assert_se(parse_nsec(" infinity .7", &u) < 0); ++ assert_se(parse_nsec(".3 infinity", &u) < 0); + } + + static void test_format_timespan_one(usec_t x, usec_t accuracy) { diff --git a/SOURCES/0024-bootchart-fix-default-init-path.patch b/SOURCES/0024-bootchart-fix-default-init-path.patch new file mode 100644 index 00000000..5412474f --- /dev/null +++ b/SOURCES/0024-bootchart-fix-default-init-path.patch @@ -0,0 +1,41 @@ +From 685ddafd9e3c5f548e02e38633f366ff453f918b Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Tue, 24 Feb 2015 14:30:10 +0100 +Subject: [PATCH] bootchart: fix default init path + +Commit 6e1bf7ab99 used the wrong directory; we need rootlibexecdir, not +rootlibdir, as the latter is something like /lib/x86_64-linux-gnu/ on +multi-arch systems. + +https://launchpad.net/bugs/1423867 +(cherry picked from commit a804d849b3c2199bc25d1d4e65fc119fa4d7d0e2) +--- + Makefile.am | 1 + + src/bootchart/bootchart.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index bf65b2406..2e6455f6e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -199,6 +199,7 @@ AM_CPPFLAGS = \ + -DKEXEC=\"$(KEXEC)\" \ + -DLIBDIR=\"$(libdir)\" \ + -DROOTLIBDIR=\"$(rootlibdir)\" \ ++ -DROOTLIBEXECDIR=\"$(rootlibexecdir)\" \ + -DTEST_DIR=\"$(abs_top_srcdir)/test\" \ + -I $(top_srcdir)/src \ + -I $(top_builddir)/src/shared \ +diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c +index 64a384bac..175be6868 100644 +--- a/src/bootchart/bootchart.c ++++ b/src/bootchart/bootchart.c +@@ -76,7 +76,7 @@ int sysfd=-1; + #define DEFAULT_HZ 25.0 + #define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */ + #define DEFAULT_SCALE_Y 20.0 /* 16px = 1 process bar */ +-#define DEFAULT_INIT ROOTLIBDIR "/systemd/systemd" ++#define DEFAULT_INIT ROOTLIBEXECDIR "/systemd" + #define DEFAULT_OUTPUT "/run/log" + + /* graph defaults */ diff --git a/SOURCES/0025-systemctl-bump-NOFILE-only-for-systemctl_main.patch b/SOURCES/0025-systemctl-bump-NOFILE-only-for-systemctl_main.patch new file mode 100644 index 00000000..711be450 --- /dev/null +++ b/SOURCES/0025-systemctl-bump-NOFILE-only-for-systemctl_main.patch @@ -0,0 +1,41 @@ +From 4581f8d1cde9b6fac4320e5cdf5234c96bbd60ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 24 Feb 2015 10:10:04 -0500 +Subject: [PATCH] systemctl: bump NOFILE only for systemctl_main + +It is not necessary when running as telinit, etc. + +https://bugzilla.redhat.com/show_bug.cgi?id=1184712 +(cherry picked from commit 95d383ee47db488f182048cfd6846f2e6b859f2b) +--- + src/systemctl/systemctl.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 21cb898b9..6b93ec844 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -7204,6 +7204,11 @@ found: + } + } + ++ /* Increase max number of open files to 16K if we can, we ++ * might needs this when browsing journal files, which might ++ * be split up into many files. */ ++ setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); ++ + return verb->dispatch(bus, argv + optind); + } + +@@ -7453,11 +7458,6 @@ int main(int argc, char*argv[]) { + goto finish; + } + +- /* Increase max number of open files to 16K if we can, we +- * might needs this when browsing journal files, which might +- * be split up into many files. */ +- setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); +- + if (!avoid_bus()) + r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus); + diff --git a/SOURCES/0026-acl-util-avoid-freeing-uninitialized-pointer.patch b/SOURCES/0026-acl-util-avoid-freeing-uninitialized-pointer.patch new file mode 100644 index 00000000..8905c894 --- /dev/null +++ b/SOURCES/0026-acl-util-avoid-freeing-uninitialized-pointer.patch @@ -0,0 +1,34 @@ +From 86592a27154d8da0e695304a75ae1458c574c962 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 24 Feb 2015 20:40:07 +0100 +Subject: [PATCH] acl-util: avoid freeing uninitialized pointer + +CID#1271344/1271345 + +(cherry picked from commit 76dcbc4992e895a377aad26f8c4a0dcd71002396) +--- + src/shared/acl-util.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c +index cbe09d7ab..e67e9acb6 100644 +--- a/src/shared/acl-util.c ++++ b/src/shared/acl-util.c +@@ -302,7 +302,7 @@ static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { + /* can have only one of those */ + return true; + case ACL_USER: { +- _cleanup_(acl_free_uid_tpp) uid_t *uid_a, *uid_b; ++ _cleanup_(acl_free_uid_tpp) uid_t *uid_a = NULL, *uid_b = NULL; + + uid_a = acl_get_qualifier(a); + if (!uid_a) +@@ -315,7 +315,7 @@ static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { + return *uid_a == *uid_b; + } + case ACL_GROUP: { +- _cleanup_(acl_free_gid_tpp) gid_t *gid_a, *gid_b; ++ _cleanup_(acl_free_gid_tpp) gid_t *gid_a = NULL, *gid_b = NULL; + + gid_a = acl_get_qualifier(a); + if (!gid_a) diff --git a/SOURCES/0027-bootchart-svg-fix-checking-of-list-end.patch b/SOURCES/0027-bootchart-svg-fix-checking-of-list-end.patch new file mode 100644 index 00000000..9aa8e4c2 --- /dev/null +++ b/SOURCES/0027-bootchart-svg-fix-checking-of-list-end.patch @@ -0,0 +1,25 @@ +From 93ac68f5225bc0cf63ead3a3212539586d1fffb7 Mon Sep 17 00:00:00 2001 +From: Aaro Koskinen +Date: Tue, 24 Feb 2015 18:32:31 +0200 +Subject: [PATCH] bootchart: svg: fix checking of list end + +If we have less samples than expected, systemd-bootchart will crash. + +(cherry picked from commit c1682f17a0c966988e865c649e565dae41abf32d) +--- + src/bootchart/svg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c +index e111fa9cc..144177cd4 100644 +--- a/src/bootchart/svg.c ++++ b/src/bootchart/svg.c +@@ -1170,7 +1170,7 @@ static void svg_ps_bars(void) { + + ps->sample = ps->sample->next; + sample_hz = ps->sample; +- for (ii=0;((ii<(int)arg_hz/2)&&(ps->sample->next));ii++) ++ for (ii=0;((ii<(int)arg_hz/2)&&(sample_hz->next));ii++) + sample_hz = sample_hz->next; + + /* subtract bootchart cpu utilization from total */ diff --git a/SOURCES/0028-systemd-add-getrandom-syscall-numbers-for-MIPS.patch b/SOURCES/0028-systemd-add-getrandom-syscall-numbers-for-MIPS.patch new file mode 100644 index 00000000..540dc288 --- /dev/null +++ b/SOURCES/0028-systemd-add-getrandom-syscall-numbers-for-MIPS.patch @@ -0,0 +1,35 @@ +From 32213f2f1d98bf851a570ecc35c018001e5d5ac4 Mon Sep 17 00:00:00 2001 +From: Aaro Koskinen +Date: Mon, 23 Feb 2015 16:01:31 +0200 +Subject: [PATCH] systemd: add getrandom syscall numbers for MIPS + +Add getrandom syscall numbers for MIPS. Based on Linux 3.17 kernel +(commit 42944521af97a3b25516f15f3149aec3779656dc, "MIPS: Wire up new +syscalls getrandom and memfd_create"). + +(cherry picked from commit 3bec6d4690d2a7f08dc27b8221299c1db94978c4) +--- + src/shared/missing.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 06a55769a..8cb0b2c96 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -243,6 +243,16 @@ static inline int memfd_create(const char *name, unsigned int flags) { + # define __NR_getrandom 349 + # elif defined(__powerpc__) + # define __NR_getrandom 359 ++# elif defined _MIPS_SIM ++# if _MIPS_SIM == _MIPS_SIM_ABI32 ++# define __NR_getrandom 4353 ++# endif ++# if _MIPS_SIM == _MIPS_SIM_NABI32 ++# define __NR_getrandom 6317 ++# endif ++# if _MIPS_SIM == _MIPS_SIM_ABI64 ++# define __NR_getrandom 5313 ++# endif + # else + # warning "__NR_getrandom unknown for your architecture" + # define __NR_getrandom 0xffffffff diff --git a/SOURCES/0029-unit-use-weaker-dependencies-between-mount-and-devic.patch b/SOURCES/0029-unit-use-weaker-dependencies-between-mount-and-devic.patch new file mode 100644 index 00000000..b0c98a85 --- /dev/null +++ b/SOURCES/0029-unit-use-weaker-dependencies-between-mount-and-devic.patch @@ -0,0 +1,30 @@ +From 1c0e8e9ce84cd74a20a60b98ab3a39d75d05b45f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 25 Feb 2015 22:05:14 +0100 +Subject: [PATCH] unit: use weaker dependencies between mount and device units + in --user mode + +When running in user mode unmounting of mount units when a device +vanishes is unlikely to work, and even if it would work is already done +by PID 1 anyway. HEnce, when creating implicit dependencies between +mount units and their backing devices, created a Wants= type dependency +in --user mode, but leave a BindsTo= dependency in --system mode. + +(cherry picked from commit 5bd4b173605142c7be493aa4d958ebaef21f421d) +--- + src/core/unit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index ee8e607c2..9f1e55e2f 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2845,7 +2845,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { + if (r < 0) + return r; + +- r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BINDS_TO, device, true); ++ r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true); + if (r < 0) + return r; + diff --git a/SOURCES/0030-unit-When-stopping-due-to-BindsTo-log-which-unit-cau.patch b/SOURCES/0030-unit-When-stopping-due-to-BindsTo-log-which-unit-cau.patch new file mode 100644 index 00000000..ee8e413e --- /dev/null +++ b/SOURCES/0030-unit-When-stopping-due-to-BindsTo-log-which-unit-cau.patch @@ -0,0 +1,39 @@ +From 95216d7246fe5e8ac404cc9d432072eb59f2af04 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Tue, 17 Feb 2015 13:47:34 -0500 +Subject: [PATCH] unit: When stopping due to BindsTo=, log which unit caused it + +I'm trying to track down a relatively recent change in systemd +which broke OSTree; see https://bugzilla.gnome.org/show_bug.cgi?id=743891 + +Systemd started to stop sysroot.mount, and this patch should help +me debug why at least. + +While we're here, "break" on the first unit we find that will +deactivate, as there's no point in further iteration. + +(cherry picked from commit 98f738b62047229af4a929d7996e2ab04253b02c) +--- + src/core/unit.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 9f1e55e2f..563f6fe85 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -1648,12 +1648,14 @@ static void unit_check_binds_to(Unit *u) { + continue; + + stop = true; ++ break; + } + + if (!stop) + return; + +- log_unit_info(u->id, "Unit %s is bound to inactive unit. Stopping, too.", u->id); ++ assert(other); ++ log_unit_info(u->id, "Unit %s is bound to inactive unit %s. Stopping, too.", u->id, other->id); + + /* A unit we need to run is gone. Sniff. Let's stop this. */ + manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL); diff --git a/SOURCES/0031-sysctl-downgrade-message-about-sysctl-overrides-to-d.patch b/SOURCES/0031-sysctl-downgrade-message-about-sysctl-overrides-to-d.patch new file mode 100644 index 00000000..9789955f --- /dev/null +++ b/SOURCES/0031-sysctl-downgrade-message-about-sysctl-overrides-to-d.patch @@ -0,0 +1,26 @@ +From 24e82cb7aa809bb8d50f40957cfed51dc48e0d72 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 26 Feb 2015 19:00:11 -0500 +Subject: [PATCH] sysctl: downgrade message about sysctl overrides to debug + +Printing it at info level was tedious. We don't do that for any other +overrides. + +(cherry picked from commit 7933e4266f8124e3fca71f67757abd44155fa1cb) +--- + 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 d007c932c..b6945eda5 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -176,7 +176,7 @@ found: + if (streq(value, existing)) + continue; + +- log_info("Overwriting earlier assignment of %s in file '%s'.", p, path); ++ log_debug("Overwriting earlier assignment of %s in file '%s'.", p, path); + free(hashmap_remove(sysctl_options, p)); + free(v); + } diff --git a/SOURCES/0032-sysctl-add-some-hints-how-to-override-settings.patch b/SOURCES/0032-sysctl-add-some-hints-how-to-override-settings.patch new file mode 100644 index 00000000..e2ed67ce --- /dev/null +++ b/SOURCES/0032-sysctl-add-some-hints-how-to-override-settings.patch @@ -0,0 +1,36 @@ +From 66d069acb953ed8f2bfc6d76561d594520b5c67b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 26 Feb 2015 19:05:51 -0500 +Subject: [PATCH] sysctl: add some hints how to override settings + +Also a link to decent documentation for sysrq keys. It is surprising +hard to find. + +https://lists.fedoraproject.org/pipermail/devel/2015-February/208412.html +(cherry picked from commit 16b65d7f463e91f6299dfa7b83d4b5fbeb109d1c) +--- + sysctl.d/50-default.conf | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf +index f18923399..def151bb8 100644 +--- a/sysctl.d/50-default.conf ++++ b/sysctl.d/50-default.conf +@@ -5,9 +5,16 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + +-# See sysctl.d(5) and core(5) for for details. ++# See sysctl.d(5) and core(5) for for documentation. ++ ++# To override settings in this file, create a local file in /etc ++# (e.g. /etc/sysctl.d/90-override.conf), and put any assignments ++# there. + + # System Request functionality of the kernel (SYNC) ++# ++# Use kernel.sysrq = 1 to allow all keys. ++# See http://fedoraproject.org/wiki/QA/Sysrq for a list of values and keys. + kernel.sysrq = 16 + + # Append the PID to the core filename diff --git a/SOURCES/0033-core-rework-device-state-logic.patch b/SOURCES/0033-core-rework-device-state-logic.patch new file mode 100644 index 00000000..20c1f705 --- /dev/null +++ b/SOURCES/0033-core-rework-device-state-logic.patch @@ -0,0 +1,909 @@ +From 30ced6a8c742e1c798fff439b28a9800ca43f3e7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 27 Feb 2015 21:55:08 +0100 +Subject: [PATCH] core: rework device state logic + +This change introduces a new state "tentative" for device units. Device +units are considered "plugged" when udev announced them, "dead" when +they are not available in the kernel, and "tentative" when they are +referenced in /proc/self/mountinfo or /proc/swaps but not (yet) +announced via udev. + +This should fix a race when device nodes (like loop devices) are created +and immediately mounted. Previously, systemd might end up seeing the +mount unit before the device, and would thus pull down the mount because +its BindTo dependency on the device would not be fulfilled. + +(cherry picked from commit 628c89cc68ab96fce2de7ebba5933725d147aecc) +--- + src/core/device.c | 368 +++++++++++++++++++++++++++++++++--------------------- + src/core/device.h | 14 ++- + src/core/mount.c | 46 ++++--- + src/core/swap.c | 32 +++-- + src/core/swap.h | 4 +- + src/core/unit.c | 1 - + 6 files changed, 285 insertions(+), 180 deletions(-) + +diff --git a/src/core/device.c b/src/core/device.c +index d3deac393..75b9a4628 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -36,7 +36,8 @@ + + static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = UNIT_INACTIVE, +- [DEVICE_PLUGGED] = UNIT_ACTIVE ++ [DEVICE_TENTATIVE] = UNIT_ACTIVATING, ++ [DEVICE_PLUGGED] = UNIT_ACTIVE, + }; + + static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); +@@ -65,6 +66,41 @@ static void device_unset_sysfs(Device *d) { + d->sysfs = NULL; + } + ++static int device_set_sysfs(Device *d, const char *sysfs) { ++ Device *first; ++ char *copy; ++ int r; ++ ++ assert(d); ++ ++ if (streq_ptr(d->sysfs, sysfs)) ++ return 0; ++ ++ r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &string_hash_ops); ++ if (r < 0) ++ return r; ++ ++ copy = strdup(sysfs); ++ if (!copy) ++ return -ENOMEM; ++ ++ device_unset_sysfs(d); ++ ++ first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs); ++ LIST_PREPEND(same_sysfs, first, d); ++ ++ r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first); ++ if (r < 0) { ++ LIST_REMOVE(same_sysfs, first, d); ++ free(copy); ++ return r; ++ } ++ ++ d->sysfs = copy; ++ ++ return 0; ++} ++ + static void device_init(Unit *u) { + Device *d = DEVICE(u); + +@@ -112,8 +148,13 @@ static int device_coldplug(Unit *u) { + assert(d); + assert(d->state == DEVICE_DEAD); + +- if (d->sysfs) ++ if (d->found & DEVICE_FOUND_UDEV) ++ /* If udev says the device is around, it's around */ + device_set_state(d, DEVICE_PLUGGED); ++ else if (d->found != DEVICE_NOT_FOUND) ++ /* If a device is found in /proc/self/mountinfo or ++ * /proc/swaps, it's "tentatively" around. */ ++ device_set_state(d, DEVICE_TENTATIVE); + + return 0; + } +@@ -142,49 +183,9 @@ _pure_ static const char *device_sub_state_to_string(Unit *u) { + return device_state_to_string(DEVICE(u)->state); + } + +-static int device_add_escaped_name(Unit *u, const char *dn) { +- _cleanup_free_ char *e = NULL; +- int r; +- +- assert(u); +- assert(dn); +- assert(dn[0] == '/'); +- +- e = unit_name_from_path(dn, ".device"); +- if (!e) +- return -ENOMEM; +- +- r = unit_add_name(u, e); +- if (r < 0 && r != -EEXIST) +- return r; +- +- return 0; +-} +- +-static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) { +- _cleanup_free_ char *e = NULL; +- Unit *u; +- +- assert(m); +- assert(dn); +- assert(dn[0] == '/'); +- assert(_u); +- +- e = unit_name_from_path(dn, ".device"); +- if (!e) +- return -ENOMEM; +- +- u = manager_get_unit(m, e); +- if (u) { +- *_u = u; +- return 1; +- } +- +- return 0; +-} +- +-static int device_make_description(Unit *u, struct udev_device *dev, const char *path) { ++static int device_update_description(Unit *u, struct udev_device *dev, const char *path) { + const char *model; ++ int r; + + assert(u); + assert(dev); +@@ -209,13 +210,16 @@ static int device_make_description(Unit *u, struct udev_device *dev, const char + + j = strjoin(model, " ", label, NULL); + if (j) +- return unit_set_description(u, j); +- } ++ r = unit_set_description(u, j); ++ } else ++ r = unit_set_description(u, model); ++ } else ++ r = unit_set_description(u, path); + +- return unit_set_description(u, model); +- } ++ if (r < 0) ++ log_unit_error_errno(u->id, r, "Failed to set device description: %m"); + +- return unit_set_description(u, path); ++ return r; + } + + static int device_add_udev_wants(Unit *u, struct udev_device *dev) { +@@ -242,20 +246,20 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) { + + n = unit_name_mangle(e, MANGLE_NOGLOB); + if (!n) +- return -ENOMEM; ++ return log_oom(); + + r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true); + if (r < 0) +- return r; ++ return log_unit_error_errno(u->id, r, "Failed to add wants dependency: %m"); + } + if (!isempty(state)) +- log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.", +- property, strna(udev_device_get_syspath(dev))); ++ log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.", property, strna(udev_device_get_syspath(dev))); + + return 0; + } + +-static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) { ++static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) { ++ _cleanup_free_ char *e = NULL; + const char *sysfs; + Unit *u = NULL; + bool delete; +@@ -269,12 +273,18 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p + if (!sysfs) + return 0; + +- r = device_find_escape_name(m, path, &u); +- if (r < 0) +- return r; ++ e = unit_name_from_path(path, ".device"); ++ if (!e) ++ return log_oom(); ++ ++ u = manager_get_unit(m, e); + +- if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs)) ++ if (u && ++ DEVICE(u)->sysfs && ++ !path_equal(DEVICE(u)->sysfs, sysfs)) { ++ log_unit_error(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); + return -EEXIST; ++ } + + if (!u) { + delete = true; +@@ -283,7 +293,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p + if (!u) + return log_oom(); + +- r = device_add_escaped_name(u, path); ++ r = unit_add_name(u, e); + if (r < 0) + goto fail; + +@@ -295,37 +305,16 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p + * actually been seen yet ->sysfs will not be + * initialized. Hence initialize it if necessary. */ + +- if (!DEVICE(u)->sysfs) { +- Device *first; +- +- DEVICE(u)->sysfs = strdup(sysfs); +- if (!DEVICE(u)->sysfs) { +- r = -ENOMEM; +- goto fail; +- } +- +- r = hashmap_ensure_allocated(&m->devices_by_sysfs, &string_hash_ops); +- if (r < 0) +- goto fail; +- +- first = hashmap_get(m->devices_by_sysfs, sysfs); +- LIST_PREPEND(same_sysfs, first, DEVICE(u)); +- +- r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first); +- if (r < 0) +- goto fail; +- } +- +- device_make_description(u, dev, path); ++ r = device_set_sysfs(DEVICE(u), sysfs); ++ if (r < 0) ++ goto fail; + +- if (main) { +- /* The additional systemd udev properties we only +- * interpret for the main object */ ++ (void) device_update_description(u, dev, path); + +- r = device_add_udev_wants(u, dev); +- if (r < 0) +- goto fail; +- } ++ /* The additional systemd udev properties we only interpret ++ * for the main object */ ++ if (main) ++ (void) device_add_udev_wants(u, dev); + + /* Note that this won't dispatch the load queue, the caller + * has to do that if needed and appropriate */ +@@ -334,7 +323,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p + return 0; + + fail: +- log_warning_errno(r, "Failed to load device unit: %m"); ++ log_unit_warning_errno(u->id, r, "Failed to set up device unit: %m"); + + if (delete && u) + unit_free(u); +@@ -342,7 +331,7 @@ fail: + return r; + } + +-static int device_process_new_device(Manager *m, struct udev_device *dev) { ++static int device_process_new(Manager *m, struct udev_device *dev) { + const char *sysfs, *dn, *alias; + struct udev_list_entry *item = NULL, *first = NULL; + int r; +@@ -354,14 +343,14 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) { + return 0; + + /* Add the main unit named after the sysfs path */ +- r = device_update_unit(m, dev, sysfs, true); ++ r = device_setup_unit(m, dev, sysfs, true); + if (r < 0) + return r; + + /* Add an additional unit for the device node */ + dn = udev_device_get_devnode(dev); + if (dn) +- device_update_unit(m, dev, dn, false); ++ (void) device_setup_unit(m, dev, dn, false); + + /* Add additional units for all symlinks */ + first = udev_device_get_devlinks_list_entry(dev); +@@ -388,7 +377,7 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) { + st.st_rdev != udev_device_get_devnum(dev)) + continue; + +- device_update_unit(m, dev, p, false); ++ (void) device_setup_unit(m, dev, p, false); + } + + /* Add additional units for all explicitly configured +@@ -405,7 +394,7 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) { + e[l] = 0; + + if (path_is_absolute(e)) +- device_update_unit(m, dev, e, false); ++ (void) device_setup_unit(m, dev, e, false); + else + log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e); + } +@@ -416,39 +405,62 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) { + return 0; + } + +-static void device_set_path_plugged(Manager *m, struct udev_device *dev) { +- const char *sysfs; ++static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) { ++ DeviceFound n; ++ ++ assert(d); ++ ++ n = add ? (d->found | found) : (d->found & ~found); ++ if (n == d->found) ++ return; ++ ++ d->found = n; ++ ++ if (now) { ++ if (d->found & DEVICE_FOUND_UDEV) ++ device_set_state(d, DEVICE_PLUGGED); ++ else if (d->found != DEVICE_NOT_FOUND) ++ device_set_state(d, DEVICE_TENTATIVE); ++ else ++ device_set_state(d, DEVICE_DEAD); ++ } ++} ++ ++static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) { + Device *d, *l; + + assert(m); +- assert(dev); ++ assert(sysfs); + +- sysfs = udev_device_get_syspath(dev); +- if (!sysfs) +- return; ++ if (found == DEVICE_NOT_FOUND) ++ return 0; + + l = hashmap_get(m->devices_by_sysfs, sysfs); + LIST_FOREACH(same_sysfs, d, l) +- device_set_state(d, DEVICE_PLUGGED); ++ device_update_found_one(d, add, found, now); ++ ++ return 0; + } + +-static int device_process_removed_device(Manager *m, struct udev_device *dev) { +- const char *sysfs; +- Device *d; ++static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) { ++ _cleanup_free_ char *e = NULL; ++ Unit *u; + + assert(m); +- assert(dev); ++ assert(path); + +- sysfs = udev_device_get_syspath(dev); +- if (!sysfs) +- return -ENOMEM; ++ if (found == DEVICE_NOT_FOUND) ++ return 0; + +- /* Remove all units of this sysfs path */ +- while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) { +- device_unset_sysfs(d); +- device_set_state(d, DEVICE_DEAD); +- } ++ e = unit_name_from_path(path, ".device"); ++ if (!e) ++ return log_oom(); + ++ u = manager_get_unit(m, e); ++ if (!u) ++ return 0; ++ ++ device_update_found_one(DEVICE(u), add, found, now); + return 0; + } + +@@ -464,22 +476,6 @@ static bool device_is_ready(struct udev_device *dev) { + return parse_boolean(ready) != 0; + } + +-static int device_process_new_path(Manager *m, const char *path) { +- _cleanup_udev_device_unref_ struct udev_device *dev = NULL; +- +- assert(m); +- assert(path); +- +- dev = udev_device_new_from_syspath(m->udev, path); +- if (!dev) +- return log_oom(); +- +- if (!device_is_ready(dev)) +- return 0; +- +- return device_process_new_device(m, dev); +-} +- + static Unit *device_following(Unit *u) { + Device *d = DEVICE(u); + Device *other, *first = NULL; +@@ -606,12 +602,31 @@ static int device_enumerate(Manager *m) { + goto fail; + + first = udev_enumerate_get_list_entry(e); +- udev_list_entry_foreach(item, first) +- device_process_new_path(m, udev_list_entry_get_name(item)); ++ udev_list_entry_foreach(item, first) { ++ _cleanup_udev_device_unref_ struct udev_device *dev = NULL; ++ const char *sysfs; ++ ++ sysfs = udev_list_entry_get_name(item); ++ ++ dev = udev_device_new_from_syspath(m->udev, sysfs); ++ if (!dev) { ++ log_oom(); ++ continue; ++ } ++ ++ if (!device_is_ready(dev)) ++ continue; ++ ++ (void) device_process_new(m, dev); ++ ++ device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false); ++ } + + return 0; + + fail: ++ log_error_errno(r, "Failed to enumerate devices: %m"); ++ + device_shutdown(m); + return r; + } +@@ -619,7 +634,7 @@ fail: + static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_udev_device_unref_ struct udev_device *dev = NULL; + Manager *m = userdata; +- const char *action; ++ const char *action, *sysfs; + int r; + + assert(m); +@@ -641,33 +656,47 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + if (!dev) + return 0; + ++ sysfs = udev_device_get_syspath(dev); ++ if (!sysfs) { ++ log_error("Failed to get udev sys path."); ++ return 0; ++ } ++ + action = udev_device_get_action(dev); + if (!action) { + log_error("Failed to get udev action string."); + return 0; + } + +- if (streq(action, "remove") || !device_is_ready(dev)) { +- r = device_process_removed_device(m, dev); +- if (r < 0) +- log_error_errno(r, "Failed to process device remove event: %m"); +- +- r = swap_process_removed_device(m, dev); ++ if (streq(action, "remove")) { ++ r = swap_process_device_remove(m, dev); + if (r < 0) + log_error_errno(r, "Failed to process swap device remove event: %m"); + +- } else { +- r = device_process_new_device(m, dev); +- if (r < 0) +- log_error_errno(r, "Failed to process device new event: %m"); ++ /* If we get notified that a device was removed by ++ * udev, then it's completely gone, hence unset all ++ * found bits */ ++ device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP, true); + +- r = swap_process_new_device(m, dev); ++ } else if (device_is_ready(dev)) { ++ ++ (void) device_process_new(m, dev); ++ ++ r = swap_process_device_new(m, dev); + if (r < 0) + log_error_errno(r, "Failed to process swap device new event: %m"); + + manager_dispatch_load_queue(m); + +- device_set_path_plugged(m, dev); ++ /* The device is found now, set the udev found bit */ ++ device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, true); ++ ++ } else { ++ /* The device is nominally around, but not ready for ++ * us. Hence unset the udev bit, but leave the rest ++ * around. */ ++ ++ device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV, true); + } + + return 0; +@@ -686,9 +715,58 @@ static bool device_supported(Manager *m) { + return read_only <= 0; + } + ++int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now) { ++ _cleanup_udev_device_unref_ struct udev_device *dev = NULL; ++ struct stat st; ++ ++ assert(m); ++ assert(node); ++ ++ /* This is called whenever we find a device referenced in ++ * /proc/swaps or /proc/self/mounts. Such a device might be ++ * mounted/enabled at a time where udev has not finished ++ * probing it yet, and we thus haven't learned about it ++ * yet. In this case we will set the device unit to ++ * "tentative" state. */ ++ ++ if (add) { ++ if (!path_startswith(node, "/dev")) ++ return 0; ++ ++ if (stat(node, &st) < 0) { ++ if (errno == ENOENT) ++ return 0; ++ ++ return log_error_errno(errno, "Failed to stat device node file %s: %m", node); ++ } ++ ++ if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ++ return 0; ++ ++ dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev); ++ if (!dev) { ++ if (errno == ENOENT) ++ return 0; ++ ++ return log_oom(); ++ } ++ ++ /* If the device is known in the kernel and newly ++ * appeared, then we'll create a device unit for it, ++ * under the name referenced in /proc/swaps or ++ * /proc/self/mountinfo. */ ++ ++ (void) device_setup_unit(m, dev, node, false); ++ } ++ ++ /* Update the device unit's state, should it exist */ ++ return device_update_found_by_name(m, node, add, found, now); ++} ++ + static const char* const device_state_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = "dead", +- [DEVICE_PLUGGED] = "plugged" ++ [DEVICE_TENTATIVE] = "tentative", ++ [DEVICE_PLUGGED] = "plugged", + }; + + DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); +diff --git a/src/core/device.h b/src/core/device.h +index bb7ae0783..0609b20fd 100644 +--- a/src/core/device.h ++++ b/src/core/device.h +@@ -29,20 +29,28 @@ typedef struct Device Device; + * simplifies the state engine greatly */ + typedef enum DeviceState { + DEVICE_DEAD, +- DEVICE_PLUGGED, ++ DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ ++ DEVICE_PLUGGED, /* announced by udev */ + _DEVICE_STATE_MAX, + _DEVICE_STATE_INVALID = -1 + } DeviceState; + ++typedef enum DeviceFound { ++ DEVICE_NOT_FOUND = 0, ++ DEVICE_FOUND_UDEV = 1, ++ DEVICE_FOUND_MOUNT = 2, ++ DEVICE_FOUND_SWAP = 4, ++} DeviceFound; ++ + struct Device { + Unit meta; + + char *sysfs; ++ DeviceFound found; + + /* In order to be able to distinguish dependencies on + different device nodes we might end up creating multiple + devices for the same sysfs path. We chain them up here. */ +- + LIST_FIELDS(struct Device, same_sysfs); + + DeviceState state; +@@ -52,3 +60,5 @@ extern const UnitVTable device_vtable; + + const char* device_state_to_string(DeviceState i) _const_; + DeviceState device_state_from_string(const char *s) _pure_; ++ ++int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now); +diff --git a/src/core/mount.c b/src/core/mount.c +index f3977e62d..c971330af 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1391,7 +1391,7 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user + return 0; + } + +-static int mount_add_one( ++static int mount_setup_unit( + Manager *m, + const char *what, + const char *where, +@@ -1434,7 +1434,7 @@ static int mount_add_one( + + u = unit_new(m, sizeof(Mount)); + if (!u) +- return -ENOMEM; ++ return log_oom(); + + r = unit_add_name(u, e); + if (r < 0) +@@ -1547,6 +1547,8 @@ static int mount_add_one( + return 0; + + fail: ++ log_warning_errno(r, "Failed to set up mount unit: %m"); ++ + if (delete && u) + unit_free(u); + +@@ -1554,33 +1556,36 @@ fail: + } + + static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { +- _cleanup_(mnt_free_tablep) struct libmnt_table *tb = NULL; +- _cleanup_(mnt_free_iterp) struct libmnt_iter *itr = NULL; +- struct libmnt_fs *fs; ++ _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; ++ _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; + int r = 0; + + assert(m); + +- tb = mnt_new_table(); +- itr = mnt_new_iter(MNT_ITER_FORWARD); +- if (!tb || !itr) ++ t = mnt_new_table(); ++ if (!t) + return log_oom(); + +- r = mnt_table_parse_mtab(tb, NULL); ++ i = mnt_new_iter(MNT_ITER_FORWARD); ++ if (!i) ++ return log_oom(); ++ ++ r = mnt_table_parse_mtab(t, NULL); + if (r < 0) +- return r; ++ return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m"); + + r = 0; + for (;;) { + const char *device, *path, *options, *fstype; + _cleanup_free_ const char *d = NULL, *p = NULL; ++ struct libmnt_fs *fs; + int k; + +- k = mnt_table_next_fs(tb, itr, &fs); ++ k = mnt_table_next_fs(t, i, &fs); + if (k == 1) + break; +- else if (k < 0) +- return log_error_errno(k, "Failed to get next entry from /etc/fstab: %m"); ++ if (k < 0) ++ return log_error_errno(k, "Failed to get next entry from /proc/self/mountinfo: %m"); + + device = mnt_fs_get_source(fs); + path = mnt_fs_get_target(fs); +@@ -1588,11 +1593,16 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { + fstype = mnt_fs_get_fstype(fs); + + d = cunescape(device); ++ if (!d) ++ return log_oom(); ++ + p = cunescape(path); +- if (!d || !p) ++ if (!p) + return log_oom(); + +- k = mount_add_one(m, d, p, options, fstype, set_flags); ++ (void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags); ++ ++ k = mount_setup_unit(m, d, p, options, fstype, set_flags); + if (r == 0 && k < 0) + r = k; + } +@@ -1736,8 +1746,6 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + + r = mount_load_proc_self_mountinfo(m, true); + if (r < 0) { +- log_error_errno(r, "Failed to reread /proc/self/mountinfo: %m"); +- + /* Reset flags, just in case, for later calls */ + LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) { + Mount *mount = MOUNT(u); +@@ -1770,6 +1778,10 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + break; + } + ++ if (mount->parameters_proc_self_mountinfo.what) ++ (void) device_found_node(m, mount->parameters_proc_self_mountinfo.what, false, DEVICE_FOUND_MOUNT, true); ++ ++ + } else if (mount->just_mounted || mount->just_changed) { + + /* New or changed mount entry */ +diff --git a/src/core/swap.c b/src/core/swap.c +index 6997921fd..5c19af5d9 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -338,7 +338,7 @@ static int swap_load(Unit *u) { + return swap_verify(s); + } + +-static int swap_add_one( ++static int swap_setup_unit( + Manager *m, + const char *what, + const char *what_proc_swaps, +@@ -363,8 +363,10 @@ static int swap_add_one( + + if (u && + SWAP(u)->from_proc_swaps && +- !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) ++ !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) { ++ log_error("Swap %s appeared twice with different device paths %s and %s", e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps); + return -EEXIST; ++ } + + if (!u) { + delete = true; +@@ -379,7 +381,7 @@ static int swap_add_one( + + SWAP(u)->what = strdup(what); + if (!SWAP(u)->what) { +- r = log_oom(); ++ r = -ENOMEM; + goto fail; + } + +@@ -407,7 +409,6 @@ static int swap_add_one( + p->priority = priority; + + unit_add_to_dbus_queue(u); +- + return 0; + + fail: +@@ -419,7 +420,7 @@ fail: + return r; + } + +-static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) { ++static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + const char *dn; +@@ -428,7 +429,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool + + assert(m); + +- r = swap_add_one(m, device, device, prio, set_flags); ++ r = swap_setup_unit(m, device, device, prio, set_flags); + if (r < 0) + return r; + +@@ -444,7 +445,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool + /* Add the main device node */ + dn = udev_device_get_devnode(d); + if (dn && !streq(dn, device)) +- swap_add_one(m, dn, device, prio, set_flags); ++ swap_setup_unit(m, dn, device, prio, set_flags); + + /* Add additional units for all symlinks */ + first = udev_device_get_devlinks_list_entry(d); +@@ -465,7 +466,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool + st.st_rdev != udev_device_get_devnum(d)) + continue; + +- swap_add_one(m, p, device, prio, set_flags); ++ swap_setup_unit(m, p, device, prio, set_flags); + } + + return r; +@@ -1091,15 +1092,17 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) { + if (k == EOF) + break; + +- log_warning("Failed to parse /proc/swaps:%u", i); ++ log_warning("Failed to parse /proc/swaps:%u.", i); + continue; + } + + d = cunescape(dev); + if (!d) +- return -ENOMEM; ++ return log_oom(); ++ ++ device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags); + +- k = swap_process_new_swap(m, d, prio, set_flags); ++ k = swap_process_new(m, d, prio, set_flags); + if (k < 0) + r = k; + } +@@ -1151,6 +1154,9 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v + break; + } + ++ if (swap->what) ++ device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true); ++ + } else if (swap->just_activated) { + + /* New swap entry */ +@@ -1298,7 +1304,7 @@ fail: + return r; + } + +-int swap_process_new_device(Manager *m, struct udev_device *dev) { ++int swap_process_device_new(Manager *m, struct udev_device *dev) { + struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_free_ char *e = NULL; + const char *dn; +@@ -1341,7 +1347,7 @@ int swap_process_new_device(Manager *m, struct udev_device *dev) { + return r; + } + +-int swap_process_removed_device(Manager *m, struct udev_device *dev) { ++int swap_process_device_remove(Manager *m, struct udev_device *dev) { + const char *dn; + int r = 0; + Swap *s; +diff --git a/src/core/swap.h b/src/core/swap.h +index 73e64d87a..914a2dbcc 100644 +--- a/src/core/swap.h ++++ b/src/core/swap.h +@@ -116,8 +116,8 @@ struct Swap { + + extern const UnitVTable swap_vtable; + +-int swap_process_new_device(Manager *m, struct udev_device *dev); +-int swap_process_removed_device(Manager *m, struct udev_device *dev); ++int swap_process_device_new(Manager *m, struct udev_device *dev); ++int swap_process_device_remove(Manager *m, struct udev_device *dev); + + const char* swap_state_to_string(SwapState i) _const_; + SwapState swap_state_from_string(const char *s) _pure_; +diff --git a/src/core/unit.c b/src/core/unit.c +index 563f6fe85..a6558ee23 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2843,7 +2843,6 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { + return -ENOMEM; + + r = manager_load_unit(u->manager, e, NULL, NULL, &device); +- + if (r < 0) + return r; + diff --git a/SOURCES/0034-core-fix-return-value-on-OOM.patch b/SOURCES/0034-core-fix-return-value-on-OOM.patch new file mode 100644 index 00000000..e1916e0f --- /dev/null +++ b/SOURCES/0034-core-fix-return-value-on-OOM.patch @@ -0,0 +1,23 @@ +From 8cbaef2f9e08dc14e827445de76072e31aa6cce7 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sat, 28 Feb 2015 23:39:55 +0100 +Subject: [PATCH] core: fix return value on OOM + +(cherry picked from commit c43b2132f37264600cc26e07c8d85dfdd6c969f0) +--- + src/core/device.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/core/device.c b/src/core/device.c +index 75b9a4628..1cc103c29 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -211,6 +211,8 @@ static int device_update_description(Unit *u, struct udev_device *dev, const cha + j = strjoin(model, " ", label, NULL); + if (j) + r = unit_set_description(u, j); ++ else ++ r = -ENOMEM; + } else + r = unit_set_description(u, model); + } else diff --git a/SOURCES/0035-machined-use-x-machine-unix-prefix-for-the-container.patch b/SOURCES/0035-machined-use-x-machine-unix-prefix-for-the-container.patch new file mode 100644 index 00000000..65398d52 --- /dev/null +++ b/SOURCES/0035-machined-use-x-machine-unix-prefix-for-the-container.patch @@ -0,0 +1,30 @@ +From e02e6845a4c4abe7d79df4305810703af5e6ec21 Mon Sep 17 00:00:00 2001 +From: Benjamin Franzke +Date: Thu, 19 Feb 2015 20:47:28 +0100 +Subject: [PATCH] machined: use x-machine-unix prefix for the container bus on + dbus1 + +This fixes "machinectl login" on systems configured with --disable-kdbus. + +The error was: +machinectl login foo +Failed to get machine PTY: Input/output error + +(cherry picked from commit f2273101c21bc59a390379e182e53cd4f07a7e71) +--- + src/machine/machine-dbus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c +index b46f0a8da..b0f0f66e0 100644 +--- a/src/machine/machine-dbus.c ++++ b/src/machine/machine-dbus.c +@@ -477,7 +477,7 @@ int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *us + #ifdef ENABLE_KDBUS + asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader); + #else +- asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT, m->leader); ++ asprintf(&container_bus->address, "x-machine-unix:pid=" PID_FMT, m->leader); + #endif + if (!container_bus->address) + return -ENOMEM; diff --git a/SOURCES/0036-shared-AFS-is-also-a-network-filesystem.patch b/SOURCES/0036-shared-AFS-is-also-a-network-filesystem.patch new file mode 100644 index 00000000..25f87b12 --- /dev/null +++ b/SOURCES/0036-shared-AFS-is-also-a-network-filesystem.patch @@ -0,0 +1,22 @@ +From 46392c1d8f433ee44fc5bacb085879779a662468 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Fri, 20 Feb 2015 15:35:11 -0300 +Subject: [PATCH] shared: AFS is also a network filesystem + +(cherry picked from commit ba89821c104d959082aad6f3f0e05a8afd575023) +--- + src/shared/util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/util.c b/src/shared/util.c +index ba035caed..f24b5b4ec 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -1689,6 +1689,7 @@ bool chars_intersect(const char *a, const char *b) { + + bool fstype_is_network(const char *fstype) { + static const char table[] = ++ "afs\0" + "cifs\0" + "smbfs\0" + "sshfs\0" diff --git a/SOURCES/0037-core-downgrade-unit-type-not-supported-message.patch b/SOURCES/0037-core-downgrade-unit-type-not-supported-message.patch new file mode 100644 index 00000000..29e00ddb --- /dev/null +++ b/SOURCES/0037-core-downgrade-unit-type-not-supported-message.patch @@ -0,0 +1,28 @@ +From 0b78cbf29f02adc3cc490bf2b4e9365057ed7d7b Mon Sep 17 00:00:00 2001 +From: Umut Tezduyar Lindskog +Date: Fri, 20 Feb 2015 10:53:28 +0100 +Subject: [PATCH] core: downgrade unit type not supported message + +Otherwise every daemon reload prints out warnings like: + +systemd[1]: Unit type .busname is not supported on this system. +systemd[1]: Unit type .swap is not supported on this system. + +(cherry picked from commit 03afec3c9aa849ba13161c253b129b834298fd40) +--- + 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 4775219e4..bc9b7ec62 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -961,7 +961,7 @@ int manager_enumerate(Manager *m) { + int q; + + if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) { +- log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c)); ++ log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c)); + continue; + } + diff --git a/SOURCES/0038-journal-remote-fix-saving-of-binary-fields.patch b/SOURCES/0038-journal-remote-fix-saving-of-binary-fields.patch new file mode 100644 index 00000000..1fd7e481 --- /dev/null +++ b/SOURCES/0038-journal-remote-fix-saving-of-binary-fields.patch @@ -0,0 +1,94 @@ +From 608259be892c532d0afaeb81de3a5ee578d7658a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 2 Mar 2015 10:34:51 -0500 +Subject: [PATCH] journal-remote: fix saving of binary fields + +Binary fields were not processed properly, and resulting journal files +were non-conforming, resulting in an error ("Invalid field.") when reading. + +https://bugs.freedesktop.org/show_bug.cgi?id=89391 +(cherry picked from commit 09d801a82a46df518dd752e40bf13ac404daa2ce) +--- + src/journal-remote/journal-remote-parse.c | 31 ++++++++++++++++++------------- + src/journal-remote/journal-remote-parse.h | 4 +++- + 2 files changed, 21 insertions(+), 14 deletions(-) + +diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c +index d9dea8deb..afded7e38 100644 +--- a/src/journal-remote/journal-remote-parse.c ++++ b/src/journal-remote/journal-remote-parse.c +@@ -344,22 +344,25 @@ int process_data(RemoteSource *source) { + LLLLLLLL0011223344...\n + */ + sep = memchr(line, '=', n); +- if (sep) ++ if (sep) { + /* chomp newline */ + n--; +- else ++ ++ r = iovw_put(&source->iovw, line, n); ++ if (r < 0) ++ return r; ++ } else { + /* replace \n with = */ + line[n-1] = '='; +- log_trace("Received: %.*s", (int) n, line); + +- r = iovw_put(&source->iovw, line, n); +- if (r < 0) { +- log_error("Failed to put line in iovect"); +- return r; ++ source->field_len = n; ++ source->state = STATE_DATA_START; ++ ++ /* we cannot put the field in iovec until we have all data */ + } + +- if (!sep) +- source->state = STATE_DATA_START; ++ log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary"); ++ + return 0; /* continue */ + } + +@@ -382,6 +385,7 @@ int process_data(RemoteSource *source) { + + case STATE_DATA: { + void *data; ++ char *field; + + assert(source->data_size > 0); + +@@ -396,11 +400,12 @@ int process_data(RemoteSource *source) { + + assert(data); + +- r = iovw_put(&source->iovw, data, source->data_size); +- if (r < 0) { +- log_error("failed to put binary buffer in iovect"); ++ field = (char*) data - sizeof(uint64_t) - source->field_len; ++ memmove(field + sizeof(uint64_t), field, source->field_len); ++ ++ r = iovw_put(&source->iovw, field + sizeof(uint64_t), source->field_len + source->data_size); ++ if (r < 0) + return r; +- } + + source->state = STATE_DATA_FINISH; + +diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h +index 8499f4eb8..22db55091 100644 +--- a/src/journal-remote/journal-remote-parse.h ++++ b/src/journal-remote/journal-remote-parse.h +@@ -42,7 +42,9 @@ typedef struct RemoteSource { + size_t offset; /* offset to the beginning of live data in the buffer */ + size_t scanned; /* number of bytes since the beginning of data without a newline */ + size_t filled; /* total number of bytes in the buffer */ +- size_t data_size; /* size of the binary data chunk being processed */ ++ ++ size_t field_len; /* used for binary fields: the field name length */ ++ size_t data_size; /* and the size of the binary data chunk being processed */ + + struct iovec_wrapper iovw; + diff --git a/SOURCES/0039-journal-fix-Inappropriate-ioctl-for-device-on-ext4.patch b/SOURCES/0039-journal-fix-Inappropriate-ioctl-for-device-on-ext4.patch new file mode 100644 index 00000000..b628a6ac --- /dev/null +++ b/SOURCES/0039-journal-fix-Inappropriate-ioctl-for-device-on-ext4.patch @@ -0,0 +1,34 @@ +From b3df4af4258e3285704f9622b9655084439c6f5e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Sun, 1 Mar 2015 21:13:10 -0300 +Subject: [PATCH] journal: fix Inappropriate ioctl for device on ext4 + +Logs constantly show + +systemd-journald[395]: Failed to set file attributes: Inappropriate ioctl for device + +This is because ext4 does not support FS_NOCOW_FL. + +[zj: fold into one conditional as suggested on the ML and + fix (preexisting) r/errno confusion in error message.] + +(cherry picked from commit 65eae3b76243d2dfd869f8c43b787575f7b4b994) +--- + src/journal/journal-file.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 2845e05ce..0f28718b0 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -2611,8 +2611,8 @@ int journal_file_open( + * shouldn't be too bad, given that we do our own + * checksumming). */ + r = chattr_fd(f->fd, true, FS_NOCOW_FL); +- if (r < 0) +- log_warning_errno(errno, "Failed to set file attributes: %m"); ++ if (r < 0 && r != -ENOTTY) ++ log_warning_errno(r, "Failed to set file attributes: %m"); + + /* Let's attach the creation time to the journal file, + * so that the vacuuming code knows the age of this diff --git a/SOURCES/0040-sd-daemon-replace-VLA-with-alloca-to-make-llvm-happy.patch b/SOURCES/0040-sd-daemon-replace-VLA-with-alloca-to-make-llvm-happy.patch new file mode 100644 index 00000000..e31e45de --- /dev/null +++ b/SOURCES/0040-sd-daemon-replace-VLA-with-alloca-to-make-llvm-happy.patch @@ -0,0 +1,49 @@ +From 529c94b47f886f99796cff0f5827d6c2ebdcea19 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Mar 2015 20:55:38 +0100 +Subject: [PATCH] sd-daemon: replace VLA with alloca(), to make llvm happy + +https://bugs.freedesktop.org/show_bug.cgi?id=89379 +(cherry picked from commit d4a144fadf89bca681724c6c9a65b4a165fa0f90) +--- + src/libsystemd/sd-daemon/sd-daemon.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c +index 028c2a7a5..22a3a5347 100644 +--- a/src/libsystemd/sd-daemon/sd-daemon.c ++++ b/src/libsystemd/sd-daemon/sd-daemon.c +@@ -352,11 +352,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char + .msg_iovlen = 1, + .msg_name = &sockaddr, + }; +- union { +- struct cmsghdr cmsghdr; +- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + +- CMSG_SPACE(sizeof(int) * n_fds)]; +- } control; ++ struct cmsghdr *control; + _cleanup_close_ int fd = -1; + struct cmsghdr *cmsg = NULL; + const char *e; +@@ -400,8 +396,10 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char + if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) + msghdr.msg_namelen = sizeof(struct sockaddr_un); + ++ control = alloca(CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * n_fds)); ++ + if (n_fds > 0) { +- msghdr.msg_control = &control; ++ msghdr.msg_control = control; + msghdr.msg_controllen = CMSG_LEN(sizeof(int) * n_fds); + + cmsg = CMSG_FIRSTHDR(&msghdr); +@@ -418,7 +416,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char + try_without_ucred = true; + controllen_without_ucred = msghdr.msg_controllen; + +- msghdr.msg_control = &control; ++ msghdr.msg_control = control; + msghdr.msg_controllen += CMSG_LEN(sizeof(struct ucred)); + + if (cmsg) diff --git a/SOURCES/0041-tmpfiles-quietly-ignore-ACLs-on-unsupported-filesyst.patch b/SOURCES/0041-tmpfiles-quietly-ignore-ACLs-on-unsupported-filesyst.patch new file mode 100644 index 00000000..a360030a --- /dev/null +++ b/SOURCES/0041-tmpfiles-quietly-ignore-ACLs-on-unsupported-filesyst.patch @@ -0,0 +1,80 @@ +From 6ad61c838992d17f5faa94faa8f17967083a4226 Mon Sep 17 00:00:00 2001 +From: Hans-Peter Deifel +Date: Tue, 3 Mar 2015 00:35:08 +0100 +Subject: [PATCH] tmpfiles: quietly ignore ACLs on unsupported filesystems + +A warning is printed if ACLs cannot be retrieved for any reason other +than -ENOSYS. For -ENOSYS, debug log is printed. + +(cherry picked from commit d873e8778c92014c02a9122852758b436fa95c0e) +--- + src/tmpfiles/tmpfiles.c | 36 ++++++++++++++++++++---------------- + 1 file changed, 20 insertions(+), 16 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 88ba7e46a..187997e1f 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -704,6 +704,9 @@ static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modif + int r; + _cleanup_(acl_free_charpp) char *t = NULL; + ++ /* Returns 0 for success, positive error if already warned, ++ * negative error otherwise. */ ++ + if (modify) { + r = acls_for_file(path, type, acl, &dup); + if (r < 0) +@@ -731,35 +734,36 @@ static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modif + + r = acl_set_file(path, type, dup); + if (r < 0) +- return log_error_errno(-errno, +- "Setting %s ACL \"%s\" on %s failed: %m", +- type == ACL_TYPE_ACCESS ? "access" : "default", +- strna(t), path); ++ return -log_error_errno(errno, ++ "Setting %s ACL \"%s\" on %s failed: %m", ++ type == ACL_TYPE_ACCESS ? "access" : "default", ++ strna(t), path); ++ + return 0; + } + #endif + + static int path_set_acls(Item *item, const char *path) { ++ int r = 0; + #ifdef HAVE_ACL +- int r; +- + assert(item); + assert(path); + +- if (item->acl_access) { ++ if (item->acl_access) + r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force); +- if (r < 0) +- return r; +- } + +- if (item->acl_default) { ++ if (r == 0 && item->acl_default) + r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force); +- if (r < 0) +- return r; +- } +-#endif + +- return 0; ++ if (r > 0) ++ return -r; /* already warned */ ++ else if (r == -ENOTSUP) { ++ log_debug_errno(r, "ACLs not supported by file system at %s", path); ++ return 0; ++ } else if (r < 0) ++ log_error_errno(r, "ACL operation on \"%s\" failed: %m", path); ++#endif ++ return r; + } + + static int write_one_file(Item *i, const char *path) { diff --git a/SOURCES/0042-shared-util-assume-ac-when-sys-class-power_supply-is.patch b/SOURCES/0042-shared-util-assume-ac-when-sys-class-power_supply-is.patch new file mode 100644 index 00000000..6489de52 --- /dev/null +++ b/SOURCES/0042-shared-util-assume-ac-when-sys-class-power_supply-is.patch @@ -0,0 +1,27 @@ +From a2911c593e9d69a2aa01d89d876e313f90e7db17 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 3 Mar 2015 19:07:28 -0500 +Subject: [PATCH] shared/util: assume ac when /sys/class/power_supply is + missing + +On s390 (at least) /sys/class/power_supply is not present. We should +treat this like if this directory was empty, and not an error. + +(cherry picked from commit 6d89003462484c8656b698e07b9cf0a337e3818e) +--- + src/shared/util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index f24b5b4ec..85487230a 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -5994,7 +5994,7 @@ int on_ac_power(void) { + + d = opendir("/sys/class/power_supply"); + if (!d) +- return -errno; ++ return errno == ENOENT ? true : -errno; + + for (;;) { + struct dirent *de; diff --git a/SOURCES/0043-import-remove-unused-variable.patch b/SOURCES/0043-import-remove-unused-variable.patch new file mode 100644 index 00000000..2f53c5d8 --- /dev/null +++ b/SOURCES/0043-import-remove-unused-variable.patch @@ -0,0 +1,22 @@ +From 2bbdb63f7e5f125e1259b0fcfcea8226c5ae4e58 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 17 Feb 2015 20:06:13 +0100 +Subject: [PATCH] import: remove unused variable + +(cherry picked from commit b89c454b37a23433f8fd6ad7b93f5a6190930aa4) +--- + src/import/import-tar.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/import/import-tar.c b/src/import/import-tar.c +index 999aa8ab5..493252a13 100644 +--- a/src/import/import-tar.c ++++ b/src/import/import-tar.c +@@ -301,7 +301,6 @@ finish: + } + + static int tar_import_job_on_open_disk(ImportJob *j) { +- _cleanup_close_pair_ int pipefd[2] = { -1 , -1 }; + TarImport *i; + int r; + diff --git a/SOURCES/0044-hwdb-fix-ThinkPad-X-Tablet-special-keys.patch b/SOURCES/0044-hwdb-fix-ThinkPad-X-Tablet-special-keys.patch new file mode 100644 index 00000000..ca351d09 --- /dev/null +++ b/SOURCES/0044-hwdb-fix-ThinkPad-X-Tablet-special-keys.patch @@ -0,0 +1,44 @@ +From 61d5dff976f33ec7189eae58641c49088e166479 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Wed, 18 Feb 2015 21:02:01 +0100 +Subject: [PATCH] hwdb: fix ThinkPad X* Tablet special keys + +ThinkPad tablet firmware has DMI product name and version reversed: + +Handle 0x0001, DMI type 1, 27 bytes +System Information + Manufacturer: LENOVO + Product Name: 7762AS1 + Version: ThinkPad X61 Tablet + Serial Number: LKZCDH2 + UUID: 6ADBC681-4FC9-11CB-844F-B47CB9210BE2 + Wake-up Type: Power Switch + SKU Number: Not Specified + Family: ThinkPad X61 Tablet + +(cherry picked from commit 39addb81b660dd7af7d21be941d8de6497abbdbf) +--- + hwdb/60-keyboard.hwdb | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb +index 1b7d87101..2cb976923 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -586,7 +586,6 @@ keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:pvr* + KEYBOARD_KEY_f3=f21 + + # Thinkpad X200_Tablet +-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnThinkPad*X2*Tablet*:pvr* + keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet* + KEYBOARD_KEY_5d=menu + KEYBOARD_KEY_63=fn +@@ -596,7 +595,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet* + KEYBOARD_KEY_6c=direction # rotate screen + + # ThinkPad X6 Tablet +-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnThinkPad*X6*:pvr* ++keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet* + KEYBOARD_KEY_6c=direction # rotate + KEYBOARD_KEY_68=leftmeta # toolbox + KEYBOARD_KEY_6b=esc # escape diff --git a/SOURCES/0045-man-add-newlines-to-the-pull-raw-example-in-machinec.patch b/SOURCES/0045-man-add-newlines-to-the-pull-raw-example-in-machinec.patch new file mode 100644 index 00000000..ffc4ab69 --- /dev/null +++ b/SOURCES/0045-man-add-newlines-to-the-pull-raw-example-in-machinec.patch @@ -0,0 +1,34 @@ +From e411ef694a09d001cdb97e139af6884b01be4aba Mon Sep 17 00:00:00 2001 +From: Benjamin Franzke +Date: Thu, 19 Feb 2015 13:10:18 +0100 +Subject: [PATCH] man: add newlines to the pull-raw example in machinectl(1) + +They were removed in commit 798d3a52 ("Reindent man pages to 2ch"). + +(cherry picked from commit ac92ced5bb41def1d90f871d6c8cfec2b03c0c7d) +--- + man/machinectl.xml | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/man/machinectl.xml b/man/machinectl.xml +index 9b07af422..640cb8b7d 100644 +--- a/man/machinectl.xml ++++ b/man/machinectl.xml +@@ -715,11 +715,12 @@ + Download a Fedora image, set a root password in it, start + it as service + +- # machinectl pull-raw --verify=no +- http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz +- # systemd-nspawn -M Fedora-Cloud-Base-20141203-21 # passwd # +- exit # machinectl start Fedora-Cloud-Base-20141203-21 # +- machinectl login Fedora-Cloud-Base-20141203-21 ++ # machinectl pull-raw --verify=no http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz ++# systemd-nspawn -M Fedora-Cloud-Base-20141203-21 ++# passwd ++# exit ++# machinectl start Fedora-Cloud-Base-20141203-21 ++# machinectl login Fedora-Cloud-Base-20141203-21 + + This downloads the specified .raw + image with verification disabled. Then a shell is opened in it diff --git a/SOURCES/0046-core-shared-in-deserializing-match-same-files-reache.patch b/SOURCES/0046-core-shared-in-deserializing-match-same-files-reache.patch new file mode 100644 index 00000000..80be3a99 --- /dev/null +++ b/SOURCES/0046-core-shared-in-deserializing-match-same-files-reache.patch @@ -0,0 +1,133 @@ +From 5d66d4942090a971de8df2c3de9ce143a208eb37 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Thu, 19 Feb 2015 23:12:38 +0100 +Subject: [PATCH] core, shared: in deserializing, match same files reached via + different paths + +When dbus.socket is updated like this: +-ListenStream=/var/run/dbus/system_bus_socket ++ListenStream=/run/dbus/system_bus_socket +... and daemon-reload is performed, bad things happen. +During deserialization systemd does not recognize that the two paths +refer to the same named socket and replaces the socket file with a new +one. As a result, applications hang when they try talking to dbus. + +Fix this by finding a match not only when the path names are equal, but +also when they point to the same inode. +In socket_address_equal() it is necessary to move the address size +comparison into the abstract sockets branch. For path name sockets the +comparison must not be done and for other families it is redundant +(their sizes are constant and checked by socket_address_verify()). + +FIFOs and special files can also have multiple pathnames, so compare the +inodes for them as well. Note that previously the pathname checks used +streq_ptr(), but the paths cannot be NULL. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1186018 +(cherry picked from commit c78e47a61fa8d9a21fece01c83e4c26ce0938d27) +--- + src/core/socket.c | 6 +++--- + src/shared/path-util.c | 4 ++++ + src/shared/path-util.h | 1 + + src/shared/socket-util.c | 10 ++++------ + 4 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/src/core/socket.c b/src/core/socket.c +index 48c43a288..88aae4815 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -2100,7 +2100,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, + + LIST_FOREACH(port, p, s->ports) + if (p->type == SOCKET_FIFO && +- streq_ptr(p->path, value+skip)) ++ path_equal_or_files_same(p->path, value+skip)) + break; + + if (p) { +@@ -2119,7 +2119,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, + + LIST_FOREACH(port, p, s->ports) + if (p->type == SOCKET_SPECIAL && +- streq_ptr(p->path, value+skip)) ++ path_equal_or_files_same(p->path, value+skip)) + break; + + if (p) { +@@ -2138,7 +2138,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, + + LIST_FOREACH(port, p, s->ports) + if (p->type == SOCKET_MQUEUE && +- streq_ptr(p->path, value+skip)) ++ streq(p->path, value+skip)) + break; + + if (p) { +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index b9db7f104..70bc1caa2 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -436,6 +436,10 @@ bool path_equal(const char *a, const char *b) { + } + } + ++bool path_equal_or_files_same(const char *a, const char *b) { ++ return path_equal(a, b) || files_same(a, b) > 0; ++} ++ + char* path_join(const char *root, const char *path, const char *rest) { + assert(path); + +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index bd0d32473..bcf116ed3 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -45,6 +45,7 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r); + char* path_kill_slashes(char *path); + char* path_startswith(const char *path, const char *prefix) _pure_; + bool path_equal(const char *a, const char *b) _pure_; ++bool path_equal_or_files_same(const char *a, const char *b); + char* path_join(const char *root, const char *path, const char *rest); + + char** path_strv_make_absolute_cwd(char **l); +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index c6f64876b..c278d6f9d 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -325,9 +325,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { + if (a->type != b->type) + return false; + +- if (a->size != b->size) +- return false; +- + if (socket_address_family(a) != socket_address_family(b)) + return false; + +@@ -352,14 +349,16 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { + break; + + case AF_UNIX: +- + if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0)) + return false; + + if (a->sockaddr.un.sun_path[0]) { +- if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path))) ++ if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path)) + return false; + } else { ++ if (a->size != b->size) ++ return false; ++ + if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0) + return false; + } +@@ -367,7 +366,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { + break; + + case AF_NETLINK: +- + if (a->protocol != b->protocol) + return false; + diff --git a/SOURCES/0047-shared-use-SocketAddress-in-socket_address_matches_f.patch b/SOURCES/0047-shared-use-SocketAddress-in-socket_address_matches_f.patch new file mode 100644 index 00000000..8fd388df --- /dev/null +++ b/SOURCES/0047-shared-use-SocketAddress-in-socket_address_matches_f.patch @@ -0,0 +1,83 @@ +From 73cbcbaf7e04d42816ada8ee44b5fbc6b7f0bdb4 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Fri, 20 Feb 2015 02:04:05 +0100 +Subject: [PATCH] shared: use SocketAddress in socket_address_matches_fd() + +Cleanup. No behavior change. + +(cherry picked from commit dbafedacba3ee77098e932222ae7840e7b4040fc) +--- + src/shared/socket-util.c | 36 ++++++++++++++++++------------------ + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index c278d6f9d..c31f60ec7 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -435,48 +435,48 @@ bool socket_ipv6_is_supported(void) { + } + + bool socket_address_matches_fd(const SocketAddress *a, int fd) { +- union sockaddr_union sa; +- socklen_t salen = sizeof(sa), solen; +- int protocol, type; ++ SocketAddress b; ++ socklen_t solen; + + assert(a); + assert(fd >= 0); + +- if (getsockname(fd, &sa.sa, &salen) < 0) ++ b.size = sizeof(b.sockaddr); ++ if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0) + return false; + +- if (sa.sa.sa_family != a->sockaddr.sa.sa_family) ++ if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family) + return false; + +- solen = sizeof(type); +- if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0) ++ solen = sizeof(b.type); ++ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0) + return false; + +- if (type != a->type) ++ if (b.type != a->type) + return false; + + if (a->protocol != 0) { +- solen = sizeof(protocol); +- if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0) ++ solen = sizeof(b.protocol); ++ if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0) + return false; + +- if (protocol != a->protocol) ++ if (b.protocol != a->protocol) + return false; + } + +- switch (sa.sa.sa_family) { ++ switch (b.sockaddr.sa.sa_family) { + + case AF_INET: +- return sa.in.sin_port == a->sockaddr.in.sin_port && +- sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr; ++ return b.sockaddr.in.sin_port == a->sockaddr.in.sin_port && ++ b.sockaddr.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr; + + case AF_INET6: +- return sa.in6.sin6_port == a->sockaddr.in6.sin6_port && +- memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0; ++ return b.sockaddr.in6.sin6_port == a->sockaddr.in6.sin6_port && ++ memcmp(&b.sockaddr.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0; + + case AF_UNIX: +- return salen == a->size && +- memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0; ++ return b.sockaddr.size == a->size && ++ memcmp(b.sockaddr.un.sun_path, a->sockaddr.un.sun_path, b.size - offsetof(struct sockaddr_un, sun_path)) == 0; + + } + diff --git a/SOURCES/0048-shared-avoid-semi-duplicating-socket_address_equal.patch b/SOURCES/0048-shared-avoid-semi-duplicating-socket_address_equal.patch new file mode 100644 index 00000000..7bda801f --- /dev/null +++ b/SOURCES/0048-shared-avoid-semi-duplicating-socket_address_equal.patch @@ -0,0 +1,42 @@ +From ea81ddfdc0eadfb62e28ed998d33c5e1d3b3abab Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Fri, 20 Feb 2015 02:13:03 +0100 +Subject: [PATCH] shared: avoid semi-duplicating socket_address_equal() + +Just call socket_address_equal() from socket_address_matches_fd() +instead of implementing similar comparing of addresses. + +(cherry picked from commit 02233928a502e46fc125118dba7234ba3e48dc15) +--- + src/shared/socket-util.c | 18 +----------------- + 1 file changed, 1 insertion(+), 17 deletions(-) + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index c31f60ec7..deecce8a8 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -464,23 +464,7 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { + return false; + } + +- switch (b.sockaddr.sa.sa_family) { +- +- case AF_INET: +- return b.sockaddr.in.sin_port == a->sockaddr.in.sin_port && +- b.sockaddr.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr; +- +- case AF_INET6: +- return b.sockaddr.in6.sin6_port == a->sockaddr.in6.sin6_port && +- memcmp(&b.sockaddr.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0; +- +- case AF_UNIX: +- return b.sockaddr.size == a->size && +- memcmp(b.sockaddr.un.sun_path, a->sockaddr.un.sun_path, b.size - offsetof(struct sockaddr_un, sun_path)) == 0; +- +- } +- +- return false; ++ return socket_address_equal(a, &b); + } + + int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) { diff --git a/SOURCES/0049-shared-handle-unnamed-sockets-in-socket_address_equa.patch b/SOURCES/0049-shared-handle-unnamed-sockets-in-socket_address_equa.patch new file mode 100644 index 00000000..052866bd --- /dev/null +++ b/SOURCES/0049-shared-handle-unnamed-sockets-in-socket_address_equa.patch @@ -0,0 +1,29 @@ +From 394185c013c15e47ffa1bdc5948ac6010c329728 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Fri, 20 Feb 2015 02:25:16 +0100 +Subject: [PATCH] shared: handle unnamed sockets in socket_address_equal() + +Make sure we don't inspect sun_path of unnamed sockets. +Since we cannot know if two unnamed sockets' adresses refer to the same +socket, just return false. + +(cherry picked from commit 710708a54ccc48e168ad7d4cd401645ef9e2eb14) +--- + src/shared/socket-util.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index deecce8a8..a4e26b1d8 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -349,6 +349,10 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { + break; + + case AF_UNIX: ++ if (a->size <= offsetof(struct sockaddr_un, sun_path) || ++ b->size <= offsetof(struct sockaddr_un, sun_path)) ++ return false; ++ + if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0)) + return false; + diff --git a/SOURCES/0050-man-make-bootup-graph-consistent.patch b/SOURCES/0050-man-make-bootup-graph-consistent.patch new file mode 100644 index 00000000..35d03cd9 --- /dev/null +++ b/SOURCES/0050-man-make-bootup-graph-consistent.patch @@ -0,0 +1,23 @@ +From d65ce525915a604d31cda80b5d7a8d639fb5cbb9 Mon Sep 17 00:00:00 2001 +From: Chris Morin +Date: Wed, 4 Feb 2015 14:54:34 -0500 +Subject: [PATCH] man: make bootup graph consistent + +(cherry picked from commit b44787bd437f4051660272b37bd6f75392f17931) +--- + man/bootup.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/bootup.xml b/man/bootup.xml +index d97d55023..b92057af2 100644 +--- a/man/bootup.xml ++++ b/man/bootup.xml +@@ -134,7 +134,7 @@ + v v | v rescue.target + timers.target paths.target | sockets.target + | | | | +- v |_________________ | ___________________/ ++ v \_________________ | ___________________/ + \|/ + v + basic.target diff --git a/SOURCES/0051-nspawn-fix-whitespace-and-typo-in-partition-table-bl.patch b/SOURCES/0051-nspawn-fix-whitespace-and-typo-in-partition-table-bl.patch new file mode 100644 index 00000000..b38325fc --- /dev/null +++ b/SOURCES/0051-nspawn-fix-whitespace-and-typo-in-partition-table-bl.patch @@ -0,0 +1,23 @@ +From 3af8c723aebecb5d220fdb5b1fb80a097c366db1 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 23 Feb 2015 15:22:40 +0100 +Subject: [PATCH] nspawn: fix whitespace and typo in partition table blurb + +(cherry picked from commit 4aab5d0cbd979b2cccb88534f118bceaa86466d8) +--- + src/nspawn/nspawn.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index fb672510b..7724df96b 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -2676,7 +2676,7 @@ static int setup_image(char **device_path, int *loop_nr) { + + #define PARTITION_TABLE_BLURB \ + "Note that the disk image needs to either contain only a single MBR partition of\n" \ +- "type 0x83 that is marked bootable, or a sinlge GPT partition of type" \ ++ "type 0x83 that is marked bootable, or a single GPT partition of type " \ + "0FC63DAF-8483-4772-8E79-3D69D8477DE4 or follow\n" \ + " http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" \ + "to be bootable with systemd-nspawn." diff --git a/SOURCES/0052-man-explain-time-units-in-tmpfiles.patch b/SOURCES/0052-man-explain-time-units-in-tmpfiles.patch new file mode 100644 index 00000000..84321a73 --- /dev/null +++ b/SOURCES/0052-man-explain-time-units-in-tmpfiles.patch @@ -0,0 +1,53 @@ +From 6995221c988db99faa5de5ed948466e1982d9d9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 23 Feb 2015 18:59:17 -0500 +Subject: [PATCH] man: explain time units in tmpfiles + +https://bugzilla.redhat.com/show_bug.cgi?id=1195294 +(cherry picked from commit 00c53f4283ca41878a84b370840a84760b00d46e) +--- + man/tmpfiles.d.xml | 29 ++++++++++++++--------------- + 1 file changed, 14 insertions(+), 15 deletions(-) + +diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml +index 8815bf997..4bd0fcf75 100644 +--- a/man/tmpfiles.d.xml ++++ b/man/tmpfiles.d.xml +@@ -443,23 +443,22 @@ + delete when cleaning. If a file or directory is older than the + current time minus the age field, it is deleted. The field + format is a series of integers each followed by one of the +- following postfixes for the respective time units: +- +- +- +- s +- min +- h +- d +- w +- ms +- m +- us +- ++ following postfixes for the respective time units: ++ s, ++ m or min, ++ h, ++ d, ++ w, ++ ms, ++ us, ++ respectively meaning seconds, minutes, hours, days, weeks, ++ milliseconds, and microseconds. Full names of the time units can ++ be used too. ++ + + If multiple integers and units are specified, the time +- values are summed up. If an integer is given without a unit, +- s is assumed. ++ values are summed. If an integer is given without a unit, ++ s is assumed. + + + When the age is set to zero, the files are cleaned diff --git a/SOURCES/0053-systemctl-check-validity-of-PID-we-received.patch b/SOURCES/0053-systemctl-check-validity-of-PID-we-received.patch new file mode 100644 index 00000000..be25640f --- /dev/null +++ b/SOURCES/0053-systemctl-check-validity-of-PID-we-received.patch @@ -0,0 +1,33 @@ +From 3b573e5c39f452f98084b3d36486369882455b72 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 7 Feb 2015 11:16:04 -0500 +Subject: [PATCH] systemctl: check validity of PID we received + +(cherry picked from commit d028e01814a405e83c400c60545785d35dba2a17) +--- + src/systemctl/systemctl.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 6b93ec844..3da4d3d4f 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -2881,6 +2881,9 @@ static int check_inhibitors(sd_bus *bus, enum action a) { + if (!sv) + return log_oom(); + ++ if ((pid_t) pid < 0) ++ return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid); ++ + if (!strv_contains(sv, + a == ACTION_HALT || + a == ACTION_POWEROFF || +@@ -2892,7 +2895,7 @@ static int check_inhibitors(sd_bus *bus, enum action a) { + user = uid_to_name(uid); + + log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".", +- who, pid, strna(comm), strna(user), why); ++ who, (pid_t) pid, strna(comm), strna(user), why); + + c++; + } diff --git a/SOURCES/0054-systemctl-support-auditd.service-better.patch b/SOURCES/0054-systemctl-support-auditd.service-better.patch new file mode 100644 index 00000000..2f5acd4a --- /dev/null +++ b/SOURCES/0054-systemctl-support-auditd.service-better.patch @@ -0,0 +1,85 @@ +From 98d1fe84e1eac91563bff326539465cd34e971c0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 7 Feb 2015 11:35:37 -0500 +Subject: [PATCH] systemctl: support auditd.service better + +We would print the filename header before trying to open the file. But since +the header was printed to stdout, and the error to stderr, the error would appear +on the terminal before the header. It is cleaner to open the file first, then +and only then print the header. + +Also exit on first error. We shouldn't report success if we were unable to open +a file. + +(cherry picked from commit 8527b07be1c5211b50a1a6496585952857a25c73) +--- + src/systemctl/systemctl.c | 46 +++++++++++++++++++++++----------------------- + 1 file changed, 23 insertions(+), 23 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 3da4d3d4f..4ec0cff21 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4555,6 +4555,23 @@ static int init_home_and_lookup_paths(char **user_home, char **user_runtime, Loo + return 0; + } + ++static int cat_file(const char *filename, bool newline) { ++ _cleanup_close_ int fd; ++ ++ fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY); ++ if (fd < 0) ++ return -errno; ++ ++ printf("%s%s# %s%s\n", ++ newline ? "\n" : "", ++ ansi_highlight_blue(), ++ filename, ++ ansi_highlight_off()); ++ fflush(stdout); ++ ++ return copy_bytes(fd, STDOUT_FILENO, (off_t) -1, false); ++} ++ + static int cat(sd_bus *bus, char **args) { + _cleanup_free_ char *user_home = NULL; + _cleanup_free_ char *user_runtime = NULL; +@@ -4600,32 +4617,15 @@ static int cat(sd_bus *bus, char **args) { + puts(""); + + if (fragment_path) { +- printf("%s# %s%s\n", +- ansi_highlight_blue(), +- fragment_path, +- ansi_highlight_off()); +- fflush(stdout); +- +- r = copy_file_fd(fragment_path, STDOUT_FILENO, false); +- if (r < 0) { +- log_warning_errno(r, "Failed to cat %s: %m", fragment_path); +- continue; +- } ++ r = cat_file(fragment_path, false); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to cat %s: %m", fragment_path); + } + + STRV_FOREACH(path, dropin_paths) { +- printf("%s%s# %s%s\n", +- isempty(fragment_path) && path == dropin_paths ? "" : "\n", +- ansi_highlight_blue(), +- *path, +- ansi_highlight_off()); +- fflush(stdout); +- +- r = copy_file_fd(*path, STDOUT_FILENO, false); +- if (r < 0) { +- log_warning_errno(r, "Failed to cat %s: %m", *path); +- continue; +- } ++ r = cat_file(*path, path == dropin_paths); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to cat %s: %m", *path); + } + } + diff --git a/SOURCES/0055-shared-unit-name-fix-gcc5-warning.patch b/SOURCES/0055-shared-unit-name-fix-gcc5-warning.patch new file mode 100644 index 00000000..6a35a44b --- /dev/null +++ b/SOURCES/0055-shared-unit-name-fix-gcc5-warning.patch @@ -0,0 +1,31 @@ +From 10cfa6f617fdc2b9d85823163b4445f5ae9058c5 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 24 Feb 2015 16:18:43 +0100 +Subject: [PATCH] shared/unit-name: fix gcc5 warning + +Fix the following gcc5 warning: + + CC src/shared/libsystemd_shared_la-unit-name.lo +src/shared/unit-name.c: In function 'unit_name_is_valid': +src/shared/unit-name.c:102:34: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] + if (!template_ok == TEMPLATE_VALID && at+1 == e) + ^ + +(cherry picked from commit f9bf3e260c480f7b660bec3f78a13f52a46ec34d) +--- + src/shared/unit-name.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c +index 21b66913c..f728af4a8 100644 +--- a/src/shared/unit-name.c ++++ b/src/shared/unit-name.c +@@ -100,7 +100,7 @@ bool unit_name_is_valid(const char *n, enum template_valid template_ok) { + if (at == n) + return false; + +- if (!template_ok == TEMPLATE_VALID && at+1 == e) ++ if (template_ok != TEMPLATE_VALID && at+1 == e) + return false; + } + diff --git a/SOURCES/0056-test-hashmap-fix-gcc5-warning.patch b/SOURCES/0056-test-hashmap-fix-gcc5-warning.patch new file mode 100644 index 00000000..8790fa03 --- /dev/null +++ b/SOURCES/0056-test-hashmap-fix-gcc5-warning.patch @@ -0,0 +1,32 @@ +From a4409b8ae6b80acffc9a4f89df2d06c498b8c8f9 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 24 Feb 2015 16:24:14 +0100 +Subject: [PATCH] test-hashmap: fix gcc5 warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +gcc5 spits out a warning about test-hashmap.c: + + CC src/test/test-hashmap.o +src/test/test-hashmap.c: In function ‘test_string_compare_func’: +src/test/test-hashmap.c:76:79: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] + +(cherry picked from commit 4b3eff61640672bf0b19cb8cdd88ce5e84dcda1c) +--- + src/test/test-hashmap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c +index 6900da9e8..351563b96 100644 +--- a/src/test/test-hashmap.c ++++ b/src/test/test-hashmap.c +@@ -75,7 +75,7 @@ static void test_trivial_compare_func(void) { + } + + static void test_string_compare_func(void) { +- assert_se(!string_compare_func("fred", "wilma") == 0); ++ assert_se(string_compare_func("fred", "wilma") != 0); + assert_se(string_compare_func("fred", "fred") == 0); + } + diff --git a/SOURCES/0057-shared-fix-wrong-assertion-in-barrier_set_role.patch b/SOURCES/0057-shared-fix-wrong-assertion-in-barrier_set_role.patch new file mode 100644 index 00000000..bb838a95 --- /dev/null +++ b/SOURCES/0057-shared-fix-wrong-assertion-in-barrier_set_role.patch @@ -0,0 +1,29 @@ +From 5acd5e264d53cf293ac5d2e57371690120fb7119 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Fri, 20 Feb 2015 15:14:56 -0300 +Subject: [PATCH] shared: fix wrong assertion in barrier_set_role() + + assert(b->pipe[0] >= 0 && b->pipe[0] >= 0); + +Test the same condition twice, pretty sure we mean + + assert(b->pipe[0] >= 0 && b->pipe[1] >= 0); + +(cherry picked from commit 3f7f1fad7621f584d9ce024abb313ecbc9bd0e62) +--- + src/shared/barrier.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/barrier.c b/src/shared/barrier.c +index f65363a67..b7dca7509 100644 +--- a/src/shared/barrier.c ++++ b/src/shared/barrier.c +@@ -178,7 +178,7 @@ void barrier_set_role(Barrier *b, unsigned int role) { + assert(b); + assert(role == BARRIER_PARENT || role == BARRIER_CHILD); + /* make sure this is only called once */ +- assert(b->pipe[1] >= 0 && b->pipe[1] >= 0); ++ assert(b->pipe[0] >= 0 && b->pipe[1] >= 0); + + if (role == BARRIER_PARENT) + b->pipe[1] = safe_close(b->pipe[1]); diff --git a/SOURCES/0058-hwdb-Update-database-of-Bluetooth-company-identifier.patch b/SOURCES/0058-hwdb-Update-database-of-Bluetooth-company-identifier.patch new file mode 100644 index 00000000..0b70a55c --- /dev/null +++ b/SOURCES/0058-hwdb-Update-database-of-Bluetooth-company-identifier.patch @@ -0,0 +1,60 @@ +From 7958951ba84f870c624b4d2ab452b12c844bde20 Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Wed, 25 Feb 2015 07:27:49 +0100 +Subject: [PATCH] hwdb: Update database of Bluetooth company identifiers + +(cherry picked from commit 3cabeab1197d3e45f16f514f5a396e0fb311e867) +--- + hwdb/20-bluetooth-vendor-product.hwdb | 42 +++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb +index fb789fd49..4fd951a58 100644 +--- a/hwdb/20-bluetooth-vendor-product.hwdb ++++ b/hwdb/20-bluetooth-vendor-product.hwdb +@@ -1430,3 +1430,45 @@ bluetooth:v01D9* + + bluetooth:v01DA* + ID_VENDOR_FROM_DATABASE=Logitech International SA ++ ++bluetooth:v01DB* ++ ID_VENDOR_FROM_DATABASE=Innblue Consulting ++ ++bluetooth:v01DC* ++ ID_VENDOR_FROM_DATABASE=iParking Ltd. ++ ++bluetooth:v01DD* ++ ID_VENDOR_FROM_DATABASE=Koninklijke Philips Electronics N.V. ++ ++bluetooth:v01DE* ++ ID_VENDOR_FROM_DATABASE=Minelab Electronics Pty Limited ++ ++bluetooth:v01DF* ++ ID_VENDOR_FROM_DATABASE=Bison Group Ltd. ++ ++bluetooth:v01E0* ++ ID_VENDOR_FROM_DATABASE=Widex A/S ++ ++bluetooth:v01E1* ++ ID_VENDOR_FROM_DATABASE=Jolla Ltd ++ ++bluetooth:v01E2* ++ ID_VENDOR_FROM_DATABASE=Lectronix, Inc. ++ ++bluetooth:v01E3* ++ ID_VENDOR_FROM_DATABASE=Caterpillar Inc ++ ++bluetooth:v01E4* ++ ID_VENDOR_FROM_DATABASE=Freedom Innovations ++ ++bluetooth:v01E5* ++ ID_VENDOR_FROM_DATABASE=Dynamic Devices Ltd ++ ++bluetooth:v01E6* ++ ID_VENDOR_FROM_DATABASE=Technology Solutions (UK) Ltd ++ ++bluetooth:v01E7* ++ ID_VENDOR_FROM_DATABASE=IPS Group Inc. ++ ++bluetooth:v01E8* ++ ID_VENDOR_FROM_DATABASE=STIR diff --git a/SOURCES/0059-journal-make-skipping-of-exhausted-journal-files-eff.patch b/SOURCES/0059-journal-make-skipping-of-exhausted-journal-files-eff.patch new file mode 100644 index 00000000..7b188fa5 --- /dev/null +++ b/SOURCES/0059-journal-make-skipping-of-exhausted-journal-files-eff.patch @@ -0,0 +1,114 @@ +From 0ad01db952718d3437fa8f077a065d17efe5279b Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Tue, 24 Feb 2015 19:45:17 +0100 +Subject: [PATCH] journal: make skipping of exhausted journal files effective + again + +Commit 668c965af "journal: skipping of exhausted journal files is bad if +direction changed" fixed a correctness issue, but it also significantly +limited the cases where the optimization that skips exhausted journal +files could apply. +As a result, some journalctl queries are much slower in v219 than in v218. +(e.g. queries where a "--since" cutoff should have quickly eliminated +older journal files from consideration, but didn't.) + +If already in the initial iteration find_location_with_matches() finds +no entry, the journal file's location is not updated. This is fine, +except that: + - We must update at least f->last_direction. The optimization relies on + it. Let's separate that from journal_file_save_location() and update + it immediately after the direction checks. + - The optimization was conditional on "f->current_offset > 0", but it + would always be 0 in this scenario. This check is unnecessary for the + optimization. + +(cherry picked from commit 950c07d421c04e5aae99973479f4f13131fb45e1) +--- + src/journal/journal-file.c | 3 +-- + src/journal/journal-file.h | 2 +- + src/journal/sd-journal.c | 24 +++++++++++++++--------- + 3 files changed, 17 insertions(+), 12 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 0f28718b0..24c49b916 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -2014,8 +2014,7 @@ void journal_file_reset_location(JournalFile *f) { + f->current_xor_hash = 0; + } + +-void journal_file_save_location(JournalFile *f, direction_t direction, Object *o, uint64_t offset) { +- f->last_direction = direction; ++void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset) { + f->location_type = LOCATION_SEEK; + f->current_offset = offset; + f->current_seqnum = le64toh(o->entry.seqnum); +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index 2526e14d6..403c8f760 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -199,7 +199,7 @@ int journal_file_find_field_object(JournalFile *f, const void *field, uint64_t s + int journal_file_find_field_object_with_hash(JournalFile *f, const void *field, uint64_t size, uint64_t hash, Object **ret, uint64_t *offset); + + void journal_file_reset_location(JournalFile *f); +-void journal_file_save_location(JournalFile *f, direction_t direction, Object *o, uint64_t offset); ++void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset); + int journal_file_compare_locations(JournalFile *af, JournalFile *bf); + int journal_file_next_entry(JournalFile *f, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 94891cdf3..9b57e5945 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -723,13 +723,17 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc + assert(j); + assert(f); + +- if (f->last_direction == direction && f->current_offset > 0) { +- /* If we hit EOF before, recheck if any new entries arrived. */ +- n_entries = le64toh(f->header->n_entries); +- if (f->location_type == LOCATION_TAIL && n_entries == f->last_n_entries) +- return 0; +- f->last_n_entries = n_entries; ++ n_entries = le64toh(f->header->n_entries); ++ ++ /* If we hit EOF before, we don't need to look into this file again ++ * unless direction changed or new entries appeared. */ ++ if (f->last_direction == direction && f->location_type == LOCATION_TAIL && ++ n_entries == f->last_n_entries) ++ return 0; + ++ f->last_n_entries = n_entries; ++ ++ if (f->last_direction == direction && f->current_offset > 0) { + /* LOCATION_SEEK here means we did the work in a previous + * iteration and the current location already points to a + * candidate entry. */ +@@ -738,14 +742,16 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc + if (r <= 0) + return r; + +- journal_file_save_location(f, direction, c, cp); ++ journal_file_save_location(f, c, cp); + } + } else { ++ f->last_direction = direction; ++ + r = find_location_with_matches(j, f, direction, &c, &cp); + if (r <= 0) + return r; + +- journal_file_save_location(f, direction, c, cp); ++ journal_file_save_location(f, c, cp); + } + + /* OK, we found the spot, now let's advance until an entry +@@ -773,7 +779,7 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc + if (r <= 0) + return r; + +- journal_file_save_location(f, direction, c, cp); ++ journal_file_save_location(f, c, cp); + } + } + diff --git a/SOURCES/0060-shared-condition-fix-gcc5-warning.patch b/SOURCES/0060-shared-condition-fix-gcc5-warning.patch new file mode 100644 index 00000000..741690bd --- /dev/null +++ b/SOURCES/0060-shared-condition-fix-gcc5-warning.patch @@ -0,0 +1,42 @@ +From 2ee0903b0a00dd4a13af8a26ee5fb435c9895568 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 27 Feb 2015 20:05:26 +0100 +Subject: [PATCH] shared/condition: fix gcc5 warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes the warning below. + +src/shared/condition.c: In function ‘condition_new’: +src/shared/condition.c:47:27: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] + assert(!parameter == (type == CONDITION_NULL)); + ^ +src/shared/macro.h:42:44: note: in definition of macro ‘_unlikely_’ + #define _unlikely_(x) (__builtin_expect(!!(x),0)) + ^ +src/shared/macro.h:226:22: note: in expansion of macro ‘assert_se’ + #define assert(expr) assert_se(expr) + ^ +src/shared/condition.c:47:9: note: in expansion of macro ‘assert’ + assert(!parameter == (type == CONDITION_NULL)); + ^ + +(cherry picked from commit 8a9c6071cb7467170010f0287672c987981bdf9c) +--- + src/shared/condition.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/condition.c b/src/shared/condition.c +index da7560f05..796cc520d 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -46,7 +46,7 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger + + assert(type >= 0); + assert(type < _CONDITION_TYPE_MAX); +- assert(!parameter == (type == CONDITION_NULL)); ++ assert((!parameter) == (type == CONDITION_NULL)); + + c = new0(Condition, 1); + if (!c) diff --git a/SOURCES/0061-man-correct-description-of-systemd-user-sessions.patch b/SOURCES/0061-man-correct-description-of-systemd-user-sessions.patch new file mode 100644 index 00000000..ccf7ab19 --- /dev/null +++ b/SOURCES/0061-man-correct-description-of-systemd-user-sessions.patch @@ -0,0 +1,34 @@ +From 3104b6659b1405d25cdb5cad68e2bb2c9f8b5980 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 27 Feb 2015 17:26:42 -0500 +Subject: [PATCH] man: correct description of systemd-user-sessions + +That part of functionality was removed in 7fb3ee51c1b377. + +(cherry picked from commit 3849a2ac8198fedd25e66fe780821fa96eb6396d) +--- + man/systemd-user-sessions.service.xml | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/man/systemd-user-sessions.service.xml b/man/systemd-user-sessions.service.xml +index 9d796b1ae..e75ef11c4 100644 +--- a/man/systemd-user-sessions.service.xml ++++ b/man/systemd-user-sessions.service.xml +@@ -55,13 +55,12 @@ + Description + + systemd-user-sessions.service is a +- service that controls user logins. After basic system +- initialization is complete it removes ++ service that controls user logins through ++ pam_nologin8. ++ After basic system initialization is complete it removes + /run/nologin, thus permitting logins. Before + system shutdown it creates /run/nologin, thus +- prohibiting further logins. At the same time it also kills all +- user processes, so that system shutdown may proceed without any +- remaining user processes around. ++ prohibiting further logins. + + + diff --git a/SOURCES/0062-build-sys-allow-lto-and-FORTIFY_SOURCE-with-O-sz.patch b/SOURCES/0062-build-sys-allow-lto-and-FORTIFY_SOURCE-with-O-sz.patch new file mode 100644 index 00000000..1e141bdc --- /dev/null +++ b/SOURCES/0062-build-sys-allow-lto-and-FORTIFY_SOURCE-with-O-sz.patch @@ -0,0 +1,31 @@ +From 21511551c7d49424a202b25ffe76cf1371dfc0c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 1 Mar 2015 22:46:43 -0500 +Subject: [PATCH] build-sys: allow lto and FORTIFY_SOURCE with -O[sz] + +https://bugs.freedesktop.org/show_bug.cgi?id=89382 +(cherry picked from commit 0289f2fb2a64df53b589b771f69c43126b029590) +--- + configure.ac | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 9c25c3c6f..3201428c4 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -208,13 +208,13 @@ AS_CASE([$CC], [*clang*], + -Wno-gnu-variable-sized-type-not-at-end \ + ])]) + +-AS_CASE([$CFLAGS], [*-O[[12345\ ]]*], ++AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], + [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ + -flto -ffat-lto-objects])], + [AC_MSG_RESULT([skipping -flto, optimization not enabled])]) + AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags") + +-AS_CASE([$CFLAGS], [*-O[[12345\ ]]*], ++AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], + [CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\ + -Wp,-D_FORTIFY_SOURCE=2])], + [AC_MSG_RESULT([skipping -D_FORTIFY_SOURCE, optimization not enabled])]) diff --git a/SOURCES/0063-man-fix-typo.patch b/SOURCES/0063-man-fix-typo.patch new file mode 100644 index 00000000..08edf6cd --- /dev/null +++ b/SOURCES/0063-man-fix-typo.patch @@ -0,0 +1,23 @@ +From 3f4c4af890ff655bf409875d0775f436e6d63353 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 3 Mar 2015 00:11:51 +0100 +Subject: [PATCH] man: fix typo + +(cherry picked from commit a68188812290cb9ec9f3f8a17b65e64549a4fd65) +--- + man/systemd.netdev.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml +index 4480e1999..ef58887dc 100644 +--- a/man/systemd.netdev.xml ++++ b/man/systemd.netdev.xml +@@ -108,7 +108,7 @@ + A bond device is an aggregation of all its slave devices. See Linux Ethernet Bonding Driver HOWTO for details.Local configuration + + bridge +- A bridge devcie is a software switch, each of its slave devices and the bridge itself are ports of the switch. ++ A bridge device is a software switch, each of its slave devices and the bridge itself are ports of the switch. + + dummy + A dummy device drops all packets sent to it. diff --git a/SOURCES/0064-bus-proxyd-avoid-logging-oom-twice.patch b/SOURCES/0064-bus-proxyd-avoid-logging-oom-twice.patch new file mode 100644 index 00000000..4156898a --- /dev/null +++ b/SOURCES/0064-bus-proxyd-avoid-logging-oom-twice.patch @@ -0,0 +1,23 @@ +From 61dd027666b40102bc9463217264f1deaab4cc8a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 3 Mar 2015 00:05:14 -0500 +Subject: [PATCH] bus-proxyd: avoid logging oom twice + +(cherry picked from commit c29005212dc38d98c707639d1a82ffa5270f2e97) +--- + src/bus-proxyd/bus-proxyd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +index b6b005636..b6550ed3c 100644 +--- a/src/bus-proxyd/bus-proxyd.c ++++ b/src/bus-proxyd/bus-proxyd.c +@@ -82,7 +82,7 @@ static int client_context_new(ClientContext **out) { + + c = new0(ClientContext, 1); + if (!c) +- return log_oom(); ++ return -ENOMEM; + + c->fd = -1; + diff --git a/SOURCES/0065-Do-not-run-sysv-generator-test-when-sysv-compat-is-d.patch b/SOURCES/0065-Do-not-run-sysv-generator-test-when-sysv-compat-is-d.patch new file mode 100644 index 00000000..c3765146 --- /dev/null +++ b/SOURCES/0065-Do-not-run-sysv-generator-test-when-sysv-compat-is-d.patch @@ -0,0 +1,29 @@ +From c11c73fc4541bf0ea5a418ebea53e58668100f82 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 3 Mar 2015 10:36:47 -0500 +Subject: [PATCH] Do not run sysv-generator-test when sysv compat is disabled + +(cherry picked from commit dcf1369057231fbf09e37b5a48483763b4ae6e19) +--- + Makefile.am | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index 2e6455f6e..4933f76bd 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3789,9 +3789,14 @@ TESTS += \ + if HAVE_PYTHON + TESTS += \ + test/rule-syntax-check.py \ ++ $(NULL) ++ ++if HAVE_SYSV_COMPAT ++TESTS += \ + test/sysv-generator-test.py \ + $(NULL) + endif ++endif + + manual_tests += \ + test-libudev \ diff --git a/SOURCES/0066-README-mention-ACLs-more.patch b/SOURCES/0066-README-mention-ACLs-more.patch new file mode 100644 index 00000000..7785e091 --- /dev/null +++ b/SOURCES/0066-README-mention-ACLs-more.patch @@ -0,0 +1,26 @@ +From b1e53a9d3cc7c6fbe4447e201c8f6348ffcd7b6a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 3 Mar 2015 09:00:39 -0500 +Subject: [PATCH] README: mention ACLs more + +They are now useful for any fs used for journal storage. + +(cherry picked from commit a6cccd8f580fc1e062dba3895e232007acd38781) +--- + README | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/README b/README +index ac2a81c0c..ffc2cf9f2 100644 +--- a/README ++++ b/README +@@ -78,8 +78,8 @@ REQUIREMENTS: + Optional but strongly recommended: + CONFIG_IPV6 + CONFIG_AUTOFS4_FS +- CONFIG_TMPFS_POSIX_ACL + CONFIG_TMPFS_XATTR ++ CONFIG_{TMPFS,EXT4,XFS,BTRFS_FS,...}_POSIX_ACL + CONFIG_SECCOMP + + Required for CPUShares in resource control unit settings diff --git a/SOURCES/0067-Do-not-advertise-.d-snippets-over-main-config-file.patch b/SOURCES/0067-Do-not-advertise-.d-snippets-over-main-config-file.patch new file mode 100644 index 00000000..cc8b5685 --- /dev/null +++ b/SOURCES/0067-Do-not-advertise-.d-snippets-over-main-config-file.patch @@ -0,0 +1,333 @@ +From b72201257216f687bf3462ad7539612cccbbce75 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 3 Mar 2015 19:10:21 -0500 +Subject: [PATCH] Do not advertise .d snippets over main config file + +For daemons which have a main configuration file, there's +little reason for the administrator to use configuration snippets. +They are useful for packagers which need to override settings, but +we shouldn't advertise that as the main way of configuring those +services. + +https://bugs.freedesktop.org/show_bug.cgi?id=89397 +(cherry picked from commit e93549ef29c4123d9ee45acb5815048390201e49) +--- + man/bootchart.conf.xml | 3 +-- + man/coredump.conf.xml | 3 +-- + man/journald.conf.xml | 3 +-- + man/logind.conf.xml | 8 +++++--- + man/resolved.conf.xml | 3 +-- + man/standard-conf.xml | 42 ++++++++++++++++++++++++++++++++++-------- + man/systemd-sleep.conf.xml | 3 +-- + man/systemd-system.conf.xml | 3 +-- + man/timesyncd.conf.xml | 3 +-- + src/bootchart/bootchart.conf | 7 ++++--- + src/core/system.conf | 7 ++++--- + src/journal/coredump.conf | 7 ++++--- + src/journal/journald.conf | 7 ++++--- + src/login/logind.conf | 7 ++++--- + src/resolve/resolved.conf.in | 5 +++-- + src/timesync/timesyncd.conf.in | 7 ++++--- + 16 files changed, 73 insertions(+), 45 deletions(-) + +diff --git a/man/bootchart.conf.xml b/man/bootchart.conf.xml +index 8d9700d30..bf6ca0bf9 100644 +--- a/man/bootchart.conf.xml ++++ b/man/bootchart.conf.xml +@@ -68,8 +68,7 @@ + parameters and graph output. + + +- +- ++ + + + Options +diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml +index 3d325e6ad..0b7329bf5 100644 +--- a/man/coredump.conf.xml ++++ b/man/coredump.conf.xml +@@ -63,8 +63,7 @@ + a handler for core dumps invoked by the kernel. + + +- +- ++ + + + Options +diff --git a/man/journald.conf.xml b/man/journald.conf.xml +index 364b58f07..85146b0d8 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -64,8 +64,7 @@ + + + +- +- ++ + + + Options +diff --git a/man/logind.conf.xml b/man/logind.conf.xml +index ffaec5035..ca2b18783 100644 +--- a/man/logind.conf.xml ++++ b/man/logind.conf.xml +@@ -58,11 +58,13 @@ + + Description + +- These files configure various parameters of the systemd login manager, systemd-logind.service8. ++ These files configure various parameters of the systemd ++ login manager, ++ systemd-logind.service8. ++ + + +- +- ++ + + + Options +diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml +index 36cae2706..8047a4ea7 100644 +--- a/man/resolved.conf.xml ++++ b/man/resolved.conf.xml +@@ -63,8 +63,7 @@ + + + +- +- ++ + + + Options +diff --git a/man/standard-conf.xml b/man/standard-conf.xml +index b87d7e955..36af45927 100644 +--- a/man/standard-conf.xml ++++ b/man/standard-conf.xml +@@ -33,13 +33,39 @@ + configuration file. + + +- +- Configuration File +- +- Configuration is also read from a single configuration file in +- /etc/. This file is read before any of the +- configuration directories, and has the lowest precedence; entries in a file +- in any configuration directory override entries in the single configuration +- file. ++ ++ Configuration Directories and Precedence ++ ++ Default configuration is defined during compilation, so a ++ configuration file is only needed when it is necessary to deviate ++ from those defaults. By default the configuration file in ++ /etc/systemd/ contains commented out entries ++ showing the defaults as a guide to the administrator. This file ++ can be edited to create local overrides. ++ ++ ++ When packages need to customize the configuration, they can ++ install configuration snippets in ++ /usr/lib/systemd/*.conf.d/. Files in ++ /etc/ are reserved for the local ++ administrator, who may use this logic to override the ++ configuration files installed by vendor packages. The main ++ configuration file is read before any of the configuration ++ directories, and has the lowest precedence; entries in a file in ++ any configuration directory override entries in the single ++ configuration file. Files in the ++ logind.conf.d/ configuration subdirectories ++ are sorted by their filename in lexicographic order, regardless of ++ which of the subdirectories they reside in. If multiple files ++ specify the same option, the entry in the file with the ++ lexicographically latest name takes precedence. It is recommended ++ to prefix all filenames in those subdirectories with a two-digit ++ number and a dash, to simplify the ordering of the files. ++ ++ To disable a configuration file supplied by the vendor, the ++ recommended way is to place a symlink to ++ /dev/null in the configuration directory in ++ /etc/, with the same filename as the vendor ++ configuration file. + + +diff --git a/man/systemd-sleep.conf.xml b/man/systemd-sleep.conf.xml +index 433f2f83a..bb17ec866 100644 +--- a/man/systemd-sleep.conf.xml ++++ b/man/systemd-sleep.conf.xml +@@ -112,8 +112,7 @@ along with systemd; If not, see . + attempts to suspend or hibernate the machine. + + +- +- ++ + + + Options +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 7c3f23756..c7bcfaee4 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -74,8 +74,7 @@ + operations. + + +- +- ++ + + + Options +diff --git a/man/timesyncd.conf.xml b/man/timesyncd.conf.xml +index 1127970a1..89a651c66 100644 +--- a/man/timesyncd.conf.xml ++++ b/man/timesyncd.conf.xml +@@ -63,8 +63,7 @@ + + + +- +- ++ + + + Options +diff --git a/src/bootchart/bootchart.conf b/src/bootchart/bootchart.conf +index 2d7cb6121..4f5e50936 100644 +--- a/src/bootchart/bootchart.conf ++++ b/src/bootchart/bootchart.conf +@@ -5,10 +5,11 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + # +-# You can override the directives in this file by creating files in +-# /etc/systemd/bootchart.conf.d/*.conf. ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. + # +-# See bootchart.conf(5) for details ++# See bootchart.conf(5) for details. + + [Bootchart] + #Samples=500 +diff --git a/src/core/system.conf b/src/core/system.conf +index a3727200d..231609033 100644 +--- a/src/core/system.conf ++++ b/src/core/system.conf +@@ -5,10 +5,11 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + # +-# You can override the directives in this file by creating files in +-# /etc/systemd/system.conf.d/*.conf. ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. + # +-# See systemd-system.conf(5) for details ++# See systemd-system.conf(5) for details. + + [Manager] + #LogLevel=info +diff --git a/src/journal/coredump.conf b/src/journal/coredump.conf +index 0fe9fe801..c2f0643e0 100644 +--- a/src/journal/coredump.conf ++++ b/src/journal/coredump.conf +@@ -5,10 +5,11 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + # +-# You can override the directives in this file by creating files in +-# /etc/systemd/coredump.conf.d/*.conf. ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. + # +-# See coredump.conf(5) for details ++# See coredump.conf(5) for details. + + [Coredump] + #Storage=external +diff --git a/src/journal/journald.conf b/src/journal/journald.conf +index 29bdf8f18..47eefe91c 100644 +--- a/src/journal/journald.conf ++++ b/src/journal/journald.conf +@@ -5,10 +5,11 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + # +-# You can override the directives in this file by creating files in +-# /etc/systemd/journald.conf.d/*.conf. ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. + # +-# See journald.conf(5) for details ++# See journald.conf(5) for details. + + [Journal] + #Storage=auto +diff --git a/src/login/logind.conf b/src/login/logind.conf +index 6b1943a2d..834c4c2eb 100644 +--- a/src/login/logind.conf ++++ b/src/login/logind.conf +@@ -5,10 +5,11 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + # +-# You can override the directives in this file by creating files in +-# /etc/systemd/logind.conf.d/*.conf. ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. + # +-# See logind.conf(5) for details ++# See logind.conf(5) for details. + + [Login] + #NAutoVTs=6 +diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in +index e5a19ee47..3eb19e42b 100644 +--- a/src/resolve/resolved.conf.in ++++ b/src/resolve/resolved.conf.in +@@ -5,8 +5,9 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + # +-# You can override the directives in this file by creating files in +-# /etc/systemd/resolved.conf.d/*.conf. ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. + # + # See resolved.conf(5) for details + +diff --git a/src/timesync/timesyncd.conf.in b/src/timesync/timesyncd.conf.in +index fc3c6c49c..b6a2ada27 100644 +--- a/src/timesync/timesyncd.conf.in ++++ b/src/timesync/timesyncd.conf.in +@@ -5,10 +5,11 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + # +-# You can override the directives in this file by creating files in +-# /etc/systemd/timesyncd.conf.d/*.conf. ++# Entries in this file show the compile time defaults. ++# You can change settings by editing this file. ++# Defaults can be restored by simply deleting this file. + # +-# See timesyncd.conf(5) for details ++# See timesyncd.conf(5) for details. + + [Time] + #NTP= diff --git a/SOURCES/0068-hwdb-add-pnpid-for-the-T450s-touchpad.patch b/SOURCES/0068-hwdb-add-pnpid-for-the-T450s-touchpad.patch new file mode 100644 index 00000000..680602b6 --- /dev/null +++ b/SOURCES/0068-hwdb-add-pnpid-for-the-T450s-touchpad.patch @@ -0,0 +1,22 @@ +From 48b8df6ea51021e6624bdc45ff371dd033d379df Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Wed, 4 Mar 2015 13:24:45 +1000 +Subject: [PATCH] hwdb: add pnpid for the T450s touchpad + +https://bugs.freedesktop.org/show_bug.cgi?id=89411 +(cherry picked from commit c26c1d86b3e466e073577e27ad839a0c112cd17b) +--- + hwdb/70-touchpad.hwdb | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hwdb/70-touchpad.hwdb b/hwdb/70-touchpad.hwdb +index bbf44db77..9fcb5fdb9 100644 +--- a/hwdb/70-touchpad.hwdb ++++ b/hwdb/70-touchpad.hwdb +@@ -36,4 +36,6 @@ + + # Lenovo X1 Carbon 3rd + touchpad:pnpid:*LEN0048*: ++# Lenovo T450s ++touchpad:pnpid:*LEN200f*: + TOUCHPAD_HAS_TRACKPOINT_BUTTONS=1 diff --git a/SOURCES/0069-networkd-netdev-inform-when-we-take-over-an-existing.patch b/SOURCES/0069-networkd-netdev-inform-when-we-take-over-an-existing.patch new file mode 100644 index 00000000..fb5bd174 --- /dev/null +++ b/SOURCES/0069-networkd-netdev-inform-when-we-take-over-an-existing.patch @@ -0,0 +1,30 @@ +From fab00ed4a9ce8a1d579028c2fc39db3717b454da Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 4 Mar 2015 10:33:50 +0100 +Subject: [PATCH] networkd: netdev - inform when we take over an existing + netdev + +The crucial point here is that we will not change the settings of a netdev created by someone else +we simply use it as is and trust it was set up as intended. + +This is confusing in the case of the pre-created netdev's (bond0 etc.), the solution should probably +be to simply make the kernel stop creating these devices as they are pretty useless. + +(cherry picked from commit ff88a301e93cf1bddbaa7faa981f390a2a81a4bb) +--- + src/network/networkd-netdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c +index 8119205dd..7d193d088 100644 +--- a/src/network/networkd-netdev.c ++++ b/src/network/networkd-netdev.c +@@ -261,7 +261,7 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda + + r = sd_rtnl_message_get_errno(m); + if (r == -EEXIST) +- log_netdev_debug(netdev, "netdev exists, using existing"); ++ log_info_netdev(netdev, "netdev exists, using existing without changing its parameters"); + else if (r < 0) { + log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r)); + netdev_drop(netdev); diff --git a/SOURCES/0070-man-replace-obsolete-wiki-link-with-man-page.patch b/SOURCES/0070-man-replace-obsolete-wiki-link-with-man-page.patch new file mode 100644 index 00000000..9bff772b --- /dev/null +++ b/SOURCES/0070-man-replace-obsolete-wiki-link-with-man-page.patch @@ -0,0 +1,181 @@ +From d3a45e70ee215646cdfbe19f514be08ae95e12eb Mon Sep 17 00:00:00 2001 +From: Zachary Cook +Date: Wed, 4 Mar 2015 18:43:20 -0500 +Subject: [PATCH] man: replace obsolete wiki link with man page + +(cherry picked from commit b1c1a51944e8e11545ae2a230d674f5145595192) +--- + man/systemd-cryptsetup-generator.xml | 6 ++---- + man/systemd-debug-generator.xml | 6 ++---- + man/systemd-efi-boot-generator.xml | 4 +--- + man/systemd-fstab-generator.xml | 6 ++---- + man/systemd-getty-generator.xml | 5 ++--- + man/systemd-gpt-auto-generator.xml | 4 +--- + man/systemd-system-update-generator.xml | 6 ++---- + man/systemd-sysv-generator.xml | 6 ++---- + man/systemd.unit.xml | 4 ++-- + man/systemd.xml | 5 ++--- + 10 files changed, 18 insertions(+), 34 deletions(-) + +diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml +index 0e48e7934..1974cd7a2 100644 +--- a/man/systemd-cryptsetup-generator.xml ++++ b/man/systemd-cryptsetup-generator.xml +@@ -59,10 +59,8 @@ + systemd-cryptsetup@.service8 + units as necessary. + +- systemd-cryptsetup-generator +- implements the generator +- specification. ++ systemd-cryptsetup-generator implements ++ systemd.generator7. + + + +diff --git a/man/systemd-debug-generator.xml b/man/systemd-debug-generator.xml +index 74c3b2620..5c5e9fc4a 100644 +--- a/man/systemd-debug-generator.xml ++++ b/man/systemd-debug-generator.xml +@@ -79,10 +79,8 @@ + systemctl1's + enable command. + +- systemd-debug-generator implements the +- generator +- specification. ++ systemd-debug-generator implements ++ systemd.generator7. + + + +diff --git a/man/systemd-efi-boot-generator.xml b/man/systemd-efi-boot-generator.xml +index b2d8d65e3..fd7ba7983 100644 +--- a/man/systemd-efi-boot-generator.xml ++++ b/man/systemd-efi-boot-generator.xml +@@ -68,9 +68,7 @@ + only be activated on-demand, when accessed. + + systemd-efi-boot-generator implements +- the generator +- specification. ++ systemd.generator7. + + + +diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml +index 8f82e3330..022efb413 100644 +--- a/man/systemd-fstab-generator.xml ++++ b/man/systemd-fstab-generator.xml +@@ -71,10 +71,8 @@ + for more information about special /etc/fstab + mount options this generator understands. + +- systemd-fstab-generator implements the +- generator +- specification. ++ systemd-fstab-generator implements ++ systemd.generator7. + + + +diff --git a/man/systemd-getty-generator.xml b/man/systemd-getty-generator.xml +index 0b5b2f2a7..338925964 100644 +--- a/man/systemd-getty-generator.xml ++++ b/man/systemd-getty-generator.xml +@@ -75,9 +75,8 @@ + for more information on the console= kernel + parameter. + +- systemd-getty-generator implements the +- generator +- specification. ++ systemd-getty-generator implements ++ systemd.generator7. + + Further information about configuration of gettys you may + find in +diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml +index 9c706df24..8d2eaca4f 100644 +--- a/man/systemd-gpt-auto-generator.xml ++++ b/man/systemd-gpt-auto-generator.xml +@@ -157,9 +157,7 @@ + using btrfs subvolume set-default. + + systemd-gpt-auto-generator implements +- the +- Generator +- Specification. ++ systemd.generator7. + + + +diff --git a/man/systemd-system-update-generator.xml b/man/systemd-system-update-generator.xml +index 3eec1d7b9..e7fc95c74 100644 +--- a/man/systemd-system-update-generator.xml ++++ b/man/systemd-system-update-generator.xml +@@ -61,10 +61,8 @@ + Updates Specification. + + +- systemd-system-update-generator +- implements the +- generator +- specification. ++ systemd-system-update-generator implements ++ systemd.generator7. + + + +diff --git a/man/systemd-sysv-generator.xml b/man/systemd-sysv-generator.xml +index e619b1bc2..f2d56cbcd 100644 +--- a/man/systemd-sysv-generator.xml ++++ b/man/systemd-sysv-generator.xml +@@ -81,10 +81,8 @@ + part of early boot, so all wrapper units are ordered after + basic.target. + +- systemd-sysv-generator +- implements the generator +- specification. ++ systemd-sysv-generator implements ++ systemd.generator7. + + + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index 09e11b471..a452f87ba 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -357,8 +357,8 @@ + from directories not on the unit load path. See the + link command for + systemctl1. +- Also, some units are dynamically created via generators Generators. ++ Also, some units are dynamically created via a ++ systemd.generator7. + + + +diff --git a/man/systemd.xml b/man/systemd.xml +index 80591dc73..9b92140e6 100644 +--- a/man/systemd.xml ++++ b/man/systemd.xml +@@ -415,9 +415,8 @@ + + Units may be generated dynamically at boot and system + manager reload time, for example based on other configuration +- files or parameters passed on the kernel command line. For details +- see the +- Generators Specification. ++ files or parameters passed on the kernel command line. For details see ++ systemd.generator7. + + Systems which invoke systemd in a container or initrd + environment should implement the diff --git a/SOURCES/0071-Use-correct-uname-identifiers-in-arch_map-for-SuperH.patch b/SOURCES/0071-Use-correct-uname-identifiers-in-arch_map-for-SuperH.patch new file mode 100644 index 00000000..5140e7e7 --- /dev/null +++ b/SOURCES/0071-Use-correct-uname-identifiers-in-arch_map-for-SuperH.patch @@ -0,0 +1,31 @@ +From 3df99b05df12b73e4d081ee223f9b35ed33f47ca Mon Sep 17 00:00:00 2001 +From: John Paul Adrian Glaubitz +Date: Thu, 5 Mar 2015 00:07:33 +0100 +Subject: [PATCH] Use correct uname identifiers in arch_map for SuperH + architecture + +https://bugs.freedesktop.org/show_bug.cgi?id=89421 +(cherry picked from commit 3a867c6a2361c8af943d3ed452da6e8623a3f65d) +--- + src/shared/architecture.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/shared/architecture.c b/src/shared/architecture.c +index 34c5a53fa..884abdd3e 100644 +--- a/src/shared/architecture.c ++++ b/src/shared/architecture.c +@@ -108,8 +108,12 @@ int uname_architecture(void) { + { "armv8l", ARCHITECTURE_ARM }, + { "armv8b", ARCHITECTURE_ARM_BE }, + #elif defined(__sh__) || defined(__sh64__) +- { "sh64", ARCHITECTURE_SH64 }, +- { "sh", ARCHITECTURE_SH }, ++ { "sh5", ARCHITECTURE_SH64 }, ++ { "sh2", ARCHITECTURE_SH }, ++ { "sh2a", ARCHITECTURE_SH }, ++ { "sh3", ARCHITECTURE_SH }, ++ { "sh4", ARCHITECTURE_SH }, ++ { "sh4a", ARCHITECTURE_SH }, + #elif defined(__m68k__) + { "m68k", ARCHITECTURE_M68K }, + #elif defined(__tilegx__) diff --git a/SOURCES/0072-hwdb-fix-Dell-XPS12-9Q33-key-name.patch b/SOURCES/0072-hwdb-fix-Dell-XPS12-9Q33-key-name.patch new file mode 100644 index 00000000..6ed6bfc6 --- /dev/null +++ b/SOURCES/0072-hwdb-fix-Dell-XPS12-9Q33-key-name.patch @@ -0,0 +1,24 @@ +From e43361ab55a61ebfaf16e1c78be1bce1fdf84c67 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 4 Mar 2015 20:25:04 -0500 +Subject: [PATCH] hwdb: fix Dell XPS12 9Q33 key name + +https://bugs.freedesktop.org/show_bug.cgi?id=84437 +(cherry picked from commit 4f70555d76c90ffdc5a5e4f75bbc08b38022c911) +--- + hwdb/60-keyboard.hwdb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb +index 2cb976923..88906655e 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -259,7 +259,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:pvr* + # Dell XPS12 9Q33 + keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr* + KEYBOARD_KEY_88=wlan +- KEYBOARD_KEY_65=switchvideomode # Screen Rotate ++ KEYBOARD_KEY_65=direction # Screen Rotate + + # Dell Latitude microphone mute + keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude* diff --git a/SOURCES/0073-Remove-the-cap-on-epoll-events.patch b/SOURCES/0073-Remove-the-cap-on-epoll-events.patch new file mode 100644 index 00000000..7ec345e1 --- /dev/null +++ b/SOURCES/0073-Remove-the-cap-on-epoll-events.patch @@ -0,0 +1,36 @@ +From f5ce5e24f9cf18a37ef6aedb149891d07767b045 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 4 Mar 2015 16:32:16 +0100 +Subject: [PATCH] Remove the cap on epoll events + +Currently the code will silently blank out events if there are more +then 512 epoll events, causing them never to be handled at all. This +patch removes the cap on the number of events for epoll_wait, thereby +avoiding this issue. + +(cherry picked from commit 1c724e9e0ec5bc4bf791a3d7b1cf5b955cdb98b2) +--- + src/libsystemd/sd-event/sd-event.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 25089a033..c6350be9f 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -37,7 +37,6 @@ + + #include "sd-event.h" + +-#define EPOLL_QUEUE_MAX 512U + #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) + + typedef enum EventSourceType { +@@ -2367,7 +2366,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { + return 1; + } + +- ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX); ++ ev_queue_max = MAX(e->n_sources, 1u); + ev_queue = newa(struct epoll_event, ev_queue_max); + + m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max, diff --git a/SOURCES/0074-Allow-up-to-4096-simultaneous-connections.patch b/SOURCES/0074-Allow-up-to-4096-simultaneous-connections.patch new file mode 100644 index 00000000..c2d7f994 --- /dev/null +++ b/SOURCES/0074-Allow-up-to-4096-simultaneous-connections.patch @@ -0,0 +1,30 @@ +From b4ea0d8280135b7eabb1bb70e24d62c86e065db3 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 4 Mar 2015 16:32:17 +0100 +Subject: [PATCH] Allow up to 4096 simultaneous connections + +On large system we hit the limit on 512 simultaneous dbus +connections, resulting in tons of annoying messages: + +Too many concurrent connections, refusing + +This patch raises the limit to 4096. + +(cherry picked from commit cbecf9bf929318533fea798c57c10efcf6b2b447) +--- + src/core/dbus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/dbus.c b/src/core/dbus.c +index 260775cd8..85b517486 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -44,7 +44,7 @@ + #include "bus-internal.h" + #include "selinux-access.h" + +-#define CONNECTIONS_MAX 512 ++#define CONNECTIONS_MAX 4096 + + static void destroy_bus(Manager *m, sd_bus **bus); + diff --git a/SOURCES/0075-hwdb-add-Logitech-G5-Laser-Mouse.patch b/SOURCES/0075-hwdb-add-Logitech-G5-Laser-Mouse.patch new file mode 100644 index 00000000..bc2be592 --- /dev/null +++ b/SOURCES/0075-hwdb-add-Logitech-G5-Laser-Mouse.patch @@ -0,0 +1,23 @@ +From b9c441e4f5e7049c23d3f5d0a5a874b13e0356fc Mon Sep 17 00:00:00 2001 +From: Jonathon Gilbert +Date: Thu, 5 Mar 2015 20:29:56 +1000 +Subject: [PATCH] hwdb: add Logitech G5 Laser Mouse + +(cherry picked from commit 6437edbebe80e68b782f178c7a76e870a53811d7) +--- + hwdb/70-mouse.hwdb | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb +index a62ebc497..93ee4d9fa 100644 +--- a/hwdb/70-mouse.hwdb ++++ b/hwdb/70-mouse.hwdb +@@ -196,6 +196,8 @@ mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4008: + mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101b: + MOUSE_DPI=800@166 + ++# Logitech G5 Laser Mouse ++mouse:usb:v046dpc049:name:Logitech USB Gaming Mouse: + # Logitech G500s Laser Gaming Mouse + mouse:usb:v046dpc24e:name:Logitech G500s Laser Gaming Mouse: + MOUSE_DPI=400@500 *800@500 2000@500 diff --git a/SOURCES/0076-tmpfiles-Fix-handling-of-duplicate-lines.patch b/SOURCES/0076-tmpfiles-Fix-handling-of-duplicate-lines.patch new file mode 100644 index 00000000..f491d814 --- /dev/null +++ b/SOURCES/0076-tmpfiles-Fix-handling-of-duplicate-lines.patch @@ -0,0 +1,32 @@ +From 339b62c8f336bb51dc7a925062abeb3ce76145e6 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Thu, 5 Mar 2015 14:58:56 +0100 +Subject: [PATCH] tmpfiles: Fix handling of duplicate lines + +Commit 3f93da987 accidentally dropped the "return 0" after detection of a +duplicate line. Put it back, to get back the documented and intended "first +match wins" behaviour. + +https://launchpad.net/bugs/1428540 +(cherry picked from commit 6487ada88d63e4998113f4c57fa10b7c865f8026) +--- + src/tmpfiles/tmpfiles.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 187997e1f..1e1096816 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1750,9 +1750,11 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + unsigned n; + + for (n = 0; n < existing->count; n++) { +- if (!item_compatible(existing->items + n, &i)) ++ if (!item_compatible(existing->items + n, &i)) { + log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.", + fname, line, i.path); ++ return 0; ++ } + } + } else { + existing = new0(ItemArray, 1); diff --git a/SOURCES/0077-hwdb-add-Lenovo-W451-to-TOUCHPAD_HAS_TRACKPOINT_BUTT.patch b/SOURCES/0077-hwdb-add-Lenovo-W451-to-TOUCHPAD_HAS_TRACKPOINT_BUTT.patch new file mode 100644 index 00000000..5dcb3ec6 --- /dev/null +++ b/SOURCES/0077-hwdb-add-Lenovo-W451-to-TOUCHPAD_HAS_TRACKPOINT_BUTT.patch @@ -0,0 +1,23 @@ +From 01dd8dc414460df51940c64e73cf318a9f587270 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Fri, 6 Mar 2015 11:02:04 +1000 +Subject: [PATCH] hwdb: add Lenovo W451 to TOUCHPAD_HAS_TRACKPOINT_BUTTONS list + +(cherry picked from commit 9638ee90862e4a24f5796e87beebc4c47e2728c2) +--- + hwdb/70-touchpad.hwdb | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hwdb/70-touchpad.hwdb b/hwdb/70-touchpad.hwdb +index 9fcb5fdb9..8a324466b 100644 +--- a/hwdb/70-touchpad.hwdb ++++ b/hwdb/70-touchpad.hwdb +@@ -36,6 +36,8 @@ + + # Lenovo X1 Carbon 3rd + touchpad:pnpid:*LEN0048*: ++# Lenovo W541 ++touchpad:pnpid:*LEN004a*: + # Lenovo T450s + touchpad:pnpid:*LEN200f*: + TOUCHPAD_HAS_TRACKPOINT_BUTTONS=1 diff --git a/SOURCES/0078-vconsole-match-on-vtcon-events-not-fbcon-ones.patch b/SOURCES/0078-vconsole-match-on-vtcon-events-not-fbcon-ones.patch new file mode 100644 index 00000000..19d04e42 --- /dev/null +++ b/SOURCES/0078-vconsole-match-on-vtcon-events-not-fbcon-ones.patch @@ -0,0 +1,39 @@ +From 5e6503d0d2efb5cbff945df42423640ffb138073 Mon Sep 17 00:00:00 2001 +From: Jan Engelhardt +Date: Tue, 24 Feb 2015 17:49:02 +0100 +Subject: [PATCH] vconsole: match on vtcon events, not fbcon ones + +I observe that upon loading of framebuffer drivers, I do not get the +desired system font, but the kernel-level defaults (usually +lib/fonts/font_8x16.c, but your mileage may vary depending on kernel +config and boot options). + +The fbcon driver may be loaded at a time way before the first +framebuffer device is active, such that the vconsole setup helper +runs too early. + +The existing rule is non-fitting. The going live of the fbcon kernel +component does not indicate the proper time at which to load the +visuals, which really ought to be done when a new vtcon object comes +into existence. (The font table is a per-vtcon property.) + +(cherry picked from commit a52750d1483ff139df33149afc0b675531e9cd79) +--- + src/vconsole/90-vconsole.rules.in | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/vconsole/90-vconsole.rules.in b/src/vconsole/90-vconsole.rules.in +index 062009640..35b9ad515 100644 +--- a/src/vconsole/90-vconsole.rules.in ++++ b/src/vconsole/90-vconsole.rules.in +@@ -5,7 +5,6 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + +-# Kernel resets vconsole state when changing console drivers so run +-# systemd-vconsole-setup when fbcon loads +- +-ACTION=="add", SUBSYSTEM=="graphics", KERNEL=="fbcon", RUN+="@rootlibexecdir@/systemd-vconsole-setup" ++# Each vtcon keeps its own state of fonts. ++# ++ACTION=="add", SUBSYSTEM=="vtconsole", KERNEL=="vtcon*", RUN+="@rootlibexecdir@/systemd-vconsole-setup" diff --git a/SOURCES/0079-core-do-not-spawn-jobs-or-touch-other-units-during-c.patch b/SOURCES/0079-core-do-not-spawn-jobs-or-touch-other-units-during-c.patch new file mode 100644 index 00000000..35f52731 --- /dev/null +++ b/SOURCES/0079-core-do-not-spawn-jobs-or-touch-other-units-during-c.patch @@ -0,0 +1,375 @@ +From f997080b4d17a40b59b398e4354b6368d9c85f69 Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Sat, 7 Mar 2015 08:44:52 -0500 +Subject: [PATCH] core: do not spawn jobs or touch other units during + coldplugging + +Because the order of coldplugging is not defined, we can reference a +not-yet-coldplugged unit and read its state while it has not yet been +set to a meaningful value. + +This way, already active units may get started again. + +We fix this by deferring such actions until all units have been at +least somehow coldplugged. + +Fixes https://bugs.freedesktop.org/show_bug.cgi?id=88401 + +(cherry picked from commit 6e392c9c45643d106673c6643ac8bf4e65da13c1) +--- + src/core/automount.c | 2 +- + src/core/busname.c | 2 +- + src/core/device.c | 2 +- + src/core/manager.c | 35 +++++++++++++++++++++++++++++++++-- + src/core/mount.c | 2 +- + src/core/path.c | 14 ++++++++++---- + src/core/scope.c | 2 +- + src/core/service.c | 2 +- + src/core/slice.c | 2 +- + src/core/snapshot.c | 2 +- + src/core/socket.c | 2 +- + src/core/swap.c | 2 +- + src/core/target.c | 2 +- + src/core/timer.c | 14 ++++++++++---- + src/core/unit.c | 25 ++++++++++++++++--------- + src/core/unit.h | 12 +++++++++--- + 16 files changed, 89 insertions(+), 33 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index 9f6bd84b2..e4c79415d 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -235,7 +235,7 @@ 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_coldplug(Unit *u) { ++static int automount_coldplug(Unit *u, Hashmap *deferred_work) { + Automount *a = AUTOMOUNT(u); + int r; + +diff --git a/src/core/busname.c b/src/core/busname.c +index 1d77292f9..43d7607a3 100644 +--- a/src/core/busname.c ++++ b/src/core/busname.c +@@ -335,7 +335,7 @@ static void busname_set_state(BusName *n, BusNameState state) { + unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true); + } + +-static int busname_coldplug(Unit *u) { ++static int busname_coldplug(Unit *u, Hashmap *deferred_work) { + BusName *n = BUSNAME(u); + int r; + +diff --git a/src/core/device.c b/src/core/device.c +index 1cc103c29..4ff882721 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -142,7 +142,7 @@ static void device_set_state(Device *d, DeviceState state) { + unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true); + } + +-static int device_coldplug(Unit *u) { ++static int device_coldplug(Unit *u, Hashmap *deferred_work) { + Device *d = DEVICE(u); + + assert(d); +diff --git a/src/core/manager.c b/src/core/manager.c +index bc9b7ec62..203a6a0a1 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -983,7 +983,28 @@ static int manager_coldplug(Manager *m) { + Unit *u; + char *k; + +- assert(m); ++ /* ++ * Some unit types tend to spawn jobs or check other units' state ++ * during coldplug. This is wrong because it is undefined whether the ++ * units in question have been already coldplugged (i. e. their state ++ * restored). This way, we can easily re-start an already started unit ++ * or otherwise make a wrong decision based on the unit's state. ++ * ++ * Solve this by providing a way for coldplug functions to defer ++ * such actions until after all units have been coldplugged. ++ * ++ * We store Unit* -> int(*)(Unit*). ++ * ++ * https://bugs.freedesktop.org/show_bug.cgi?id=88401 ++ */ ++ _cleanup_hashmap_free_ Hashmap *deferred_work = NULL; ++ int(*proc)(Unit*); ++ ++ assert(m); ++ ++ deferred_work = hashmap_new(&trivial_hash_ops); ++ if (!deferred_work) ++ return -ENOMEM; + + /* Then, let's set up their initial state. */ + HASHMAP_FOREACH_KEY(u, k, m->units, i) { +@@ -993,7 +1014,17 @@ static int manager_coldplug(Manager *m) { + if (u->id != k) + continue; + +- q = unit_coldplug(u); ++ q = unit_coldplug(u, deferred_work); ++ if (q < 0) ++ r = q; ++ } ++ ++ /* After coldplugging and setting up initial state of the units, ++ * let's perform operations which spawn jobs or query units' state. */ ++ HASHMAP_FOREACH_KEY(proc, u, deferred_work, i) { ++ int q; ++ ++ q = proc(u); + if (q < 0) + r = q; + } +diff --git a/src/core/mount.c b/src/core/mount.c +index c971330af..3ae0eb462 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -617,7 +617,7 @@ static void mount_set_state(Mount *m, MountState state) { + m->reload_result = MOUNT_SUCCESS; + } + +-static int mount_coldplug(Unit *u) { ++static int mount_coldplug(Unit *u, Hashmap *deferred_work) { + Mount *m = MOUNT(u); + MountState new_state = MOUNT_DEAD; + int r; +diff --git a/src/core/path.c b/src/core/path.c +index e5ea79fec..51e36fa8b 100644 +--- a/src/core/path.c ++++ b/src/core/path.c +@@ -440,7 +440,12 @@ static void path_set_state(Path *p, PathState state) { + + static void path_enter_waiting(Path *p, bool initial, bool recheck); + +-static int path_coldplug(Unit *u) { ++static int path_enter_waiting_coldplug(Unit *u) { ++ path_enter_waiting(PATH(u), true, true); ++ return 0; ++} ++ ++static int path_coldplug(Unit *u, Hashmap *deferred_work) { + Path *p = PATH(u); + + assert(p); +@@ -449,9 +454,10 @@ static int path_coldplug(Unit *u) { + if (p->deserialized_state != p->state) { + + if (p->deserialized_state == PATH_WAITING || +- p->deserialized_state == PATH_RUNNING) +- path_enter_waiting(p, true, true); +- else ++ p->deserialized_state == PATH_RUNNING) { ++ hashmap_put(deferred_work, u, &path_enter_waiting_coldplug); ++ path_set_state(p, PATH_WAITING); ++ } else + path_set_state(p, p->deserialized_state); + } + +diff --git a/src/core/scope.c b/src/core/scope.c +index b41db7872..ae6614fbf 100644 +--- a/src/core/scope.c ++++ b/src/core/scope.c +@@ -173,7 +173,7 @@ static int scope_load(Unit *u) { + return scope_verify(s); + } + +-static int scope_coldplug(Unit *u) { ++static int scope_coldplug(Unit *u, Hashmap *deferred_work) { + Scope *s = SCOPE(u); + int r; + +diff --git a/src/core/service.c b/src/core/service.c +index 15e29be14..7781b4e62 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -879,7 +879,7 @@ static void service_set_state(Service *s, ServiceState state) { + s->reload_result = SERVICE_SUCCESS; + } + +-static int service_coldplug(Unit *u) { ++static int service_coldplug(Unit *u, Hashmap *deferred_work) { + Service *s = SERVICE(u); + int r; + +diff --git a/src/core/slice.c b/src/core/slice.c +index ae9819d01..61ff9d331 100644 +--- a/src/core/slice.c ++++ b/src/core/slice.c +@@ -153,7 +153,7 @@ static int slice_load(Unit *u) { + return slice_verify(s); + } + +-static int slice_coldplug(Unit *u) { ++static int slice_coldplug(Unit *u, Hashmap *deferred_work) { + Slice *t = SLICE(u); + + assert(t); +diff --git a/src/core/snapshot.c b/src/core/snapshot.c +index b70c3beb6..b1d844877 100644 +--- a/src/core/snapshot.c ++++ b/src/core/snapshot.c +@@ -75,7 +75,7 @@ static int snapshot_load(Unit *u) { + return 0; + } + +-static int snapshot_coldplug(Unit *u) { ++static int snapshot_coldplug(Unit *u, Hashmap *deferred_work) { + Snapshot *s = SNAPSHOT(u); + + assert(s); +diff --git a/src/core/socket.c b/src/core/socket.c +index 88aae4815..760de0203 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -1326,7 +1326,7 @@ static void socket_set_state(Socket *s, SocketState state) { + unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); + } + +-static int socket_coldplug(Unit *u) { ++static int socket_coldplug(Unit *u, Hashmap *deferred_work) { + Socket *s = SOCKET(u); + int r; + +diff --git a/src/core/swap.c b/src/core/swap.c +index 5c19af5d9..369abf0f5 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -513,7 +513,7 @@ static void swap_set_state(Swap *s, SwapState state) { + job_add_to_run_queue(UNIT(other)->job); + } + +-static int swap_coldplug(Unit *u) { ++static int swap_coldplug(Unit *u, Hashmap *deferred_work) { + Swap *s = SWAP(u); + SwapState new_state = SWAP_DEAD; + int r; +diff --git a/src/core/target.c b/src/core/target.c +index 33fb66bc3..2411a8e75 100644 +--- a/src/core/target.c ++++ b/src/core/target.c +@@ -107,7 +107,7 @@ static int target_load(Unit *u) { + return 0; + } + +-static int target_coldplug(Unit *u) { ++static int target_coldplug(Unit *u, Hashmap *deferred_work) { + Target *t = TARGET(u); + + assert(t); +diff --git a/src/core/timer.c b/src/core/timer.c +index 45744c7de..48cf9c16a 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -268,7 +268,12 @@ static void timer_set_state(Timer *t, TimerState state) { + + static void timer_enter_waiting(Timer *t, bool initial); + +-static int timer_coldplug(Unit *u) { ++static int timer_enter_waiting_coldplug(Unit *u) { ++ timer_enter_waiting(TIMER(u), false); ++ return 0; ++} ++ ++static int timer_coldplug(Unit *u, Hashmap *deferred_work) { + Timer *t = TIMER(u); + + assert(t); +@@ -276,9 +281,10 @@ static int timer_coldplug(Unit *u) { + + if (t->deserialized_state != t->state) { + +- if (t->deserialized_state == TIMER_WAITING) +- timer_enter_waiting(t, false); +- else ++ if (t->deserialized_state == TIMER_WAITING) { ++ hashmap_put(deferred_work, u, &timer_enter_waiting_coldplug); ++ timer_set_state(t, TIMER_WAITING); ++ } else + timer_set_state(t, t->deserialized_state); + } + +diff --git a/src/core/unit.c b/src/core/unit.c +index a6558ee23..565455bd6 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2859,27 +2859,34 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { + return 0; + } + +-int unit_coldplug(Unit *u) { ++static int unit_add_deserialized_job_coldplug(Unit *u) { ++ int r; ++ ++ r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ u->deserialized_job = _JOB_TYPE_INVALID; ++ ++ return 0; ++} ++ ++int unit_coldplug(Unit *u, Hashmap *deferred_work) { + int r; + + assert(u); + + if (UNIT_VTABLE(u)->coldplug) +- if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0) ++ if ((r = UNIT_VTABLE(u)->coldplug(u, deferred_work)) < 0) + return r; + + if (u->job) { + r = job_coldplug(u->job); + if (r < 0) + return r; +- } else if (u->deserialized_job >= 0) { ++ } else if (u->deserialized_job >= 0) + /* legacy */ +- r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL); +- if (r < 0) +- return r; +- +- u->deserialized_job = _JOB_TYPE_INVALID; +- } ++ hashmap_put(deferred_work, u, &unit_add_deserialized_job_coldplug); + + return 0; + } +diff --git a/src/core/unit.h b/src/core/unit.h +index 291bc77a7..7ebc489c8 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -307,8 +307,14 @@ struct UnitVTable { + int (*load)(Unit *u); + + /* If a lot of units got created via enumerate(), this is +- * where to actually set the state and call unit_notify(). */ +- int (*coldplug)(Unit *u); ++ * where to actually set the state and call unit_notify(). ++ * ++ * This must not reference other units (maybe implicitly through spawning ++ * jobs), because it is possible that they are not yet coldplugged. ++ * Such actions must be deferred until the end of coldplug bу adding ++ * a "Unit* -> int(*)(Unit*)" entry into the hashmap. ++ */ ++ int (*coldplug)(Unit *u, Hashmap *deferred_work); + + void (*dump)(Unit *u, FILE *f, const char *prefix); + +@@ -544,7 +550,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds); + + int unit_add_node_link(Unit *u, const char *what, bool wants); + +-int unit_coldplug(Unit *u); ++int unit_coldplug(Unit *u, Hashmap *deferred_work); + + void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0); + diff --git a/SOURCES/0080-firstboot-set-all-spwd-fields-to-1-for-consistency-w.patch b/SOURCES/0080-firstboot-set-all-spwd-fields-to-1-for-consistency-w.patch new file mode 100644 index 00000000..7ed65ee1 --- /dev/null +++ b/SOURCES/0080-firstboot-set-all-spwd-fields-to-1-for-consistency-w.patch @@ -0,0 +1,28 @@ +From 5857b7843b35d84f976a399765f1c9a5365742a2 Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Thu, 26 Feb 2015 02:46:24 +0300 +Subject: [PATCH] firstboot: set all spwd fields to -1 for consistency with + sysusers + +(cherry picked from commit ad525df851a1bef7369fe21b5cde382941e7b073) +--- + src/firstboot/firstboot.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c +index a765d6d21..a37ca170f 100644 +--- a/src/firstboot/firstboot.c ++++ b/src/firstboot/firstboot.c +@@ -525,9 +525,9 @@ static int process_root_password(void) { + + struct spwd item = { + .sp_namp = (char*) "root", +- .sp_min = 0, +- .sp_max = 99999, +- .sp_warn = 7, ++ .sp_min = -1, ++ .sp_max = -1, ++ .sp_warn = -1, + .sp_inact = -1, + .sp_expire = -1, + .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ diff --git a/SOURCES/0081-sysusers-do-not-reject-users-with-already-present-et.patch b/SOURCES/0081-sysusers-do-not-reject-users-with-already-present-et.patch new file mode 100644 index 00000000..42754c79 --- /dev/null +++ b/SOURCES/0081-sysusers-do-not-reject-users-with-already-present-et.patch @@ -0,0 +1,77 @@ +From 169e74d772eac561a24f461ac65118d3d83a5980 Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Sat, 7 Mar 2015 18:11:32 +0300 +Subject: [PATCH] sysusers: do not reject users with already present + /etc/shadow entries + +This is needed to interoperate firstboot and sysusers. The former one is started +first, and it writes only /etc/shadow when it is told to set the root password. +It's better to relax checks here than to duplicate functionality in firstboot. + +(cherry picked from commit c5abf22514b3925aa6f0d4a3f36f76799bf1911b) +--- + src/sysusers/sysusers.c | 23 +++++++++-------------- + 1 file changed, 9 insertions(+), 14 deletions(-) + +diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c +index e47bcb4dc..76b5962c5 100644 +--- a/src/sysusers/sysusers.c ++++ b/src/sysusers/sysusers.c +@@ -605,6 +605,8 @@ static int write_files(void) { + if (r < 0) + goto finish; + ++ lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); ++ + original = fopen(shadow_path, "re"); + if (original) { + struct spwd *sp; +@@ -618,8 +620,13 @@ static int write_files(void) { + + i = hashmap_get(users, sp->sp_namp); + if (i && i->todo_user) { +- r = -EEXIST; +- goto finish; ++ /* we will update the existing entry */ ++ sp->sp_lstchg = lstchg; ++ ++ /* only the /etc/shadow stage is left, so we can ++ * safely remove the item from the todo set */ ++ i->todo_user = false; ++ hashmap_remove(todo_uids, UID_TO_PTR(i->uid)); + } + + errno = 0; +@@ -642,7 +649,6 @@ static int write_files(void) { + goto finish; + } + +- lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); + HASHMAP_FOREACH(i, todo_uids, iterator) { + struct spwd n = { + .sp_namp = i->name, +@@ -879,7 +885,6 @@ static int add_user(Item *i) { + + if (!arg_root) { + struct passwd *p; +- struct spwd *sp; + + /* Also check NSS */ + errno = 0; +@@ -895,16 +900,6 @@ static int add_user(Item *i) { + } + if (!IN_SET(errno, 0, ENOENT)) + return log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name); +- +- /* And shadow too, just to be sure */ +- errno = 0; +- sp = getspnam(i->name); +- if (sp) { +- log_error("User %s already exists in shadow database, but not in user database.", i->name); +- return -EBADMSG; +- } +- if (!IN_SET(errno, 0, ENOENT)) +- return log_error_errno(errno, "Failed to check if user %s already exists in shadow database: %m", i->name); + } + + /* Try to use the suggested numeric uid */ diff --git a/SOURCES/0082-nspawn-fix-use-after-free-and-leak-in-error-paths.patch b/SOURCES/0082-nspawn-fix-use-after-free-and-leak-in-error-paths.patch new file mode 100644 index 00000000..365ea8c6 --- /dev/null +++ b/SOURCES/0082-nspawn-fix-use-after-free-and-leak-in-error-paths.patch @@ -0,0 +1,40 @@ +From 28b5692e9ab3dbb07e4d6b8e44b370637c04ba86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 7 Mar 2015 14:19:20 -0500 +Subject: [PATCH] nspawn: fix use-after-free and leak in error paths + +CID #1257765. + +(cherry picked from commit 8a16a7b4e7f6702a7e6edaead80ecf04be7d3ba2) +--- + src/nspawn/nspawn.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 7724df96b..78bd58483 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -3627,7 +3627,7 @@ int main(int argc, char *argv[]) { + } + + if (arg_ephemeral) { +- char *np; ++ _cleanup_free_ char *np = NULL; + + /* If the specified path is a mount point we + * generate the new snapshot immediately +@@ -3657,13 +3657,13 @@ int main(int argc, char *argv[]) { + + r = btrfs_subvol_snapshot(arg_directory, np, arg_read_only, true); + if (r < 0) { +- free(np); + log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory); + goto finish; + } + + free(arg_directory); + arg_directory = np; ++ np = NULL; + + remove_subvol = true; + diff --git a/SOURCES/0083-login-fix-copy-pasto-in-error-path.patch b/SOURCES/0083-login-fix-copy-pasto-in-error-path.patch new file mode 100644 index 00000000..9b65c082 --- /dev/null +++ b/SOURCES/0083-login-fix-copy-pasto-in-error-path.patch @@ -0,0 +1,25 @@ +From d67968957aece7a1d4da581d86ad719c9a7fad21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 7 Mar 2015 14:23:38 -0500 +Subject: [PATCH] login: fix copy-pasto in error path + +CID #1256583. + +(cherry picked from commit dcee01125dde502bd8108c36ddf2026c1348865f) +--- + src/login/inhibit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/login/inhibit.c b/src/login/inhibit.c +index 44bda34af..88af23e35 100644 +--- a/src/login/inhibit.c ++++ b/src/login/inhibit.c +@@ -260,7 +260,7 @@ int main(int argc, char *argv[]) { + + fd = inhibit(bus, &error); + if (fd < 0) { +- log_error("Failed to inhibit: %s", bus_error_message(&error, -r)); ++ log_error("Failed to inhibit: %s", bus_error_message(&error, fd)); + return EXIT_FAILURE; + } + diff --git a/SOURCES/0084-journalctl-update-hint-now-that-we-set-ACL-everywher.patch b/SOURCES/0084-journalctl-update-hint-now-that-we-set-ACL-everywher.patch new file mode 100644 index 00000000..76156cb9 --- /dev/null +++ b/SOURCES/0084-journalctl-update-hint-now-that-we-set-ACL-everywher.patch @@ -0,0 +1,63 @@ +From cf04c51fb2d5ce08a8b8aafec999e2007ef53c83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 8 Mar 2015 11:04:59 -0400 +Subject: [PATCH] journalctl: update hint now that we set ACL everywhere + +(cherry picked from commit 05c1853093d8c4e4aa16876b5129b65dac5abd01) +--- + src/journal/journalctl.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 55c778633..12c869f5a 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1542,10 +1542,17 @@ static int access_check_var_log_journal(sd_journal *j) { + have_access = in_group("systemd-journal") > 0; + + if (!have_access) { ++ const char* dir; ++ ++ if (access("/run/log/journal", F_OK) >= 0) ++ dir = "/run/log/journal"; ++ else ++ dir = "/var/log/journal"; ++ + /* Let's enumerate all groups from the default ACL of + * the directory, which generally should allow access + * to most journal files too */ +- r = search_acl_groups(&g, "/var/log/journal/", &have_access); ++ r = search_acl_groups(&g, dir, &have_access); + if (r < 0) + return r; + } +@@ -1571,7 +1578,7 @@ static int access_check_var_log_journal(sd_journal *j) { + return log_oom(); + + log_notice("Hint: You are currently not seeing messages from other users and the system.\n" +- " Users in the groups '%s' can see all messages.\n" ++ " Users in groups '%s' can see all messages.\n" + " Pass -q to turn off this notice.", s); + } + } +@@ -1595,18 +1602,8 @@ static int access_check(sd_journal *j) { + + if (set_contains(j->errors, INT_TO_PTR(-EACCES))) { + #ifdef HAVE_ACL +- /* If /var/log/journal doesn't even exist, +- * unprivileged users have no access at all */ +- if (access("/var/log/journal", F_OK) < 0 && +- geteuid() != 0 && +- in_group("systemd-journal") <= 0) { +- log_error("Unprivileged users cannot access messages, unless persistent log storage is\n" +- "enabled. Users in the 'systemd-journal' group may always access messages."); +- return -EACCES; +- } +- +- /* If /var/log/journal exists, try to pring a nice +- notice if the user lacks access to it */ ++ /* If /run/log/journal or /var/log/journal exist, try ++ to pring a nice notice if the user lacks access to it. */ + if (!arg_quiet && geteuid() != 0) { + r = access_check_var_log_journal(j); + if (r < 0) diff --git a/SOURCES/0085-sd-journal-return-error-when-we-cannot-open-a-file.patch b/SOURCES/0085-sd-journal-return-error-when-we-cannot-open-a-file.patch new file mode 100644 index 00000000..acb14c39 --- /dev/null +++ b/SOURCES/0085-sd-journal-return-error-when-we-cannot-open-a-file.patch @@ -0,0 +1,26 @@ +From 5633544097b9c3bf3d63ef3be9e7db5d4e1f49dc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 8 Mar 2015 11:11:50 -0400 +Subject: [PATCH] sd-journal: return error when we cannot open a file + +Lack of this caused journalctl not to display a hint about missing groups +properly when the user lacks permissions. + +(cherry picked from commit 7b300be75e6d5755778dd7da63e7147866f21351) +--- + src/journal/sd-journal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 9b57e5945..9b9e8ac85 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -1248,7 +1248,7 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { + r = add_any_file(j, path); + if (r == -ENOENT) + return 0; +- return 0; ++ return r; + } + + static int remove_file(sd_journal *j, const char *prefix, const char *filename) { diff --git a/SOURCES/0086-missing.h-add-NDA_.patch b/SOURCES/0086-missing.h-add-NDA_.patch new file mode 100644 index 00000000..7a138dfd --- /dev/null +++ b/SOURCES/0086-missing.h-add-NDA_.patch @@ -0,0 +1,70 @@ +From eceb99d70a7c0916cb626dfbcb50894e1f4e9431 Mon Sep 17 00:00:00 2001 +From: Michael Olbrich +Date: Mon, 9 Mar 2015 12:27:25 +0100 +Subject: [PATCH] missing.h: add NDA_* + +This is necessary to build with older kernel headers. NDA_VLAN was +introduced in v3.9 and NDA_PORT, NDA_VNI and NDA_IFINDEX in v3.10 + +(cherry picked from commit cf1755bac0426132c21fdca519a336ce7d920277) +--- + configure.ac | 4 +++- + src/shared/missing.h | 16 ++++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 3201428c4..081ed0f6e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -334,7 +334,8 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, + IFLA_VXLAN_LOCAL6, + IFLA_IPTUN_6RD_RELAY_PREFIXLEN, + IFLA_BRIDGE_VLAN_INFO, +- IFLA_BRPORT_UNICAST_FLOOD], ++ IFLA_BRPORT_UNICAST_FLOOD, ++ NDA_IFINDEX], + [], [], [[ + #include + #include +@@ -345,6 +346,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, + #include + #include + #include ++#include + ]]) + + # This makes sure pkg.m4 is available. +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 8cb0b2c96..6ef4dbdf4 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #ifdef HAVE_AUDIT + #include +@@ -687,6 +688,21 @@ static inline int setns(int fd, int nstype) { + #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) + #endif + ++#if !HAVE_DECL_NDA_IFINDEX ++#define NDA_UNSPEC 0 ++#define NDA_DST 1 ++#define NDA_LLADDR 2 ++#define NDA_CACHEINFO 3 ++#define NDA_PROBES 4 ++#define NDA_VLAN 5 ++#define NDA_PORT 6 ++#define NDA_VNI 7 ++#define NDA_IFINDEX 8 ++#define __NDA_MAX 9 ++ ++#define NDA_MAX (__NDA_MAX - 1) ++#endif ++ + #ifndef IPV6_UNICAST_IF + #define IPV6_UNICAST_IF 76 + #endif diff --git a/SOURCES/0087-udevd-close-race-in-udev-settle.patch b/SOURCES/0087-udevd-close-race-in-udev-settle.patch new file mode 100644 index 00000000..f9c94c79 --- /dev/null +++ b/SOURCES/0087-udevd-close-race-in-udev-settle.patch @@ -0,0 +1,85 @@ +From 175c446fc5ca6adbeeb25dfe0ef725e2f1914259 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 9 Mar 2015 16:16:23 +0100 +Subject: [PATCH] udevd: close race in udev settle + +The udev-settle guarantees that udevd is no longer processing any of the +events casued by udev-trigger. The way this works is that it sends a +synchronous PING to udevd after udev-trigger has ran, and when that returns +it knows that udevd has started processing the events from udev-trigger. +udev-settle will then wait for the event queue to empty before returning. + +However, there was a race here, as we would only update the /run state at +the beginning of the event loop, before reading out new events and before +processing the ping. + +That means that if the first uevent arrived in the same event-loop iteration +as the PING, we would return the ping before updating the queue state in /run +(which would happen on the next iteration). + +The race window here is tiny (as the /run state would probably get updated +before udev-settle got a chance to read /run), but still a possibility. + +Fix the problem by updating the /run state as the last step before returning +the PING. + +We must still update it at the beginning of the loop as well, otherwise we +risk being stuck in poll() with a stale state in /run. + +Reported-by: Daniel Drake +(cherry picked from commit db93e063bdffe0a8b95fcc522aeacddf62d1a9f9) +--- + src/udev/udevd.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 99d4c8983..e98c1fd6d 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -909,6 +909,17 @@ static void handle_signal(struct udev *udev, int signo) { + } + } + ++static void event_queue_update(void) { ++ if (!udev_list_node_is_empty(&event_list)) { ++ int fd; ++ ++ fd = open("/run/udev/queue", O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); ++ if (fd >= 0) ++ close(fd); ++ } else ++ unlink("/run/udev/queue"); ++} ++ + static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) { + int ctrl = -1, netlink = -1; + int fd, n; +@@ -1369,15 +1380,7 @@ int main(int argc, char *argv[]) { + } + + /* tell settle that we are busy or idle */ +- if (!udev_list_node_is_empty(&event_list)) { +- int fd; +- +- fd = open("/run/udev/queue", O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); +- if (fd >= 0) +- close(fd); +- } else { +- unlink("/run/udev/queue"); +- } ++ event_queue_update(); + + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout); + if (fdcount < 0) +@@ -1502,6 +1505,11 @@ int main(int argc, char *argv[]) { + if (is_inotify) + handle_inotify(udev); + ++ /* tell settle that we are busy or idle, this needs to be before the ++ * PING handling ++ */ ++ event_queue_update(); ++ + /* + * This needs to be after the inotify handling, to make sure, + * that the ping is send back after the possibly generated diff --git a/SOURCES/0088-man-document-that-ExecStartPre-is-not-the-place-to-s.patch b/SOURCES/0088-man-document-that-ExecStartPre-is-not-the-place-to-s.patch new file mode 100644 index 00000000..1c575a53 --- /dev/null +++ b/SOURCES/0088-man-document-that-ExecStartPre-is-not-the-place-to-s.patch @@ -0,0 +1,27 @@ +From 1c8b76caab7d5164ac2d0d09aff9e4ffecdf205e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 9 Mar 2015 18:01:47 +0100 +Subject: [PATCH] man: document that ExecStartPre= is not the place to start + long-running processes + +(cherry picked from commit b481de3b22fcd838a8f059aed8745375afdb9eca) +--- + man/systemd.service.xml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index c03b4e8a5..f59870563 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -334,6 +334,11 @@ + If any of those commands (not prefixed with + -) fail, the rest are not executed and the + unit is considered failed. ++ ++ Note that ExecStartPre= may not be ++ used to start long-running processes. All processes forked ++ off by processes invoked via ExecStartPre= will ++ be killed before the next service process is run. + + + diff --git a/SOURCES/0089-journal-fix-return-code.patch b/SOURCES/0089-journal-fix-return-code.patch new file mode 100644 index 00000000..181e296a --- /dev/null +++ b/SOURCES/0089-journal-fix-return-code.patch @@ -0,0 +1,31 @@ +From 185e6b251907bdf6adc63866f38722e9fb3d3715 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 9 Mar 2015 17:46:30 -0400 +Subject: [PATCH] journal: fix return code + +Introduced in fa6ac76083b8ff. + +Might be related to CID #1261724, but I don't know if coverity can +recurse this deep. + +(cherry picked from commit 977eaa1eae53af7f418d87fcb42f4a4d34aad739) +--- + src/journal/journal-file.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 24c49b916..f500568fe 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -2652,10 +2652,8 @@ int journal_file_open( + } + + r = mmap_cache_get(f->mmap, f->fd, f->prot, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h); +- if (r < 0) { +- r = -errno; ++ if (r < 0) + goto fail; +- } + + f->header = h; + diff --git a/SOURCES/0090-console-fix-error-code-inversion.patch b/SOURCES/0090-console-fix-error-code-inversion.patch new file mode 100644 index 00000000..9a1c7973 --- /dev/null +++ b/SOURCES/0090-console-fix-error-code-inversion.patch @@ -0,0 +1,27 @@ +From 6e2893aa4e1d6471b174e56c5132da31f890d620 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 16 Dec 2014 16:14:48 +0100 +Subject: [PATCH] console: fix error-code inversion + +The error-code propagated via sysview is always negative. Avoid +multiplying by -1 before returning it. Otherwise, we will return >0 +instead of <0, which will not be detected as error by sysview-core. + +(cherry picked from commit 84c3561c58dd992b339afe5bb4c41971a2ebc486) +--- + src/console/consoled-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/console/consoled-manager.c b/src/console/consoled-manager.c +index 9dd62f04a..25de0a218 100644 +--- a/src/console/consoled-manager.c ++++ b/src/console/consoled-manager.c +@@ -228,7 +228,7 @@ static int manager_sysview_session_control(Manager *m, sysview_event *event) { + sysview_session_get_name(session)); + session_free(s); + sysview_session_set_userdata(session, NULL); +- return -error; ++ return error; + } + + return 0; diff --git a/SOURCES/0091-bus-proxy-complain-only-once-about-queue-overflows.patch b/SOURCES/0091-bus-proxy-complain-only-once-about-queue-overflows.patch new file mode 100644 index 00000000..22e3e42e --- /dev/null +++ b/SOURCES/0091-bus-proxy-complain-only-once-about-queue-overflows.patch @@ -0,0 +1,72 @@ +From 4c6c21f92a8204abf031e42bb4949a0ecf039f7a Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 11 Mar 2015 13:53:21 +0100 +Subject: [PATCH] bus-proxy: complain only once about queue overflows + +If the local peer does not dispatch its incoming queue, the bus-proxy will +slowly fill its outgoing queue. Once its full, it will continously +complain that it cannot forward its messages. + +As it turns out, pulseaudio does have an idle background dbus connection +that is not integrated into any mainloop (and given that gdbus and +libdbus1 both support background shared connections, PA is probably not +the only example), therefore, the bus-proxy will loudly complain if it +cannot forward NameOwnerChanged events once the queue is full. + +This commit makes the proxy track queue-state and complain only once the +queue runs full, not if it is already full. + +A PA bug-report (and patch) has been filed, and other applications should +be fixed similarly. Hence, lets keep the error message, instead of +dropping it. It's unused resources we really want to get rid of, so +silencing the message does not really help (which is actually what +dbus-daemon does). + +(cherry picked from commit ec2c7b56599981a7d9e76b15c75af3e1af3e6f81) +--- + src/bus-proxyd/proxy.c | 16 ++++++++++++---- + src/bus-proxyd/proxy.h | 1 + + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c +index 3dea908f5..e13cf5e2e 100644 +--- a/src/bus-proxyd/proxy.c ++++ b/src/bus-proxyd/proxy.c +@@ -729,13 +729,21 @@ static int proxy_process_destination_to_local(Proxy *p) { + + /* Return the error to the client, if we can */ + synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m"); +- log_error_errno(r, +- "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m", +- p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type), +- strna(m->destination), strna(m->path), strna(m->interface), strna(m->member)); ++ if (r == -ENOBUFS) { ++ /* if local dbus1 peer does not dispatch its queue, warn only once */ ++ if (!p->queue_overflow) ++ log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid); ++ p->queue_overflow = true; ++ } else ++ log_error_errno(r, ++ "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m", ++ p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type), ++ strna(m->destination), strna(m->path), strna(m->interface), strna(m->member)); ++ + return 1; + } + ++ p->queue_overflow = false; + return 1; + } + +diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h +index 913d47071..782c4e60b 100644 +--- a/src/bus-proxyd/proxy.h ++++ b/src/bus-proxyd/proxy.h +@@ -40,6 +40,7 @@ struct Proxy { + SharedPolicy *policy; + + bool got_hello : 1; ++ bool queue_overflow : 1; + }; + + int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest); diff --git a/SOURCES/0092-cgtop-fix-assert-when-not-on-tty.patch b/SOURCES/0092-cgtop-fix-assert-when-not-on-tty.patch new file mode 100644 index 00000000..cf4fcf07 --- /dev/null +++ b/SOURCES/0092-cgtop-fix-assert-when-not-on-tty.patch @@ -0,0 +1,31 @@ +From 33088d83ecaf03611e3d20a893e675e4d7c3ae9a Mon Sep 17 00:00:00 2001 +From: Umut Tezduyar Lindskog +Date: Wed, 11 Mar 2015 11:24:18 +0100 +Subject: [PATCH] cgtop: fix assert when not on tty + +systemd-cgtop --dept=1 -b -n 10 -d 0.1 | cat + +Assertion 'new_length >= 3' failed at src/shared/util.c:3 \ +595, function ellipsize_mem(). Aborting. +Aborted (core dumped) + +(David: add comment) + +(cherry picked from commit 510c4a0f1e7e7efe2897d2fbb9067f121467b103) +--- + src/cgtop/cgtop.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c +index 3c7ad4060..f951c37cb 100644 +--- a/src/cgtop/cgtop.c ++++ b/src/cgtop/cgtop.c +@@ -447,7 +447,7 @@ static int display(Hashmap *a) { + Group *g; + Group **array; + signed path_columns; +- unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 0; ++ unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */ + char buffer[MAX3(21, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)]; + + assert(a); diff --git a/SOURCES/0093-man-split-paragraph.patch b/SOURCES/0093-man-split-paragraph.patch new file mode 100644 index 00000000..710bca8d --- /dev/null +++ b/SOURCES/0093-man-split-paragraph.patch @@ -0,0 +1,28 @@ +From 682a699e71147673f8de5fa12dbec8f2a4c28d9c Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 12 Mar 2015 12:46:46 +0100 +Subject: [PATCH] man: split paragraph + +Explicitly put the "multiple EnvironmentFile=" description into its own +paragraph to make it much easier to find. + +(cherry picked from commit f407824d751a9cb31abfdf0343fe179e0efef259) +--- + man/systemd.exec.xml | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 11b160e58..fdb157864 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -283,7 +283,9 @@ + shortly before the process is executed (more specifically, + after all processes from a previous unit state terminated. + This means you can generate these files in one unit state, and +- read it with this option in the next). Settings from these ++ read it with this option in the next). ++ ++ Settings from these + files override settings made with + Environment=. If the same variable is set + twice from these files, the files will be read in the order diff --git a/SOURCES/0094-hwdb-update.patch b/SOURCES/0094-hwdb-update.patch new file mode 100644 index 00000000..85fd5c3e --- /dev/null +++ b/SOURCES/0094-hwdb-update.patch @@ -0,0 +1,3156 @@ +From 31eb7c2966a9a52b57cc4ac1f678c9149b8e57ed Mon Sep 17 00:00:00 2001 +From: Kay Sievers +Date: Thu, 12 Mar 2015 18:34:23 +0100 +Subject: [PATCH] hwdb: update + +(cherry picked from commit b83cbcb7d95482baa588706227f01bbbe44b9d12) +--- + hwdb/20-OUI.hwdb | 247 ++++++++++- + hwdb/20-pci-vendor-model.hwdb | 936 +++++++++++++++++++++++++++-------------- + hwdb/20-sdio-vendor-model.hwdb | 30 ++ + hwdb/20-usb-vendor-model.hwdb | 181 +++++++- + 4 files changed, 1060 insertions(+), 334 deletions(-) + +diff --git a/hwdb/20-OUI.hwdb b/hwdb/20-OUI.hwdb +index 6976bdf64..deb323d34 100644 +--- a/hwdb/20-OUI.hwdb ++++ b/hwdb/20-OUI.hwdb +@@ -28829,7 +28829,7 @@ OUI:0013EB* + ID_OUI_FROM_DATABASE=Sysmaster Corporation + + OUI:0013EC* +- ID_OUI_FROM_DATABASE=Sunbay Software AG ++ ID_OUI_FROM_DATABASE=Netsnapper Technologies SARL + + OUI:0013ED* + ID_OUI_FROM_DATABASE=PSIA +@@ -44296,6 +44296,9 @@ OUI:0030FE* + OUI:0030FF* + ID_OUI_FROM_DATABASE=DATAFAB SYSTEMS, INC. + ++OUI:00323A* ++ ID_OUI_FROM_DATABASE=so-logic ++ + OUI:00336C* + ID_OUI_FROM_DATABASE=SynapSense Corporation + +@@ -44513,7 +44516,7 @@ OUI:004035* + ID_OUI_FROM_DATABASE=OPCOM + + OUI:004036* +- ID_OUI_FROM_DATABASE=TRIBE COMPUTER WORKS, INC. ++ ID_OUI_FROM_DATABASE=Zoom Telephonics, Inc + + OUI:004037* + ID_OUI_FROM_DATABASE=SEA-ILAN, INC. +@@ -50456,7 +50459,7 @@ OUI:00D093* + ID_OUI_FROM_DATABASE=TQ - COMPONENTS GMBH + + OUI:00D094* +- ID_OUI_FROM_DATABASE=TIMELINE VISTA, INC. ++ ID_OUI_FROM_DATABASE=Seeion Control LLC + + OUI:00D095* + ID_OUI_FROM_DATABASE=Alcatel-Lucent, Enterprise Business Group +@@ -52561,6 +52564,9 @@ OUI:082719* + OUI:082AD0* + ID_OUI_FROM_DATABASE=SRD Innovations Inc. + ++OUI:082CB0* ++ ID_OUI_FROM_DATABASE=Network Instruments ++ + OUI:082E5F* + ID_OUI_FROM_DATABASE=Hewlett Packard + +@@ -52699,6 +52705,9 @@ OUI:088E4F* + OUI:088F2C* + ID_OUI_FROM_DATABASE=Hills Sound Vision & Lighting + ++OUI:08952A* ++ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc ++ + OUI:0896D7* + ID_OUI_FROM_DATABASE=AVM GmbH + +@@ -52804,6 +52813,9 @@ OUI:08EB74* + OUI:08EBED* + ID_OUI_FROM_DATABASE=World Elite Technology Co.,LTD + ++OUI:08ECA9* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:08EDB9* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +@@ -53320,6 +53332,9 @@ OUI:103DEA* + OUI:1040F3* + ID_OUI_FROM_DATABASE=Apple + ++OUI:10417F* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:104369* + ID_OUI_FROM_DATABASE=Soundmax Electronic Limited + +@@ -53611,6 +53626,9 @@ OUI:141330* + OUI:14144B* + ID_OUI_FROM_DATABASE=FUJIAN STAR-NET COMMUNICATION CO.,LTD + ++OUI:14157C* ++ ID_OUI_FROM_DATABASE=TOKYO COSMOS ELECTRIC CO.,LTD. ++ + OUI:141A51* + ID_OUI_FROM_DATABASE=Treetech Sistemas Digitais + +@@ -53656,6 +53674,9 @@ OUI:14307A* + OUI:1430C6* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC + ++OUI:1432D1* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:14358B* + ID_OUI_FROM_DATABASE=Mediabridge Products, LLC. + +@@ -53716,6 +53737,9 @@ OUI:1458D0* + OUI:145A05* + ID_OUI_FROM_DATABASE=Apple + ++OUI:145A83* ++ ID_OUI_FROM_DATABASE=Logi-D inc ++ + OUI:145BD1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +@@ -53929,6 +53953,9 @@ OUI:181420* + OUI:181456* + ID_OUI_FROM_DATABASE=Nokia Corporation + ++OUI:1816C9* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:181714* + ID_OUI_FROM_DATABASE=DAEWOOIS + +@@ -54049,6 +54076,9 @@ OUI:185936* + OUI:185AE8* + ID_OUI_FROM_DATABASE=Zenotech.Co.,Ltd + ++OUI:185D9A* ++ ID_OUI_FROM_DATABASE=BobjGear LLC ++ + OUI:18622C* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +@@ -54532,6 +54562,9 @@ OUI:1CAB01* + OUI:1CABA7* + ID_OUI_FROM_DATABASE=Apple + ++OUI:1CADD1* ++ ID_OUI_FROM_DATABASE=Bosung Electronics Co., Ltd. ++ + OUI:1CAF05* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +@@ -54937,6 +54970,9 @@ OUI:20DCE6* + OUI:20DF3F* + ID_OUI_FROM_DATABASE=Nanjing SAC Power Grid Automation Co., Ltd. + ++OUI:20E407* ++ ID_OUI_FROM_DATABASE=Spark srl ++ + OUI:20E52A* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +@@ -55252,6 +55288,9 @@ OUI:24E271* + OUI:24E314* + ID_OUI_FROM_DATABASE=Apple + ++OUI:24E5AA* ++ ID_OUI_FROM_DATABASE=Philips Oral Healthcare, Inc. ++ + OUI:24E6BA* + ID_OUI_FROM_DATABASE=JSC Zavod im. Kozitsky + +@@ -56185,6 +56224,9 @@ OUI:308730* + OUI:308999* + ID_OUI_FROM_DATABASE=Guangdong East Power Co., + ++OUI:3089D3* ++ ID_OUI_FROM_DATABASE=Shenzhen ucloudlink new technology co.,LTD ++ + OUI:308CFB* + ID_OUI_FROM_DATABASE=Dropcam + +@@ -56461,6 +56503,9 @@ OUI:3476C5* + OUI:347877* + ID_OUI_FROM_DATABASE=O-NET Communications(Shenzhen) Limited + ++OUI:347A60* ++ ID_OUI_FROM_DATABASE=Pace plc ++ + OUI:347E39* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +@@ -56506,6 +56551,9 @@ OUI:3499D7* + OUI:349A0D* + ID_OUI_FROM_DATABASE=ZBD Displays Ltd + ++OUI:349B5B* ++ ID_OUI_FROM_DATABASE=Maquet GmbH ++ + OUI:349D90* + ID_OUI_FROM_DATABASE=Heinzmann GmbH & CO. KG + +@@ -57256,6 +57304,9 @@ OUI:3CA10D* + OUI:3CA315* + ID_OUI_FROM_DATABASE=Bless Information & Communications Co., Ltd + ++OUI:3CA31A* ++ ID_OUI_FROM_DATABASE=Oilfind International LLC ++ + OUI:3CA72B* + ID_OUI_FROM_DATABASE=MRV Communications (Networks) LTD + +@@ -57343,6 +57394,9 @@ OUI:3CD92B* + OUI:3CD9CE* + ID_OUI_FROM_DATABASE=Eclipse WiFi + ++OUI:3CDA2A* ++ ID_OUI_FROM_DATABASE=zte corporation ++ + OUI:3CDF1E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +@@ -57592,6 +57646,9 @@ OUI:408B07* + OUI:408BF6* + ID_OUI_FROM_DATABASE=Shenzhen TCL New Technology Co; Ltd. + ++OUI:408D5C* ++ ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. ++ + OUI:409558* + ID_OUI_FROM_DATABASE=Aisino Corporation + +@@ -58093,6 +58150,9 @@ OUI:44ED57* + OUI:44EE30* + ID_OUI_FROM_DATABASE=Budelmann Elektronik GmbH + ++OUI:44F436* ++ ID_OUI_FROM_DATABASE=zte corporation ++ + OUI:44F459* + ID_OUI_FROM_DATABASE=Samsung Electronics + +@@ -58117,6 +58177,9 @@ OUI:48066A* + OUI:480C49* + ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS,INC + ++OUI:480FCF* ++ ID_OUI_FROM_DATABASE=Hewlett Packard ++ + OUI:481249* + ID_OUI_FROM_DATABASE=Luxcom Technologies Inc. + +@@ -58171,6 +58234,9 @@ OUI:4846F1* + OUI:4846FB* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + ++OUI:485073* ++ ID_OUI_FROM_DATABASE=Microsoft Corporation ++ + OUI:4851B7* + ID_OUI_FROM_DATABASE=Intel Corporate + +@@ -58636,6 +58702,9 @@ OUI:4CB199* + OUI:4CB4EA* + ID_OUI_FROM_DATABASE=HRD (S) PTE., LTD. + ++OUI:4CB76D* ++ ID_OUI_FROM_DATABASE=Novi Security ++ + OUI:4CB81C* + ID_OUI_FROM_DATABASE=SAM Electronics GmbH + +@@ -58705,6 +58774,9 @@ OUI:4CEB42* + OUI:4CEDDE* + ID_OUI_FROM_DATABASE=Askey Computer Corp + ++OUI:4CEEB0* ++ ID_OUI_FROM_DATABASE=SHC Netzwerktechnik GmbH ++ + OUI:4CF02E* + ID_OUI_FROM_DATABASE=Vifa Denmark A/S + +@@ -59032,6 +59104,9 @@ OUI:50ED94* + OUI:50F003* + ID_OUI_FROM_DATABASE=Open Stack, Inc. + ++OUI:50F0D3* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:50F43C* + ID_OUI_FROM_DATABASE=Leeo Inc + +@@ -59137,6 +59212,9 @@ OUI:5439DF* + OUI:543D37* + ID_OUI_FROM_DATABASE=Ruckus Wireless + ++OUI:5440AD* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:544249* + ID_OUI_FROM_DATABASE=Sony Corporation + +@@ -59170,6 +59248,9 @@ OUI:545EBD* + OUI:545FA9* + ID_OUI_FROM_DATABASE=Teracom Limited + ++OUI:546172* ++ ID_OUI_FROM_DATABASE=ZODIAC AEROSPACE SAS ++ + OUI:5461EA* + ID_OUI_FROM_DATABASE=Zaplox AB + +@@ -59284,6 +59365,9 @@ OUI:54BEF7* + OUI:54C80F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + ++OUI:54CD10* ++ ID_OUI_FROM_DATABASE=Panasonic Mobile Communications Co.,Ltd. ++ + OUI:54CDA7* + ID_OUI_FROM_DATABASE=Fujian Shenzhou Electronic Co.,Ltd + +@@ -59794,6 +59878,9 @@ OUI:5C41E7* + OUI:5C43D2* + ID_OUI_FROM_DATABASE=HAZEMEYER + ++OUI:5C4527* ++ ID_OUI_FROM_DATABASE=Juniper Networks ++ + OUI:5C4A26* + ID_OUI_FROM_DATABASE=Enguity Technology Corp + +@@ -59911,6 +59998,9 @@ OUI:5CAAFD* + OUI:5CAC4C* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + ++OUI:5CB395* ++ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD ++ + OUI:5CB43E* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +@@ -60859,6 +60949,9 @@ OUI:64F970* + OUI:64F987* + ID_OUI_FROM_DATABASE=Avvasi Inc. + ++OUI:64FB81* ++ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information. ++ + OUI:64FC8C* + ID_OUI_FROM_DATABASE=Zonar Systems + +@@ -61417,6 +61510,9 @@ OUI:6C9CE9* + OUI:6C9CED* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + ++OUI:6CA100* ++ ID_OUI_FROM_DATABASE=Intel Corporate ++ + OUI:6CA682* + ID_OUI_FROM_DATABASE=EDAM information & communications + +@@ -61507,6 +61603,9 @@ OUI:6CD68A* + OUI:6CDC6A* + ID_OUI_FROM_DATABASE=Promethean Limited + ++OUI:6CE01E* ++ ID_OUI_FROM_DATABASE=Modcam AB ++ + OUI:6CE0B0* + ID_OUI_FROM_DATABASE=SOUND4 + +@@ -62119,6 +62218,9 @@ OUI:747E2D* + OUI:748114* + ID_OUI_FROM_DATABASE=Apple + ++OUI:74852A* ++ ID_OUI_FROM_DATABASE=PEGATRON CORPORATION ++ + OUI:74867A* + ID_OUI_FROM_DATABASE=Dell Inc + +@@ -62548,6 +62650,9 @@ OUI:789ED0* + OUI:789F4C* + ID_OUI_FROM_DATABASE=HOERBIGER Elektronik GmbH + ++OUI:789F70* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:789F87* + ID_OUI_FROM_DATABASE=Siemens AG I IA PP PRM + +@@ -62620,6 +62725,12 @@ OUI:78B81A* + OUI:78BAD0* + ID_OUI_FROM_DATABASE=Shinybow Technology Co. Ltd. + ++OUI:78BAF9* ++ ID_OUI_FROM_DATABASE=Cisco ++ ++OUI:78BDBC* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:78BEB6* + ID_OUI_FROM_DATABASE=Enhanced Vision + +@@ -63002,7 +63113,7 @@ OUI:7CB21B* + ID_OUI_FROM_DATABASE=Cisco SPVTG + + OUI:7CB232* +- ID_OUI_FROM_DATABASE=TCL King High Frequency EI,Co.,LTD ++ ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD + + OUI:7CB542* + ID_OUI_FROM_DATABASE=ACES Technology +@@ -63133,6 +63244,9 @@ OUI:7CF429* + OUI:7CF854* + ID_OUI_FROM_DATABASE=Samsung Electronics + ++OUI:7CF90E* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:7CFADF* + ID_OUI_FROM_DATABASE=Apple + +@@ -63235,6 +63349,9 @@ OUI:8038FD* + OUI:8039E5* + ID_OUI_FROM_DATABASE=PATLITE CORPORATION + ++OUI:803B2A* ++ ID_OUI_FROM_DATABASE=ABB Xiamen Low Voltage Equipment Co.,Ltd. ++ + OUI:803B9A* + ID_OUI_FROM_DATABASE=ghe-ces electronic ag + +@@ -63262,6 +63379,9 @@ OUI:804971* + OUI:804B20* + ID_OUI_FROM_DATABASE=Ventilation Control + ++OUI:804E81* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:804F58* + ID_OUI_FROM_DATABASE=ThinkEco, Inc. + +@@ -63514,6 +63634,9 @@ OUI:840B2D* + OUI:840F45* + ID_OUI_FROM_DATABASE=Shanghai GMT Digital Technologies Co., Ltd + ++OUI:84119E* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:841715* + ID_OUI_FROM_DATABASE=GP Electronics (HK) Ltd. + +@@ -63580,6 +63703,9 @@ OUI:842B50* + OUI:842BBC* + ID_OUI_FROM_DATABASE=Modelleisenbahn GmbH + ++OUI:842E27* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:842F75* + ID_OUI_FROM_DATABASE=Innokas Group + +@@ -63943,6 +64069,9 @@ OUI:883612* + OUI:883B8B* + ID_OUI_FROM_DATABASE=Cheering Connection Co. Ltd. + ++OUI:884157* ++ ID_OUI_FROM_DATABASE=Shenzhen Atsmart Technology Co.,Ltd. ++ + OUI:8841C1* + ID_OUI_FROM_DATABASE=ORBISAT DA AMAZONIA IND E AEROL SA + +@@ -64006,6 +64135,9 @@ OUI:88708C* + OUI:8870EF* + ID_OUI_FROM_DATABASE=SC Professional Trading Co., Ltd. + ++OUI:887384* ++ ID_OUI_FROM_DATABASE=Toshiba ++ + OUI:887398* + ID_OUI_FROM_DATABASE=K2E Tekpoint + +@@ -64039,6 +64171,9 @@ OUI:888B5D* + OUI:888C19* + ID_OUI_FROM_DATABASE=Brady Corp Asia Pacific Ltd + ++OUI:88908D* ++ ID_OUI_FROM_DATABASE=Cisco ++ + OUI:889166* + ID_OUI_FROM_DATABASE=Viewcooper Corp. + +@@ -64075,6 +64210,9 @@ OUI:889FFA* + OUI:88A25E* + ID_OUI_FROM_DATABASE=juniper networks + ++OUI:88A2D7* ++ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD ++ + OUI:88A3CC* + ID_OUI_FROM_DATABASE=Amatis Controls + +@@ -64591,6 +64729,9 @@ OUI:90203A* + OUI:902083* + ID_OUI_FROM_DATABASE=General Engine Management Systems Ltd. + ++OUI:902106* ++ ID_OUI_FROM_DATABASE=BSkyB Ltd ++ + OUI:902155* + ID_OUI_FROM_DATABASE=HTC Corporation + +@@ -64711,6 +64852,9 @@ OUI:9067F3* + OUI:9068C3* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC + ++OUI:906CAC* ++ ID_OUI_FROM_DATABASE=Fortinet, Inc. ++ + OUI:906DC8* + ID_OUI_FROM_DATABASE=DLG Automação Industrial Ltda + +@@ -65254,6 +65398,9 @@ OUI:94E711* + OUI:94E848* + ID_OUI_FROM_DATABASE=FYLDE MICRO LTD + ++OUI:94E96A* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:94E98C* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +@@ -65935,6 +66082,9 @@ OUI:9CF938* + OUI:9CFBF1* + ID_OUI_FROM_DATABASE=MESOMATIC GmbH & Co.KG + ++OUI:9CFC01* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:9CFFBE* + ID_OUI_FROM_DATABASE=OTSL Inc. + +@@ -65977,6 +66127,9 @@ OUI:A0143D* + OUI:A0165C* + ID_OUI_FROM_DATABASE=Triteka LTD + ++OUI:A01828* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:A01859* + ID_OUI_FROM_DATABASE=Shenzhen Yidashi Electronics Co Ltd + +@@ -66178,6 +66331,9 @@ OUI:A0A23C* + OUI:A0A3E2* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + ++OUI:A0A65C* ++ ID_OUI_FROM_DATABASE=Supercomputing Systems AG ++ + OUI:A0A763* + ID_OUI_FROM_DATABASE=Polytron Vertrieb GmbH + +@@ -66382,6 +66538,9 @@ OUI:A42305* + OUI:A424B3* + ID_OUI_FROM_DATABASE=FlatFrog Laboratories AB + ++OUI:A424DD* ++ ID_OUI_FROM_DATABASE=Cambrionix Ltd ++ + OUI:A4251B* + ID_OUI_FROM_DATABASE=Avaya, Inc + +@@ -66397,6 +66556,9 @@ OUI:A42B8C* + OUI:A42C08* + ID_OUI_FROM_DATABASE=Masterwork Automodules + ++OUI:A43135* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:A433D1* + ID_OUI_FROM_DATABASE=Fibrlink Communications Co.,Ltd. + +@@ -66475,6 +66637,9 @@ OUI:A46032* + OUI:A46706* + ID_OUI_FROM_DATABASE=Apple + ++OUI:A46C2A* ++ ID_OUI_FROM_DATABASE=Cisco ++ + OUI:A46CC1* + ID_OUI_FROM_DATABASE=LTi REEnergy GmbH + +@@ -67066,6 +67231,9 @@ OUI:AC20AA* + OUI:AC220B* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + ++OUI:AC293A* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:AC2DA3* + ID_OUI_FROM_DATABASE=TXTR GmbH + +@@ -67144,6 +67312,9 @@ OUI:AC562C* + OUI:AC583B* + ID_OUI_FROM_DATABASE=Human Assembler, Inc. + ++OUI:AC5A14* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:AC5D10* + ID_OUI_FROM_DATABASE=Pace Americas + +@@ -67153,6 +67324,9 @@ OUI:AC5E8C* + OUI:AC6123* + ID_OUI_FROM_DATABASE=Drivven, Inc. + ++OUI:AC620D* ++ ID_OUI_FROM_DATABASE=Jabil Circuit (Wuxi) Co. LTD ++ + OUI:AC6706* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +@@ -67180,6 +67354,9 @@ OUI:AC7289* + OUI:AC7A42* + ID_OUI_FROM_DATABASE=iConnectivity + ++OUI:AC7A4D* ++ ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. ++ + OUI:AC7BA1* + ID_OUI_FROM_DATABASE=Intel Corporate + +@@ -67402,6 +67579,9 @@ OUI:ACF7F3* + OUI:ACF97E* + ID_OUI_FROM_DATABASE=ELESYS INC. + ++OUI:ACFD93* ++ ID_OUI_FROM_DATABASE=Weifang GoerTek Electronics Co., Ltd. ++ + OUI:ACFDCE* + ID_OUI_FROM_DATABASE=Intel Corporate + +@@ -67688,7 +67868,7 @@ OUI:B0D59D* + ID_OUI_FROM_DATABASE=Shenzhen Zowee Technology Co., Ltd + + OUI:B0D7C5* +- ID_OUI_FROM_DATABASE=STP KFT ++ ID_OUI_FROM_DATABASE=Logipix Ltd + + OUI:B0DA00* + ID_OUI_FROM_DATABASE=CERA ELECTRONIQUE +@@ -67891,6 +68071,9 @@ OUI:B467E9* + OUI:B46D35* + ID_OUI_FROM_DATABASE=Dalian Seasky Automation Co;Ltd + ++OUI:B46D83* ++ ID_OUI_FROM_DATABASE=Intel Corporate ++ + OUI:B47356* + ID_OUI_FROM_DATABASE=Hangzhou Treebear Networking Co., Ltd. + +@@ -68569,6 +68752,9 @@ OUI:BC38D2* + OUI:BC39A6* + ID_OUI_FROM_DATABASE=CSUN System Technology Co.,LTD + ++OUI:BC3AEA* ++ ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD. ++ + OUI:BC3BAF* + ID_OUI_FROM_DATABASE=Apple + +@@ -69211,6 +69397,9 @@ OUI:C40F09* + OUI:C4108A* + ID_OUI_FROM_DATABASE=Ruckus Wireless + ++OUI:C412F5* ++ ID_OUI_FROM_DATABASE=D-Link International ++ + OUI:C413E2* + ID_OUI_FROM_DATABASE=Aerohive Networks Inc. + +@@ -69520,6 +69709,9 @@ OUI:C4E92F* + OUI:C4E984* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + ++OUI:C4EA1D* ++ ID_OUI_FROM_DATABASE=Technicolor ++ + OUI:C4EBE3* + ID_OUI_FROM_DATABASE=RRCN SAS + +@@ -69586,6 +69778,9 @@ OUI:C81B6B* + OUI:C81E8E* + ID_OUI_FROM_DATABASE=ADV Security (S) Pte Ltd + ++OUI:C81EE7* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:C81F66* + ID_OUI_FROM_DATABASE=Dell Inc + +@@ -69610,6 +69805,9 @@ OUI:C83232* + OUI:C8334B* + ID_OUI_FROM_DATABASE=Apple + ++OUI:C8348E* ++ ID_OUI_FROM_DATABASE=Intel Corporate ++ + OUI:C835B8* + ID_OUI_FROM_DATABASE=Ericsson, EAB/RWI/K + +@@ -70018,6 +70216,9 @@ OUI:CC4BFB* + OUI:CC4E24* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + ++OUI:CC4EEC* ++ ID_OUI_FROM_DATABASE=HUMAX Co., Ltd. ++ + OUI:CC501C* + ID_OUI_FROM_DATABASE=KVH Industries, Inc. + +@@ -70279,6 +70480,9 @@ OUI:CCFCB1* + OUI:CCFE3C* + ID_OUI_FROM_DATABASE=Samsung Electronics + ++OUI:D0034B* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:D00790* + ID_OUI_FROM_DATABASE=Texas Instruments + +@@ -70321,6 +70525,9 @@ OUI:D023DB* + OUI:D02516* + ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. + ++OUI:D02598* ++ ID_OUI_FROM_DATABASE=Apple Inc ++ + OUI:D02788* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd + +@@ -70342,6 +70549,9 @@ OUI:D03972* + OUI:D039B3* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + ++OUI:D0431E* ++ ID_OUI_FROM_DATABASE=Dell Inc. ++ + OUI:D046DC* + ID_OUI_FROM_DATABASE=Southwest Research Institute + +@@ -70501,6 +70711,9 @@ OUI:D09C30* + OUI:D09D0A* + ID_OUI_FROM_DATABASE=LINKCOM + ++OUI:D09DAB* ++ ID_OUI_FROM_DATABASE=TCT mobile ltd ++ + OUI:D0A0D6* + ID_OUI_FROM_DATABASE=Chengdu TD Tech Ltd. + +@@ -71266,6 +71479,9 @@ OUI:D8977C* + OUI:D897BA* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + ++OUI:D89A34* ++ ID_OUI_FROM_DATABASE=Beijing SHENQI Technology Co., Ltd. ++ + OUI:D89D67* + ID_OUI_FROM_DATABASE=Hewlett Packard + +@@ -72028,6 +72244,9 @@ OUI:E0D9A2* + OUI:E0DADC* + ID_OUI_FROM_DATABASE=JVC KENWOOD Corporation + ++OUI:E0DB10* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:E0DB55* + ID_OUI_FROM_DATABASE=Dell Inc + +@@ -72367,6 +72586,9 @@ OUI:E4F4C6* + OUI:E4F7A1* + ID_OUI_FROM_DATABASE=Datafox GmbH + ++OUI:E4F89C* ++ ID_OUI_FROM_DATABASE=Intel Corporate ++ + OUI:E4F8EF* + ID_OUI_FROM_DATABASE=Samsung Elec Co.,Ltd + +@@ -72376,6 +72598,9 @@ OUI:E4F939* + OUI:E4FA1D* + ID_OUI_FROM_DATABASE=PAD Peripheral Advanced Design Inc. + ++OUI:E4FAFD* ++ ID_OUI_FROM_DATABASE=Intel Corporate ++ + OUI:E4FED9* + ID_OUI_FROM_DATABASE=EDMI Europe Ltd + +@@ -72739,6 +72964,9 @@ OUI:E8F1B0* + OUI:E8F226* + ID_OUI_FROM_DATABASE=MILLSON CUSTOM SOLUTIONS INC. + ++OUI:E8F2E3* ++ ID_OUI_FROM_DATABASE=Starcor Beijing Co.,Limited ++ + OUI:E8F928* + ID_OUI_FROM_DATABASE=RFTECH SRL + +@@ -72874,6 +73102,9 @@ OUI:EC5A86* + OUI:EC5C69* + ID_OUI_FROM_DATABASE=MITSUBISHI HEAVY INDUSTRIES MECHATRONICS SYSTEMS,LTD. + ++OUI:EC60E0* ++ ID_OUI_FROM_DATABASE=AVI-ON LABS ++ + OUI:EC6264* + ID_OUI_FROM_DATABASE=Global411 Internet Services, LLC + +@@ -73213,6 +73444,9 @@ OUI:F07765* + OUI:F077D0* + ID_OUI_FROM_DATABASE=Xcellen + ++OUI:F07816* ++ ID_OUI_FROM_DATABASE=Cisco ++ + OUI:F07959* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +@@ -73279,6 +73513,9 @@ OUI:F09FC2* + OUI:F0A764* + ID_OUI_FROM_DATABASE=GST Co., Ltd. + ++OUI:F0AB54* ++ ID_OUI_FROM_DATABASE=MITSUMI ELECTRIC CO.,LTD. ++ + OUI:F0ACA4* + ID_OUI_FROM_DATABASE=HBC-radiomatic + +diff --git a/hwdb/20-pci-vendor-model.hwdb b/hwdb/20-pci-vendor-model.hwdb +index 6c2208887..3b35b26e5 100644 +--- a/hwdb/20-pci-vendor-model.hwdb ++++ b/hwdb/20-pci-vendor-model.hwdb +@@ -4361,6 +4361,9 @@ pci:v00001002d0000665Csv00001787sd00002329* + pci:v00001002d0000665D* + ID_MODEL_FROM_DATABASE=Bonaire [Radeon R7 200 Series] + ++pci:v00001002d0000665F* ++ ID_MODEL_FROM_DATABASE=Tobago [Radeon R7 300 Series] ++ + pci:v00001002d00006660* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M] + +@@ -5984,6 +5987,63 @@ pci:v00001002d000067AA* + pci:v00001002d000067B0* + ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] + ++pci:v00001002d000067B0sv00001043sd0000046A* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X DirectCU II) ++ ++pci:v00001002d000067B0sv00001043sd0000046C* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X DirectCU II OC) ++ ++pci:v00001002d000067B0sv00001043sd00000474* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Matrix R9 290X Platinum) ++ ++pci:v00001002d000067B0sv00001043sd00000476* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (ARES III) ++ ++pci:v00001002d000067B0sv00001458sd0000227C* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X OC) ++ ++pci:v00001002d000067B0sv00001458sd00002281* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X OC) ++ ++pci:v00001002d000067B0sv00001458sd0000228C* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X) ++ ++pci:v00001002d000067B0sv00001458sd0000228D* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X OC) ++ ++pci:v00001002d000067B0sv00001458sd00002290* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X) ++ ++pci:v00001002d000067B0sv00001462sd00003070* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Lightning) ++ ++pci:v00001002d000067B0sv00001462sd00003071* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Lightning) ++ ++pci:v00001002d000067B0sv00001462sd00003072* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Lightning LE) ++ ++pci:v00001002d000067B0sv00001462sd00003080* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Gaming) ++ ++pci:v00001002d000067B0sv00001462sd00003082* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Gaming OC) ++ ++pci:v00001002d000067B0sv0000148Csd00002347* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Devil 13 Dual Core R9 290X) ++ ++pci:v00001002d000067B0sv00001682sd00009290* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Double Dissipation R9 290X) ++ ++pci:v00001002d000067B0sv0000174Bsd0000E282* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Vapor-X R9 290X Tri-X OC) ++ ++pci:v00001002d000067B0sv0000174Bsd0000E285* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Tri-X OC) ++ ++pci:v00001002d000067B0sv00001787sd00002020* ++ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X IceQ X² Turbo) ++ + pci:v00001002d000067B1* + ID_MODEL_FROM_DATABASE=Hawaii PRO [Radeon R9 290] + +@@ -9092,6 +9152,9 @@ pci:v00001002d0000985E* + pci:v00001002d0000985F* + ID_MODEL_FROM_DATABASE=Mullins + ++pci:v00001002d00009874* ++ ID_MODEL_FROM_DATABASE=Carrizo ++ + pci:v00001002d00009900* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7660G] + +@@ -10272,10 +10335,10 @@ pci:v00001014d000000A6* + ID_MODEL_FROM_DATABASE=ATM 155MBPS MM Controller (1410a600) + + pci:v00001014d000000B7* +- ID_MODEL_FROM_DATABASE=256-bit Graphics Rasterizer [FireGL1] ++ ID_MODEL_FROM_DATABASE=GXT2000P Graphics Adapter + + pci:v00001014d000000B7sv00001092sd000000B8* +- ID_MODEL_FROM_DATABASE=256-bit Graphics Rasterizer [FireGL1] (FireGL1 AGP 32Mb) ++ ID_MODEL_FROM_DATABASE=GXT2000P Graphics Adapter (FireGL1 AGP 32Mb) + + pci:v00001014d000000B8* + ID_MODEL_FROM_DATABASE=GXT2000P Graphics Adapter +@@ -10325,6 +10388,15 @@ pci:v00001014d00000170* + pci:v00001014d00000170sv00001092sd00000172* + ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL2) + ++pci:v00001014d00000170sv00001092sd00000173* ++ ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL3) ++ ++pci:v00001014d00000170sv00001092sd00000174* ++ ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL4) ++ ++pci:v00001014d00000170sv00001092sd00000184* ++ ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL4s) ++ + pci:v00001014d0000017D* + ID_MODEL_FROM_DATABASE=GXT300P Graphics Adapter + +@@ -28542,913 +28614,934 @@ pci:v000010DEd000010D8* + ID_MODEL_FROM_DATABASE=GT218 [NVS 300] + + pci:v000010DEd00001140* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] + + pci:v000010DEd00001140sv00001019sd0000999F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000600* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000606* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd0000064A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd0000064C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd0000067A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000680* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000686* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd00000689* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000068B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000068D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000068E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd00000691* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd00000692* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000694* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000702* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000719* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000725* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000728* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd0000072B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd0000072E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000732* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001025sd00000763* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000773* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd00000774* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd00000776* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd0000077A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000077B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000077C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000077D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000077E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd0000077F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd00000781* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000798* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000799* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd0000079B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd0000079C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000807* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000821* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000823* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000830* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000833* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd00000837* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001025sd0000083E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000841* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001025sd00000854* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000855* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000856* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000857* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000858* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000868* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000869* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 810M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 810M) + + pci:v000010DEd00001140sv00001025sd00000873* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000878* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000087B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000087C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 810M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 810M) + + pci:v000010DEd00001140sv00001025sd00000881* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000088A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000089B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000090F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000921* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000092E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 810M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 810M) + + pci:v000010DEd00001140sv00001025sd0000092F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000093A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000093C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd0000093F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000941* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000945* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000954* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001025sd00000965* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001028sd0000054D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv00001028sd0000054E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv00001028sd00000554* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001028sd00000557* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001028sd00000562* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) + + pci:v000010DEd00001140sv00001028sd00000565* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv00001028sd00000568* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv00001028sd00000590* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv00001028sd00000592* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) + + pci:v000010DEd00001140sv00001028sd00000594* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) + + pci:v000010DEd00001140sv00001028sd00000595* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) + + pci:v000010DEd00001140sv00001028sd000005A2* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) + + pci:v000010DEd00001140sv00001028sd000005B1* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) + + pci:v000010DEd00001140sv00001028sd000005B3* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M) + + pci:v000010DEd00001140sv00001028sd000005DA* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv00001028sd000005DE* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001028sd000005E0* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001028sd000005E8* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv00001028sd000005F4* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001028sd0000060F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001028sd0000064E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001028sd00000652* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001028sd00000653* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001028sd00000655* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001028sd0000065E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001028sd00000662* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001028sd0000068D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000103Csd000018EF* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000103Csd000018F9* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000103Csd000018FB* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000103Csd000018FD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000103Csd000018FF* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000103Csd00002335* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000103Csd00002337* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000103Csd00002AEF* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A) + + pci:v000010DEd00001140sv0000103Csd00002AF9* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710A) + + pci:v000010DEd00001140sv00001043sd000010DD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M) + + pci:v000010DEd00001140sv00001043sd000010ED* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M) + + pci:v000010DEd00001140sv00001043sd000011FD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd0000124D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd0000126D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd0000131D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd000013FD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd000014C7* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd00001507* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001043sd000015AD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd000015ED* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000160D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000163D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000166D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd000016CD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd000016DD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000170D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000176D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000178D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000179D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd000017DD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd00002132* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001043sd00002136* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M) + + pci:v000010DEd00001140sv00001043sd000021BA* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd000021FA* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd0000220A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd0000221A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd0000223A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M) + + pci:v000010DEd00001140sv00001043sd0000224A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M) + + pci:v000010DEd00001140sv00001043sd0000227A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000228A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000232A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000233A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000236A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000238A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd00008595* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd000085EA* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd000085EB* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd000085EC* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd000085EE* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001043sd000085F3* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000860E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000861A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000861B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd00008628* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd00008643* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd0000864C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001043sd00008652* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000105Bsd00000DAC* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv0000105Bsd00000DAD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv0000105Bsd00000EF3* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001072sd0000152D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000010CFsd000017F5* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001179sd0000FA01* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA02* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA03* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA05* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA11* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA13* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA18* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA19* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA21* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA23* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA2A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA32* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA33* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA36* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA38* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA42* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA43* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA45* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA47* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA49* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA58* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA59* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA88* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001179sd0000FA89* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv0000144Dsd0000B092* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv0000144Dsd0000C0D5* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000144Dsd0000C0D7* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv0000144Dsd0000C0E2* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M) + + pci:v000010DEd00001140sv0000144Dsd0000C0E3* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M) + + pci:v000010DEd00001140sv0000144Dsd0000C0E4* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M) + + pci:v000010DEd00001140sv0000144Dsd0000C10D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000144Dsd0000C652* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv0000144Dsd0000C709* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv0000144Dsd0000C711* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv0000144Dsd0000C736* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv0000144Dsd0000C737* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv0000144Dsd0000C745* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000144Dsd0000C750* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001462sd000010B8* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M) + + pci:v000010DEd00001140sv00001462sd000010E9* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001462sd00001116* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001462sd0000AA33* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M) + + pci:v000010DEd00001140sv00001462sd0000AAA2* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001462sd0000AAA3* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001462sd0000ACB2* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001462sd0000ACC1* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001462sd0000AE61* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M) + + pci:v000010DEd00001140sv00001462sd0000AE65* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001462sd0000AE6A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001462sd0000AE71* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000014C0sd00000083* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000152Dsd00000926* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 620M) + + pci:v000010DEd00001140sv0000152Dsd00000982* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000152Dsd00000983* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000152Dsd00001005* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 820M) + + pci:v000010DEd00001140sv0000152Dsd00001012* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv0000152Dsd00001019* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000152Dsd00001030* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) + + pci:v000010DEd00001140sv0000152Dsd00001055* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv0000152Dsd00001067* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv0000152Dsd00001072* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv0000152Dsd00001086* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv0000152Dsd00001092* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00002200* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M) + + pci:v000010DEd00001140sv000017AAsd00002213* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00002220* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd0000309C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A) + + pci:v000010DEd00001140sv000017AAsd000030B4* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ++pci:v000010DEd00001140sv000017AAsd000030B7* ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720A) ++ ++pci:v000010DEd00001140sv000017AAsd0000361B* ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ++pci:v000010DEd00001140sv000017AAsd0000361C* ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd00003656* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv000017AAsd0000365A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M) + + pci:v000010DEd00001140sv000017AAsd0000365E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M) ++ ++pci:v000010DEd00001140sv000017AAsd00003661* ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd0000366C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M) + + pci:v000010DEd00001140sv000017AAsd00003685* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M) + + pci:v000010DEd00001140sv000017AAsd00003686* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M) + + pci:v000010DEd00001140sv000017AAsd00003687* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705A) + + pci:v000010DEd00001140sv000017AAsd00003696* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd0000369B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd0000369C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd0000369D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd0000369E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd000036A9* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ++pci:v000010DEd00001140sv000017AAsd000036AF* ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ++pci:v000010DEd00001140sv000017AAsd000036B0* ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) ++ ++pci:v000010DEd00001140sv000017AAsd000036B6* ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A) + + pci:v000010DEd00001140sv000017AAsd00003800* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003801* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003802* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003803* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003804* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003806* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003808* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd0000380D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd0000380E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd0000380F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003811* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003812* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003813* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003816* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003818* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd0000381A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd0000381C* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003901* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M / GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M / GT 620M) + + pci:v000010DEd00001140sv000017AAsd00003902* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd00003903* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M/710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M/710M) + + pci:v000010DEd00001140sv000017AAsd00003904* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M/625M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M/625M) + + pci:v000010DEd00001140sv000017AAsd00003905* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003907* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003910* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M) + + pci:v000010DEd00001140sv000017AAsd00003912* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M) + + pci:v000010DEd00001140sv000017AAsd00003913* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003915* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00003977* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00003983* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M) + + pci:v000010DEd00001140sv000017AAsd00005001* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M) + + pci:v000010DEd00001140sv000017AAsd00005003* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00005005* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M) + + pci:v000010DEd00001140sv000017AAsd0000500D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv000017AAsd00005014* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd00005017* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd00005019* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd0000501A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd0000501F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00005025* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd00005027* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd0000502A* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd0000502B* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd0000502D* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd0000502E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd0000502F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv000017AAsd00005030* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M) + + pci:v000010DEd00001140sv000017AAsd00005031* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M) + + pci:v000010DEd00001140sv000017AAsd00005032* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00005033* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd0000503E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv000017AAsd0000503F* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv000017AAsd00005040* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001854sd00000177* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001854sd00000180* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M) + + pci:v000010DEd00001140sv00001854sd00000190* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001854sd00000192* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001B0Asd000020DD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001B0Asd000020DF* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) + + pci:v000010DEd00001140sv00001B0Asd0000210E* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001B0Asd00002202* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + + pci:v000010DEd00001140sv00001B0Asd000090D7* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001140sv00001B0Asd000090DD* +- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M) ++ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + + pci:v000010DEd00001180* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 680] +@@ -29654,6 +29747,9 @@ pci:v000010DEd000011E3* + pci:v000010DEd000011E3sv000017AAsd00003683* + ID_MODEL_FROM_DATABASE=GK106M [GeForce GTX 760M] (GeForce GTX 760A) + ++pci:v000010DEd000011E7* ++ ID_MODEL_FROM_DATABASE=GK106M ++ + pci:v000010DEd000011FA* + ID_MODEL_FROM_DATABASE=GK106GL [Quadro K4000] + +@@ -30014,6 +30110,9 @@ pci:v000010DFd00000720sv000017AAsd00001057* + pci:v000010DFd00000720sv000017AAsd00001059* + ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (ThinkServer OCm14104-UT-L AnyFabric) + ++pci:v000010DFd00000720sv000017AAsd00004014* ++ ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (ThinkServer OCm14102-NX-L AnyFabric) ++ + pci:v000010DFd00000722* + ID_MODEL_FROM_DATABASE=OneConnect iSCSI Initiator (Skyhawk) + +@@ -30755,6 +30854,9 @@ pci:v000010ECd00008168sv00001775sd000011CC* + pci:v000010ECd00008168sv00001849sd00008168* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Motherboard (one of many)) + ++pci:v000010ECd00008168sv00007470sd00003468* ++ ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (TG-3468 Gigabit PCI Express Network Adapter) ++ + pci:v000010ECd00008168sv00008086sd0000D615* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Desktop Board D510MO/D525MW) + +@@ -31278,7 +31380,7 @@ pci:v00001102d00007005sv00001102sd00001002* + ID_MODEL_FROM_DATABASE=SB Audigy LS Game Port (SB0312 Audigy LS MIDI/Game port) + + pci:v00001102d00007006* +- ID_MODEL_FROM_DATABASE=[SB X-Fi Xtreme Audio] CA0110-IBG PCI to PCIe Bridge ++ ID_MODEL_FROM_DATABASE=[SB X-Fi Xtreme Audio] CA0110-IBG PCIe to PCI Bridge + + pci:v00001102d00008938* + ID_MODEL_FROM_DATABASE=Ectiva EV1938 +@@ -33896,6 +33998,9 @@ pci:v0000111Dd00008088sv00001093sd00007600* + pci:v0000111Dd00008088sv00001093sd00007602* + ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8384) + ++pci:v0000111Dd0000808F* ++ ID_MODEL_FROM_DATABASE=PES32NT8AG2 ++ + pci:v0000111E* + ID_VENDOR_FROM_DATABASE=Eldec + +@@ -34664,9 +34769,12 @@ pci:v00001131d00007164sv00000070sd000089A0* + pci:v00001131d00007164sv00000070sd000089A1* + ID_MODEL_FROM_DATABASE=SAA7164 (WinTV HVR-2200) + +-pci:v00001131d00007164sv00000070sd0000F123* ++pci:v00001131d00007164sv00000070sd0000F120* + ID_MODEL_FROM_DATABASE=SAA7164 (WinTV HVR-2205) + ++pci:v00001131d00007164sv00000070sd0000F123* ++ ID_MODEL_FROM_DATABASE=SAA7164 (WinTV HVR-2215) ++ + pci:v00001131d00007231* + ID_MODEL_FROM_DATABASE=SAA7231 + +@@ -39923,6 +40031,15 @@ pci:v0000125E* + pci:v0000125F* + ID_VENDOR_FROM_DATABASE=Concurrent Technologies, Inc. + ++pci:v0000125Fd00002071* ++ ID_MODEL_FROM_DATABASE=CC PMC/232 ++ ++pci:v0000125Fd00002084* ++ ID_MODEL_FROM_DATABASE=CC PMC/23P ++ ++pci:v0000125Fd00002091* ++ ID_MODEL_FROM_DATABASE=CC PMC/422 ++ + pci:v00001260* + ID_VENDOR_FROM_DATABASE=Intersil Corporation + +@@ -43145,17 +43262,56 @@ pci:v00001397* + pci:v00001397d000008B4* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] + ++pci:v00001397d000008B4sv00001397sd000008B4* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Cologne Chip HFC-4S Eval. Board]) ++ ++pci:v00001397d000008B4sv00001397sd0000B51A* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Allo.com BRI card]) ++ + pci:v00001397d000008B4sv00001397sd0000B520* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [IOB4ST]) + + pci:v00001397d000008B4sv00001397sd0000B540* +- ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Swyx 4xS0 SX2 QuadBri]) ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Swyx SX2 QuadBri]) + + pci:v00001397d000008B4sv00001397sd0000B550* +- ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns quadBRI]) ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET quadBRI]) + + pci:v00001397d000008B4sv00001397sd0000B556* +- ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns DuoDBRI]) ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET duoBRI]) ++ ++pci:v00001397d000008B4sv00001397sd0000B559* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET duoBRI miniPCI]) ++ ++pci:v00001397d000008B4sv00001397sd0000B560* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN4S0]) ++ ++pci:v00001397d000008B4sv00001397sd0000B566* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN2S0]) ++ ++pci:v00001397d000008B4sv00001397sd0000B567* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN1S0 miniPCI]) ++ ++pci:v00001397d000008B4sv00001397sd0000B568* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN4S0 miniPCI]) ++ ++pci:v00001397d000008B4sv00001397sd0000B569* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN2S0 miniPCI]) ++ ++pci:v00001397d000008B4sv00001397sd0000B620* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S) ++ ++pci:v00001397d000008B4sv00001397sd0000B752* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET quadBRI PCIe]) ++ ++pci:v00001397d000008B4sv00001397sd0000B761* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN2S0 PCIe]) ++ ++pci:v00001397d000008B4sv00001397sd0000B762* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN4S0 PCIe]) ++ ++pci:v00001397d000008B4sv00001397sd0000E884* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [OpenVox B200P]) + + pci:v00001397d000008B4sv00001397sd0000E888* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [OpenVox B200P / B400P]) +@@ -43163,9 +43319,33 @@ pci:v00001397d000008B4sv00001397sd0000E888* + pci:v00001397d000016B8* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] + +-pci:v00001397d000016B8sv00001397sd0000B562* ++pci:v00001397d000016B8sv00001397sd000016B8* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [Cologne Chip HFC-8S Eval. Board]) ++ ++pci:v00001397d000016B8sv00001397sd0000B521* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [IOB4ST Recording]) ++ ++pci:v00001397d000016B8sv00001397sd0000B522* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [IOB8ST]) + ++pci:v00001397d000016B8sv00001397sd0000B552* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [Junghanns.NET octoBRI]) ++ ++pci:v00001397d000016B8sv00001397sd0000B55B* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [Junghanns.NET octoBRI]) ++ ++pci:v00001397d000016B8sv00001397sd0000B562* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [BeroNet BN8S0]) ++ ++pci:v00001397d000016B8sv00001397sd0000B56B* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [BeroNet BN8S0+]) ++ ++pci:v00001397d000016B8sv00001397sd0000B622* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S) ++ ++pci:v00001397d000016B8sv00001397sd0000E998* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [OpenVox B800P]) ++ + pci:v00001397d00002BD0* + ID_MODEL_FROM_DATABASE=ISDN network controller [HFC-PCI] + +@@ -43184,6 +43364,42 @@ pci:v00001397d00002BD0sv0000E4BFsd00001000* + pci:v00001397d000030B1* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] + ++pci:v00001397d000030B1sv00001397sd000030B1* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Cologne Chip HFC-E1 Eval. Board]) ++ ++pci:v00001397d000030B1sv00001397sd0000B523* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [IOB1E1]) ++ ++pci:v00001397d000030B1sv00001397sd0000B543* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Swyx SX2 SinglePRI V2]) ++ ++pci:v00001397d000030B1sv00001397sd0000B544* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Swyx SX2 DualPRI V2]) ++ ++pci:v00001397d000030B1sv00001397sd0000B553* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET singleE1]) ++ ++pci:v00001397d000030B1sv00001397sd0000B554* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET doubleE1]) ++ ++pci:v00001397d000030B1sv00001397sd0000B555* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET doubleE1 2.0]) ++ ++pci:v00001397d000030B1sv00001397sd0000B55A* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET singleE1 miniPCI]) ++ ++pci:v00001397d000030B1sv00001397sd0000B563* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN1E1]) ++ ++pci:v00001397d000030B1sv00001397sd0000B564* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN2E1]) ++ ++pci:v00001397d000030B1sv00001397sd0000B565* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN2E1+]) ++ ++pci:v00001397d000030B1sv00001397sd0000B56A* ++ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN1E1 miniPCI]) ++ + pci:v00001397d0000B700* + ID_MODEL_FROM_DATABASE=ISDN network controller PrimuX S0 [HFC-PCI] + +@@ -45206,6 +45422,9 @@ pci:v00001425d00005088* + pci:v00001425d00005089* + ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller + ++pci:v00001425d00005090* ++ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller ++ + pci:v00001425d00005401* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +@@ -45299,6 +45518,9 @@ pci:v00001425d00005488* + pci:v00001425d00005489* + ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller + ++pci:v00001425d00005490* ++ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller ++ + pci:v00001425d00005501* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller + +@@ -45392,6 +45614,9 @@ pci:v00001425d00005588* + pci:v00001425d00005589* + ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Storage Controller + ++pci:v00001425d00005590* ++ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Storage Controller ++ + pci:v00001425d00005601* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller + +@@ -45485,6 +45710,9 @@ pci:v00001425d00005688* + pci:v00001425d00005689* + ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Storage Controller + ++pci:v00001425d00005690* ++ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Storage Controller ++ + pci:v00001425d00005701* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +@@ -45578,6 +45806,9 @@ pci:v00001425d00005788* + pci:v00001425d00005789* + ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller + ++pci:v00001425d00005790* ++ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller ++ + pci:v00001425d00005801* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller [VF] + +@@ -45671,6 +45902,9 @@ pci:v00001425d00005888* + pci:v00001425d00005889* + ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller [VF] + ++pci:v00001425d00005890* ++ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller [VF] ++ + pci:v00001425d0000A000* + ID_MODEL_FROM_DATABASE=PE10K Unified Wire Ethernet Controller + +@@ -51930,7 +52164,10 @@ pci:v0000168Cd0000003C* + ID_MODEL_FROM_DATABASE=QCA988x 802.11ac Wireless Network Adapter + + pci:v0000168Cd0000003E* +- ID_MODEL_FROM_DATABASE=Killer N1525 Wireless-AC ++ ID_MODEL_FROM_DATABASE=QCA6174 802.11ac Wireless Network Adapter ++ ++pci:v0000168Cd0000003Esv00001A56sd00001525* ++ ID_MODEL_FROM_DATABASE=QCA6174 802.11ac Wireless Network Adapter (Killer N1525 Wireless-AC) + + pci:v0000168Cd00000207* + ID_MODEL_FROM_DATABASE=AR5210 Wireless Network Adapter [AR5000 802.11a] +@@ -54326,6 +54563,12 @@ pci:v00001924d00000903sv00001924sd00008009* + pci:v00001924d00000903sv00001924sd0000800A* + ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x02F-R2 Flareon 7000 Series 10G Adapter) + ++pci:v00001924d00000903sv00001924sd0000800B* ++ ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x22F-R3 Flareon Ultra 7000 Series 10G Adapter) ++ ++pci:v00001924d00000903sv00001924sd0000800C* ++ ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x02F-R3 Flareon 7000 Series 10G Adapter) ++ + pci:v00001924d00000923* + ID_MODEL_FROM_DATABASE=SFC9140 + +@@ -55940,6 +56183,27 @@ pci:v00001BB0d00000002* + pci:v00001BB0d00000010* + ID_MODEL_FROM_DATABASE=OmniCube Accelerator OA-3000-2 + ++pci:v00001BB1* ++ ID_VENDOR_FROM_DATABASE=Seagate Technology PLC ++ ++pci:v00001BB1d0000005D* ++ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage ++ ++pci:v00001BB1d0000005Dsv00001BB1sd00006501* ++ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XP6500-8A1536 1.5TB) ++ ++pci:v00001BB1d0000005Dsv00001BB1sd00006502* ++ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XP6500-8A2048) ++ ++pci:v00001BB1d0000005Dsv00001BB1sd00006503* ++ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XP6500-8A4096) ++ ++pci:v00001BB1d0000005Dsv00001BB1sd00006511* ++ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XH6550-2GB DRAM) ++ ++pci:v00001BB1d0000005Dsv00001BB1sd00006512* ++ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XH6550-8GB DRAM) ++ + pci:v00001BB3* + ID_VENDOR_FROM_DATABASE=Bluecherry + +@@ -57905,6 +58169,9 @@ pci:v00007401* + pci:v00007401d0000E100* + ID_MODEL_FROM_DATABASE=PTP3100 PCIe PTP Slave Clock + ++pci:v00007470* ++ ID_VENDOR_FROM_DATABASE=TP-LINK Technologies Co., Ltd. ++ + pci:v00007604* + ID_VENDOR_FROM_DATABASE=O.N. Electronic Co Ltd. + +@@ -58434,13 +58701,13 @@ pci:v00008086d00000341* + ID_MODEL_FROM_DATABASE=41210 [Lanai] Serial to Parallel PCI Bridge (B-Segment Bridge) + + pci:v00008086d00000370* +- ID_MODEL_FROM_DATABASE=80333 Segment-A PCI Express-to-PCI Express Bridge ++ ID_MODEL_FROM_DATABASE=80333 Segment-A PCIe Express to PCI-X bridge + + pci:v00008086d00000371* + ID_MODEL_FROM_DATABASE=80333 A-Bus IOAPIC + + pci:v00008086d00000372* +- ID_MODEL_FROM_DATABASE=80333 Segment-B PCI Express-to-PCI Express Bridge ++ ID_MODEL_FROM_DATABASE=80333 Segment-B PCIe Express to PCI-X bridge + + pci:v00008086d00000373* + ID_MODEL_FROM_DATABASE=80333 B-Bus IOAPIC +@@ -62285,6 +62552,9 @@ pci:v00008086d00001521sv0000103Csd00003380* + pci:v00008086d00001521sv0000103Csd0000339E* + ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (Ethernet 1Gb 2-port 361T Adapter) + ++pci:v00008086d00001521sv0000103Csd00008157* ++ ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (Ethernet 1Gb 4-port 366T Adapter) ++ + pci:v00008086d00001521sv0000108Esd00007B16* + ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (Quad Port GbE PCIe 2.0 ExpressModule, UTP) + +@@ -62588,6 +62858,12 @@ pci:v00008086d00001572* + pci:v00008086d00001572sv00001028sd00001F99* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet 10G 4P X710/I350 rNDC) + ++pci:v00008086d00001572sv00001137sd00000000* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet Converged NIC X710-4) ++ ++pci:v00008086d00001572sv00001137sd0000013B* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet Converged NIC X710-4) ++ + pci:v00008086d00001572sv000017AAsd00000000* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (ThinkServer XL710 AnyFabric) + +@@ -62636,6 +62912,18 @@ pci:v00008086d00001581sv00001028sd00001F98* + pci:v00008086d00001583* + ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ + ++pci:v00008086d00001583sv0000108Esd00000000* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Oracle 10 Gb and 40 Gb Ethernet Adapter) ++ ++pci:v00008086d00001583sv0000108Esd00007B1B* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Oracle 10 Gb and 40 Gb Ethernet Adapter) ++ ++pci:v00008086d00001583sv00001137sd00000000* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet Converged NIC XL710-Q2) ++ ++pci:v00008086d00001583sv00001137sd0000013C* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet Converged NIC XL710-Q2) ++ + pci:v00008086d00001583sv00008086sd00000000* + ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet Converged Network Adapter XL710-Q2) + +@@ -62664,7 +62952,16 @@ pci:v00008086d00001584sv00008086sd00000003* + ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet I/O Module XL710-Q1) + + pci:v00008086d00001585* +- ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 10GbE QSFP+ ++ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE QSFP+ ++ ++pci:v00008086d00001586* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T ++ ++pci:v00008086d00001586sv0000108Esd00000000* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T ++ ++pci:v00008086d00001586sv0000108Esd00004857* ++ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T + + pci:v00008086d000015A0* + ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I218-LM +@@ -77396,6 +77693,15 @@ pci:v00009412* + pci:v00009412d00006565* + ID_MODEL_FROM_DATABASE=6565 + ++pci:v00009413* ++ ID_VENDOR_FROM_DATABASE=Softlogic Co., Ltd. ++ ++pci:v00009413d00006010* ++ ID_MODEL_FROM_DATABASE=SOLO6010 MPEG-4 Video encoder/decoder ++ ++pci:v00009413d00006110* ++ ID_MODEL_FROM_DATABASE=SOLO6110 H.264 Video encoder/decoder ++ + pci:v00009618* + ID_VENDOR_FROM_DATABASE=JusonTech Corporation + +diff --git a/hwdb/20-sdio-vendor-model.hwdb b/hwdb/20-sdio-vendor-model.hwdb +index 626d673c4..9cf34b2a3 100644 +--- a/hwdb/20-sdio-vendor-model.hwdb ++++ b/hwdb/20-sdio-vendor-model.hwdb +@@ -80,6 +80,36 @@ sdio:c*v02D0* + sdio:c*v02D0d044B* + ID_MODEL_FROM_DATABASE=Nintendo Wii WLAN daughter card + ++sdio:c*v02D0dA887* ++ ID_MODEL_FROM_DATABASE=BCM43143 WLAN card ++ ++sdio:c*v02D0d4324* ++ ID_MODEL_FROM_DATABASE=BCM43241 WLAN card ++ ++sdio:c*v02D0d4329* ++ ID_MODEL_FROM_DATABASE=BCM4329 WLAN card ++ ++sdio:c*v02D0d4330* ++ ID_MODEL_FROM_DATABASE=BCM4330 WLAN card ++ ++sdio:c*v02D0d4334* ++ ID_MODEL_FROM_DATABASE=BCM4334 WLAN card ++ ++sdio:c*v02D0dA94C* ++ ID_MODEL_FROM_DATABASE=BCM43340 WLAN card ++ ++sdio:c*v02D0dA94D* ++ ID_MODEL_FROM_DATABASE=BCM43341 WLAN card ++ ++sdio:c*v02D0d4335* ++ ID_MODEL_FROM_DATABASE=BCM4335/BCM4339 WLAN card ++ ++sdio:c*v02D0dA962* ++ ID_MODEL_FROM_DATABASE=BCM43362 WLAN card ++ ++sdio:c*v02D0d4354* ++ ID_MODEL_FROM_DATABASE=BCM4354 WLAN card ++ + sdio:c*v02DB* + ID_VENDOR_FROM_DATABASE=SyChip Inc. + +diff --git a/hwdb/20-usb-vendor-model.hwdb b/hwdb/20-usb-vendor-model.hwdb +index 94e0269ce..8867531a3 100644 +--- a/hwdb/20-usb-vendor-model.hwdb ++++ b/hwdb/20-usb-vendor-model.hwdb +@@ -503,6 +503,9 @@ usb:v03F0p0217* + usb:v03F0p0218* + ID_MODEL_FROM_DATABASE=APOLLO P2500/2600 + ++usb:v03F0p022A* ++ ID_MODEL_FROM_DATABASE=Laserjet CP1525nw ++ + usb:v03F0p0241* + ID_MODEL_FROM_DATABASE=Link-5 micro dongle + +@@ -1320,7 +1323,7 @@ usb:v03F0p4002* + ID_MODEL_FROM_DATABASE=PhotoSmart 635/715/720/735/935 (storage) + + usb:v03F0p4004* +- ID_MODEL_FROM_DATABASE=cp1160 ++ ID_MODEL_FROM_DATABASE=CP1160 + + usb:v03F0p4102* + ID_MODEL_FROM_DATABASE=PhotoSmart 618 +@@ -2075,6 +2078,9 @@ usb:v0403p1060* + usb:v0403p1234* + ID_MODEL_FROM_DATABASE=IronLogic RFID Adapter [Z-2 USB] + ++usb:v0403p1235* ++ ID_MODEL_FROM_DATABASE=Iron Logic Z-397 RS-485/422 converter ++ + usb:v0403p6001* + ID_MODEL_FROM_DATABASE=FT232 USB-Serial (UART) IC + +@@ -2147,6 +2153,9 @@ usb:v0403p8B2B* + usb:v0403p8B2C* + ID_MODEL_FROM_DATABASE=Alpermann+Velte TCC70 + ++usb:v0403p9090* ++ ID_MODEL_FROM_DATABASE=SNAP Stick 200 ++ + usb:v0403p9132* + ID_MODEL_FROM_DATABASE=LCD and Temperature Interface + +@@ -3311,6 +3320,9 @@ usb:v0411p00E8* + usb:v0411p0105* + ID_MODEL_FROM_DATABASE=External Hard Drive HD-CEU2 [Drive Station] + ++usb:v0411p012C* ++ ID_MODEL_FROM_DATABASE=SATA Bridge ++ + usb:v0411p012E* + ID_MODEL_FROM_DATABASE=WLI-UC-AG300N Wireless LAN Adapter + +@@ -5378,6 +5390,12 @@ usb:v0451p625F* + usb:v0451p8042* + ID_MODEL_FROM_DATABASE=Hub + ++usb:v0451p8142* ++ ID_MODEL_FROM_DATABASE=TUSB8041 4-Port Hub ++ ++usb:v0451p926B* ++ ID_MODEL_FROM_DATABASE=TUSB9260 Boot Loader ++ + usb:v0451pDBC0* + ID_MODEL_FROM_DATABASE=Device Bay Controller + +@@ -7364,6 +7382,9 @@ usb:v046Dp0A1F* + usb:v046Dp0A29* + ID_MODEL_FROM_DATABASE=H600 [Wireless Headset] + ++usb:v046Dp0A37* ++ ID_MODEL_FROM_DATABASE=USB Headset H540 ++ + usb:v046Dp0A38* + ID_MODEL_FROM_DATABASE=Headset H340 + +@@ -7608,7 +7629,7 @@ usb:v046DpC122* + ID_MODEL_FROM_DATABASE=Harmony 650/700 Remote + + usb:v046DpC124* +- ID_MODEL_FROM_DATABASE=Harmony 300 Remote ++ ID_MODEL_FROM_DATABASE=Harmony 300/350 Remote + + usb:v046DpC125* + ID_MODEL_FROM_DATABASE=Harmony 200 Remote +@@ -8432,6 +8453,9 @@ usb:v0471p20E3* + usb:v0471p20E4* + ID_MODEL_FROM_DATABASE=GoGear ViBE 8GB + ++usb:v0471p2160* ++ ID_MODEL_FROM_DATABASE=Mio LINK Heart Rate Monitor ++ + usb:v0471p262C* + ID_MODEL_FROM_DATABASE=SPC230NC Webcam + +@@ -8948,6 +8972,9 @@ usb:v0483p2018* + usb:v0483p2302* + ID_MODEL_FROM_DATABASE=Portable Flash Device (PFD) + ++usb:v0483p347B* ++ ID_MODEL_FROM_DATABASE=ST-LINK/V2-1 ++ + usb:v0483p3744* + ID_MODEL_FROM_DATABASE=STLINK Pseudo disk + +@@ -9044,6 +9071,9 @@ usb:v0489pE016* + usb:v0489pE02C* + ID_MODEL_FROM_DATABASE=Atheros AR5BBU12 Bluetooth Device + ++usb:v0489pE04D* ++ ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth ++ + usb:v048A* + ID_VENDOR_FROM_DATABASE=S-MOS Systems, Inc. + +@@ -13277,6 +13307,9 @@ usb:v04D8pF4B5* + usb:v04D8pF8DA* + ID_MODEL_FROM_DATABASE=Hughski Ltd. ColorHug + ++usb:v04D8pF8E8* ++ ID_MODEL_FROM_DATABASE=Harmony 300/350 Remote ++ + usb:v04D8pF91C* + ID_MODEL_FROM_DATABASE=SPROG IIv3 + +@@ -14376,7 +14409,7 @@ usb:v04E8p6632* + ID_MODEL_FROM_DATABASE=MITs Sync + + usb:v04E8p663E* +- ID_MODEL_FROM_DATABASE=D900e Phone ++ ID_MODEL_FROM_DATABASE=D900e/B2100 Phone + + usb:v04E8p663F* + ID_MODEL_FROM_DATABASE=SGH-E720/SGH-E840 +@@ -14400,10 +14433,10 @@ usb:v04E8p6734* + ID_MODEL_FROM_DATABASE=Juke + + usb:v04E8p6759* +- ID_MODEL_FROM_DATABASE=D900e Media Player ++ ID_MODEL_FROM_DATABASE=D900e/B2100 Media Player + + usb:v04E8p675A* +- ID_MODEL_FROM_DATABASE=D900e Mass Storage ++ ID_MODEL_FROM_DATABASE=D900e/B2100 Mass Storage + + usb:v04E8p675B* + ID_MODEL_FROM_DATABASE=D900e Camera +@@ -17153,6 +17186,9 @@ usb:v054Cp04CB* + usb:v054Cp0541* + ID_MODEL_FROM_DATABASE=DSC-HX100V [Cybershot Digital Still Camera] + ++usb:v054Cp05C4* ++ ID_MODEL_FROM_DATABASE=DualShock 4 ++ + usb:v054Cp0689* + ID_MODEL_FROM_DATABASE=Walkman NWZ-B173F + +@@ -17870,6 +17906,9 @@ usb:v056Ap00F6* + usb:v056Ap00F8* + ID_MODEL_FROM_DATABASE=Cintiq 24HD touch (DTH-2400) tablet + ++usb:v056Ap0302* ++ ID_MODEL_FROM_DATABASE=Intuos CTH480S2 [Manga] ++ + usb:v056Ap0307* + ID_MODEL_FROM_DATABASE=Cintiq Companion Hybrid 13HD (DTH-A1300) tablet + +@@ -20511,7 +20550,7 @@ usb:v05B4p4857* + ID_MODEL_FROM_DATABASE=M-Any DAH-210 + + usb:v05B4p6001* +- ID_MODEL_FROM_DATABASE=Digisette DUO-MP3 AR-100 ++ ID_MODEL_FROM_DATABASE=HYUNDAI GDS30C6001 SSFDC / MMC I/F Controller + + usb:v05B5* + ID_VENDOR_FROM_DATABASE=Dialogic Corp. +@@ -20618,6 +20657,9 @@ usb:v05C6p9001* + usb:v05C6p9002* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + ++usb:v05C6p9003* ++ ID_MODEL_FROM_DATABASE=Quectel UC20 ++ + usb:v05C6p9008* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +@@ -21548,6 +21590,9 @@ usb:v05DCpA813* + usb:v05DCpA815* + ID_MODEL_FROM_DATABASE=JumpDrive V10 + ++usb:v05DCpA833* ++ ID_MODEL_FROM_DATABASE=JumpDrive S23 64GB ++ + usb:v05DCpB002* + ID_MODEL_FROM_DATABASE=USB CF Reader + +@@ -22589,6 +22634,9 @@ usb:v064EpA219* + usb:v064EpC107* + ID_MODEL_FROM_DATABASE=HP webcam [dv6-1190en] + ++usb:v064EpC335* ++ ID_MODEL_FROM_DATABASE=HP TrueVision HD ++ + usb:v064EpD101* + ID_MODEL_FROM_DATABASE=Acer CrystalEye Webcam + +@@ -25850,6 +25898,9 @@ usb:v0764p0005* + usb:v0764p0501* + ID_MODEL_FROM_DATABASE=CP1500 AVR UPS + ++usb:v0764p0601* ++ ID_MODEL_FROM_DATABASE=PR1500LCDRT2U UPS ++ + usb:v0765* + ID_VENDOR_FROM_DATABASE=X-Rite, Inc. + +@@ -26900,6 +26951,9 @@ usb:v07B3p0A06* + usb:v07B3p0B00* + ID_MODEL_FROM_DATABASE=SmartPhoto F50 + ++usb:v07B3p0C00* ++ ID_MODEL_FROM_DATABASE=OpticPro ST64 Scanner ++ + usb:v07B3p0C03* + ID_MODEL_FROM_DATABASE=OpticPro ST64+ Scanner + +@@ -26946,7 +27000,7 @@ usb:v07B4p0112* + ID_MODEL_FROM_DATABASE=MAUSB-100 xD Card Reader + + usb:v07B4p0113* +- ID_MODEL_FROM_DATABASE=Mju 500 ++ ID_MODEL_FROM_DATABASE=Mju 500 / Stylus Digital Camera (PTP) + + usb:v07B4p0114* + ID_MODEL_FROM_DATABASE=C-350Z Camera +@@ -28589,6 +28643,9 @@ usb:v0846p9041* + usb:v0846p9042* + ID_MODEL_FROM_DATABASE=On Networks N150MA 802.11bgn [Realtek RTL8188CUS] + ++usb:v0846p9043* ++ ID_MODEL_FROM_DATABASE=WNA1000Mv2 802.11bgn [Realtek RTL8188CUS?] ++ + usb:v0846p9050* + ID_MODEL_FROM_DATABASE=A6200 802.11a/b/g/n/ac Wireless Adapter [Broadcom BCM43526] + +@@ -29432,6 +29489,9 @@ usb:v08E3p0301* + usb:v08E4* + ID_VENDOR_FROM_DATABASE=Pioneer Corp. + ++usb:v08E4p0184* ++ ID_MODEL_FROM_DATABASE=DDJ-WeGO ++ + usb:v08E4p0185* + ID_MODEL_FROM_DATABASE=DDJ-WeGO2 + +@@ -29990,6 +30050,9 @@ usb:v090Cp037A* + usb:v090Cp037B* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + ++usb:v090Cp037C* ++ ID_MODEL_FROM_DATABASE=300k Pixel Camera ++ + usb:v090Cp1000* + ID_MODEL_FROM_DATABASE=Flash Drive + +@@ -30032,6 +30095,9 @@ usb:v090CpB370* + usb:v090CpB371* + ID_MODEL_FROM_DATABASE=Silicon Motion SM371 Camera + ++usb:v090CpF37D* ++ ID_MODEL_FROM_DATABASE=Endoscope camera ++ + usb:v090D* + ID_VENDOR_FROM_DATABASE=Multiport Computer Vertriebs GmbH + +@@ -30323,6 +30389,9 @@ usb:v0928* + usb:v0928p8000* + ID_MODEL_FROM_DATABASE=Firmware uploader + ++usb:v0928pFFFF* ++ ID_MODEL_FROM_DATABASE=Blank Oxford Device ++ + usb:v0929* + ID_VENDOR_FROM_DATABASE=American Biometric Co. + +@@ -35774,6 +35843,15 @@ usb:v0C4Bp0500* + usb:v0C4Bp0501* + ID_MODEL_FROM_DATABASE=cyberJack RFID comfort dual interface smartcard reader + ++usb:v0C4Bp0502* ++ ID_MODEL_FROM_DATABASE=cyberJack compact ++ ++usb:v0C4Bp0504* ++ ID_MODEL_FROM_DATABASE=cyberJack go / go plus ++ ++usb:v0C4Bp0505* ++ ID_MODEL_FROM_DATABASE=cyberJack wave ++ + usb:v0C4Bp9102* + ID_MODEL_FROM_DATABASE=cyberJack RFID basis contactless smartcard reader + +@@ -35981,6 +36059,36 @@ usb:v0C5E* + usb:v0C60* + ID_VENDOR_FROM_DATABASE=Apogee Electronics Corp. + ++usb:v0C60p0001* ++ ID_MODEL_FROM_DATABASE=MiniMe ++ ++usb:v0C60p0002* ++ ID_MODEL_FROM_DATABASE=MiniDAC ++ ++usb:v0C60p0003* ++ ID_MODEL_FROM_DATABASE=ONE ++ ++usb:v0C60p0004* ++ ID_MODEL_FROM_DATABASE=GiO ++ ++usb:v0C60p0007* ++ ID_MODEL_FROM_DATABASE=Duet ++ ++usb:v0C60p0009* ++ ID_MODEL_FROM_DATABASE=Jam ++ ++usb:v0C60p000A* ++ ID_MODEL_FROM_DATABASE=Jam Bootloader ++ ++usb:v0C60p000B* ++ ID_MODEL_FROM_DATABASE=MiC ++ ++usb:v0C60p000C* ++ ID_MODEL_FROM_DATABASE=MiC Bootloader ++ ++usb:v0C60p8007* ++ ID_MODEL_FROM_DATABASE=Duet DFU Mode ++ + usb:v0C62* + ID_VENDOR_FROM_DATABASE=Chant Sincere Co., Ltd + +@@ -37524,7 +37632,7 @@ usb:v0DA3* + ID_VENDOR_FROM_DATABASE=Nippon Electro-Sensory Devices Corp. + + usb:v0DA4* +- ID_VENDOR_FROM_DATABASE=Polar Electro OY ++ ID_VENDOR_FROM_DATABASE=Polar Electro Oy + + usb:v0DA4p0001* + ID_MODEL_FROM_DATABASE=Interface +@@ -37667,6 +37775,18 @@ usb:v0DB3* + usb:v0DB4* + ID_VENDOR_FROM_DATABASE=Chung Fu Chen Yeh Enterprise Corp. + ++usb:v0DB5* ++ ID_VENDOR_FROM_DATABASE=Access IS ++ ++usb:v0DB5p0139* ++ ID_MODEL_FROM_DATABASE=LSR116 CDC ++ ++usb:v0DB5p013A* ++ ID_MODEL_FROM_DATABASE=LSR116 Keyboard ++ ++usb:v0DB5p013B* ++ ID_MODEL_FROM_DATABASE=LSR116 HID ++ + usb:v0DB7* + ID_VENDOR_FROM_DATABASE=ELCON Systemtechnik + +@@ -38510,6 +38630,9 @@ usb:v0E6Fp0005* + usb:v0E6Fp0006* + ID_MODEL_FROM_DATABASE=Edge wireless Controller + ++usb:v0E6Fp0128* ++ ID_MODEL_FROM_DATABASE=Wireless PS3 Controller ++ + usb:v0E70* + ID_VENDOR_FROM_DATABASE=Tokyo Electronic Industry Co., Ltd + +@@ -38618,6 +38741,9 @@ usb:v0E8Fp0020* + usb:v0E8Fp0021* + ID_MODEL_FROM_DATABASE=Multimedia Keyboard Controller + ++usb:v0E8Fp0022* ++ ID_MODEL_FROM_DATABASE=multimedia keyboard controller ++ + usb:v0E8Fp0201* + ID_MODEL_FROM_DATABASE=SmartJoy Frag Xpad/PS2 adaptor + +@@ -38858,6 +38984,9 @@ usb:v0EE3p1000* + usb:v0EE4* + ID_VENDOR_FROM_DATABASE=Sunrich Technology, Ltd + ++usb:v0EE4p0690* ++ ID_MODEL_FROM_DATABASE=SATA 3 Adapter ++ + usb:v0EEE* + ID_VENDOR_FROM_DATABASE=Digital Stream Technology, Inc. + +@@ -39663,7 +39792,7 @@ usb:v0FCEpE19B* + ID_MODEL_FROM_DATABASE=C2005 [Xperia M dual] (Mass Storage) + + usb:v0FCEpF0FA* +- ID_MODEL_FROM_DATABASE=Liveview micro display MN800 in DFU mode ++ ID_MODEL_FROM_DATABASE=MN800 / Smartwatch 2 (DFU mode) + + usb:v0FCF* + ID_VENDOR_FROM_DATABASE=Dynastream Innovations, Inc. +@@ -39884,6 +40013,9 @@ usb:v1004p61C6* + usb:v1004p61CC* + ID_MODEL_FROM_DATABASE=Optimus S + ++usb:v1004p61DA* ++ ID_MODEL_FROM_DATABASE=G2 Android Phone [tethering mode] ++ + usb:v1004p61F1* + ID_MODEL_FROM_DATABASE=Optimus Android Phone [LG Software mode] + +@@ -39900,13 +40032,13 @@ usb:v1004p6300* + ID_MODEL_FROM_DATABASE=Optimus Android Phone + + usb:v1004p631C* +- ID_MODEL_FROM_DATABASE=Optimus Android Phone [MTP mode] ++ ID_MODEL_FROM_DATABASE=G2/Optimus Android Phone [MTP mode] + + usb:v1004p631D* + ID_MODEL_FROM_DATABASE=Optimus Android Phone (Camera/PTP Mode) + + usb:v1004p631E* +- ID_MODEL_FROM_DATABASE=Optimus Android Phone [Camera/PTP mode] ++ ID_MODEL_FROM_DATABASE=G2/Optimus Android Phone [Camera/PTP mode] + + usb:v1004p631F* + ID_MODEL_FROM_DATABASE=Optimus Android Phone (Charge Mode) +@@ -40241,6 +40373,9 @@ usb:v1046p9967* + usb:v1048* + ID_VENDOR_FROM_DATABASE=Targus Group International + ++usb:v1048p2010* ++ ID_MODEL_FROM_DATABASE=4-Port hub ++ + usb:v104B* + ID_VENDOR_FROM_DATABASE=Mylex / Buslogic + +@@ -40287,13 +40422,22 @@ usb:v1050p0010* + ID_MODEL_FROM_DATABASE=Yubikey + + usb:v1050p0110* +- ID_MODEL_FROM_DATABASE=Yubikey NEO OTP ++ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) OTP + + usb:v1050p0111* +- ID_MODEL_FROM_DATABASE=Yubikey NEO OTP+CCID ++ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) OTP+CCID + + usb:v1050p0112* +- ID_MODEL_FROM_DATABASE=Yubikey NEO CCID ++ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) CCID ++ ++usb:v1050p0113* ++ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) U2F ++ ++usb:v1050p0114* ++ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) OTP+U2F ++ ++usb:v1050p0115* ++ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) U2F+CCID + + usb:v1050p0200* + ID_MODEL_FROM_DATABASE=U2F Gnubby +@@ -50777,6 +50921,15 @@ usb:v2931p0A05* + usb:v2931p0AFE* + ID_MODEL_FROM_DATABASE=Jolla charging only + ++usb:v2A03* ++ ID_VENDOR_FROM_DATABASE=dog hunter AG ++ ++usb:v2A03p0001* ++ ID_MODEL_FROM_DATABASE=Linino One (CDC ACM) ++ ++usb:v2A03p8001* ++ ID_MODEL_FROM_DATABASE=Linino ONE board ++ + usb:v2C02* + ID_VENDOR_FROM_DATABASE=Planex Communications + diff --git a/SOURCES/0095-networkd-Begin-with-serial-number-1-for-netlink-requ.patch b/SOURCES/0095-networkd-Begin-with-serial-number-1-for-netlink-requ.patch new file mode 100644 index 00000000..ee3b7cb6 --- /dev/null +++ b/SOURCES/0095-networkd-Begin-with-serial-number-1-for-netlink-requ.patch @@ -0,0 +1,45 @@ +From 0dd3b68d80bd32ecc5db65d634072390dad581aa Mon Sep 17 00:00:00 2001 +From: Richard Maw +Date: Thu, 12 Mar 2015 18:14:58 +0000 +Subject: [PATCH] networkd: Begin with serial number 1 for netlink requests + +"Notifications are of informal nature and no reply is expected, therefore the +sequence number is typically set to 0."[1] + +If networkd is started soon after recent netlink activity, then there +will be messages with sequence number 0 in the buffer. + +The first thing networkd does is to request a dump of all the links. If +it uses sequence number 0 for this, then it may confuse the dump request's +response with that of a notification. + +This will result in it failing to properly enumerate all the links, +but more importantly, when it comes to enumerate all the addresses, it +will still have the link dump in progress, so the address enumeration +will fail with -EBUSY. + +[1]: http://www.infradead.org/~tgr/libnl/doc/core.html#core_msg_types + +[tomegun: sequence -> serial] + +(cherry picked from commit d422e52a3523ad0955bec4f9fbed46e234d28590) +--- + src/libsystemd/sd-rtnl/sd-rtnl.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c +index ae49c77e0..7cdcc5d96 100644 +--- a/src/libsystemd/sd-rtnl/sd-rtnl.c ++++ b/src/libsystemd/sd-rtnl/sd-rtnl.c +@@ -61,6 +61,11 @@ static int sd_rtnl_new(sd_rtnl **ret) { + sizeof(struct nlmsghdr), sizeof(uint8_t))) + return -ENOMEM; + ++ /* Change notification responses have sequence 0, so we must ++ * start our request sequence numbers at 1, or we may confuse our ++ * responses with notifications from the kernel */ ++ rtnl->serial = 1; ++ + *ret = rtnl; + rtnl = NULL; + diff --git a/SOURCES/0096-journal-remote-downgrade-routine-messages-to-debug.patch b/SOURCES/0096-journal-remote-downgrade-routine-messages-to-debug.patch new file mode 100644 index 00000000..ce6a7181 --- /dev/null +++ b/SOURCES/0096-journal-remote-downgrade-routine-messages-to-debug.patch @@ -0,0 +1,179 @@ +From c546fffcff0d2e3522738aac30391d5996bdf4a6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 12 Mar 2015 21:29:28 -0400 +Subject: [PATCH] journal-remote: downgrade routine messages to debug + +https://bugs.freedesktop.org/show_bug.cgi?id=89486 +(cherry picked from commit 0e72da6fe8671d49b4d458519f5ac7600fd04f03) +--- + src/journal-remote/journal-remote-parse.c | 2 +- + src/journal-remote/journal-remote-write.c | 2 +- + src/journal-remote/journal-remote.c | 36 +++++++++++++++---------------- + src/journal-remote/microhttpd-util.c | 4 ++-- + 4 files changed, 22 insertions(+), 22 deletions(-) + +diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c +index afded7e38..6c096de03 100644 +--- a/src/journal-remote/journal-remote-parse.c ++++ b/src/journal-remote/journal-remote-parse.c +@@ -443,7 +443,7 @@ int process_source(RemoteSource *source, bool compress, bool seal) { + return r; + + /* We have a full event */ +- log_trace("Received a full event from source@%p fd:%d (%s)", ++ log_trace("Received full event from source@%p fd:%d (%s)", + source, source->fd, source->name); + + if (!source->iovw.count) { +diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c +index df3004939..99820fa7b 100644 +--- a/src/journal-remote/journal-remote-write.c ++++ b/src/journal-remote/journal-remote-write.c +@@ -156,7 +156,7 @@ int writer_write(Writer *w, + if (r < 0) + return r; + else +- log_info("%s: Successfully rotated journal", w->journal->path); ++ log_debug("%s: Successfully rotated journal", w->journal->path); + + log_debug("Retrying write."); + r = journal_file_append_entry(w->journal, ts, iovw->iovec, iovw->count, +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index 8f32a9a98..d1486e7cd 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -207,7 +207,7 @@ static int open_output(Writer *w, const char* host) { + log_error_errno(r, "Failed to open output journal %s: %m", + output); + else +- log_info("Opened output file %s", w->journal->path); ++ log_debug("Opened output file %s", w->journal->path); + return r; + } + +@@ -747,7 +747,7 @@ static int setup_microhttpd_socket(RemoteServer *s, + const char *trust) { + int fd; + +- fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC); ++ fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM | SOCK_CLOEXEC); + if (fd < 0) + return fd; + +@@ -844,7 +844,7 @@ static int remoteserver_init(RemoteServer *s, + if (n < 0) + return log_error_errno(n, "Failed to read listening file descriptors from environment: %m"); + else +- log_info("Received %d descriptors", n); ++ log_debug("Received %d descriptors", n); + + if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) { + log_error("Received fewer sockets than expected"); +@@ -853,7 +853,7 @@ static int remoteserver_init(RemoteServer *s, + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { + if (sd_is_socket(fd, AF_UNSPEC, 0, true)) { +- log_info("Received a listening socket (fd:%d)", fd); ++ log_debug("Received a listening socket (fd:%d)", fd); + + if (fd == http_socket) + r = setup_microhttpd_server(s, fd, NULL, NULL, NULL); +@@ -868,7 +868,7 @@ static int remoteserver_init(RemoteServer *s, + if (r < 0) + return log_error_errno(r, "Failed to retrieve remote name: %m"); + +- log_info("Received a connection socket (fd:%d) from %s", fd, hostname); ++ log_debug("Received a connection socket (fd:%d) from %s", fd, hostname); + + r = add_source(s, fd, hostname, true); + } else { +@@ -908,7 +908,7 @@ static int remoteserver_init(RemoteServer *s, + } + + if (arg_listen_raw) { +- log_info("Listening on a socket..."); ++ log_debug("Listening on a socket..."); + r = setup_raw_socket(s, arg_listen_raw); + if (r < 0) + return r; +@@ -930,12 +930,12 @@ static int remoteserver_init(RemoteServer *s, + const char *output_name; + + if (streq(*file, "-")) { +- log_info("Using standard input as source."); ++ log_debug("Using standard input as source."); + + fd = STDIN_FILENO; + output_name = "stdin"; + } else { +- log_info("Reading file %s...", *file); ++ log_debug("Reading file %s...", *file); + + fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); + if (fd < 0) +@@ -1014,22 +1014,22 @@ static int dispatch_raw_source_event(sd_event_source *event, + if (source->state == STATE_EOF) { + size_t remaining; + +- log_info("EOF reached with source fd:%d (%s)", +- source->fd, source->name); ++ log_debug("EOF reached with source fd:%d (%s)", ++ source->fd, source->name); + + remaining = source_non_empty(source); + if (remaining > 0) +- log_warning("Premature EOF. %zu bytes lost.", remaining); ++ log_notice("Premature EOF. %zu bytes lost.", remaining); + remove_source(s, source->fd); +- log_info("%zu active sources remaining", s->active); ++ log_debug("%zu active sources remaining", s->active); + return 0; + } else if (r == -E2BIG) { +- log_error("Entry too big, skipped"); ++ log_notice_errno(E2BIG, "Entry too big, skipped"); + return 1; + } else if (r == -EAGAIN) { + return 0; + } else if (r < 0) { +- log_info_errno(r, "Closing connection: %m"); ++ log_debug_errno(r, "Closing connection: %m"); + remove_source(server, fd); + return 0; + } else +@@ -1071,10 +1071,10 @@ static int accept_connection(const char* type, int fd, + return r; + } + +- log_info("Accepted %s %s connection from %s", +- type, +- socket_address_family(addr) == AF_INET ? "IP" : "IPv6", +- a); ++ log_debug("Accepted %s %s connection from %s", ++ type, ++ socket_address_family(addr) == AF_INET ? "IP" : "IPv6", ++ a); + + *hostname = b; + +diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c +index a95fff18f..b45c38d68 100644 +--- a/src/journal-remote/microhttpd-util.c ++++ b/src/journal-remote/microhttpd-util.c +@@ -178,7 +178,7 @@ static int verify_cert_authorized(gnutls_session_t session) { + if (r < 0) + return log_error_errno(r, "gnutls_certificate_verification_status_print failed: %m"); + +- log_info("Certificate status: %s", out.data); ++ log_debug("Certificate status: %s", out.data); + gnutls_free(out.data); + + return status == 0 ? 0 : -EPERM; +@@ -280,7 +280,7 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn + return -EPERM; + } + +- log_info("Connection from %s", buf); ++ log_debug("Connection from %s", buf); + + if (hostname) { + *hostname = buf; diff --git a/SOURCES/0097-journal-remote-process-events-without-delay.patch b/SOURCES/0097-journal-remote-process-events-without-delay.patch new file mode 100644 index 00000000..44854943 --- /dev/null +++ b/SOURCES/0097-journal-remote-process-events-without-delay.patch @@ -0,0 +1,156 @@ +From 47ac92420da9ecbffaf3aa0046d170be358639a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 13 Mar 2015 00:02:28 -0400 +Subject: [PATCH] journal-remote: process events without delay + +journal-remote buffers input, and then parses it handling one journal entry at a time. +It was possible for useful data to be left in the buffer after some entries were +processesed. But all data would be already read from the fd, so there would be +no reason for the event loop to call the handler again. After some new data came in, +the handler would be called again, and would then process the "old" data in the buffer. + +Fix this by enabling a handler wherever we process input data and do not exhaust data +from the input buffer (i.e. when EAGAIN was not encountered). The handler runs until +we encounter EAGAIN. + +Looping over the input data is done in this roundabout way to allow the event loop +to dispatch other events in the meanwhile. If the loop was inside the handler, a +source which produced data fast enough could completely monopolize the process. + +https://bugs.freedesktop.org/show_bug.cgi?id=89516 +(cherry picked from commit 043945b93824e33e040954612aaa934cd1a43a1b) +--- + src/journal-remote/journal-remote-parse.c | 1 + + src/journal-remote/journal-remote-parse.h | 1 + + src/journal-remote/journal-remote.c | 65 +++++++++++++++++++++++++++---- + 3 files changed, 59 insertions(+), 8 deletions(-) + +diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c +index 6c096de03..7e6295435 100644 +--- a/src/journal-remote/journal-remote-parse.c ++++ b/src/journal-remote/journal-remote-parse.c +@@ -41,6 +41,7 @@ void source_free(RemoteSource *source) { + writer_unref(source->writer); + + sd_event_source_unref(source->event); ++ sd_event_source_unref(source->buffer_event); + + free(source); + } +diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h +index 22db55091..06a50296a 100644 +--- a/src/journal-remote/journal-remote-parse.h ++++ b/src/journal-remote/journal-remote-parse.h +@@ -54,6 +54,7 @@ typedef struct RemoteSource { + Writer *writer; + + sd_event_source *event; ++ sd_event_source *buffer_event; + } RemoteSource; + + RemoteSource* source_new(int fd, bool passive_fd, char *name, Writer *writer); +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index d1486e7cd..b7cc6d717 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -289,6 +289,8 @@ static int dispatch_raw_source_event(sd_event_source *event, + int fd, + uint32_t revents, + void *userdata); ++static int dispatch_raw_source_until_block(sd_event_source *event, ++ void *userdata); + static int dispatch_blocking_source_event(sd_event_source *event, + void *userdata); + static int dispatch_raw_connection_event(sd_event_source *event, +@@ -376,8 +378,15 @@ static int add_source(RemoteServer *s, int fd, char* name, bool own_name) { + + r = sd_event_add_io(s->events, &source->event, + fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI, +- dispatch_raw_source_event, s); +- if (r == -EPERM) { ++ dispatch_raw_source_event, source); ++ if (r == 0) { ++ /* Add additional source for buffer processing. It will be ++ * enabled later. */ ++ r = sd_event_add_defer(s->events, &source->buffer_event, ++ dispatch_raw_source_until_block, source); ++ if (r == 0) ++ sd_event_source_set_enabled(source->buffer_event, SD_EVENT_OFF); ++ } else if (r == -EPERM) { + log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name); + r = sd_event_add_defer(s->events, &source->event, + dispatch_blocking_source_event, source); +@@ -997,15 +1006,18 @@ static void server_destroy(RemoteServer *s) { + ********************************************************************** + **********************************************************************/ + +-static int dispatch_raw_source_event(sd_event_source *event, +- int fd, +- uint32_t revents, +- void *userdata) { ++static int handle_raw_source(sd_event_source *event, ++ int fd, ++ uint32_t revents, ++ RemoteServer *s) { + +- RemoteServer *s = userdata; + RemoteSource *source; + int r; + ++ /* Returns 1 if there might be more data pending, ++ * 0 if data is currently exhausted, negative on error. ++ */ ++ + assert(fd >= 0 && fd < (ssize_t) s->sources_size); + source = s->sources[fd]; + assert(source->fd == fd); +@@ -1036,11 +1048,48 @@ static int dispatch_raw_source_event(sd_event_source *event, + return 1; + } + ++static int dispatch_raw_source_until_block(sd_event_source *event, ++ void *userdata) { ++ RemoteSource *source = userdata; ++ int r; ++ ++ /* Make sure event stays around even if source is destroyed */ ++ sd_event_source_ref(event); ++ ++ r = handle_raw_source(event, source->fd, EPOLLIN, server); ++ if (r != 1) ++ /* No more data for now */ ++ sd_event_source_set_enabled(event, SD_EVENT_OFF); ++ ++ sd_event_source_unref(event); ++ ++ return r; ++} ++ ++static int dispatch_raw_source_event(sd_event_source *event, ++ int fd, ++ uint32_t revents, ++ void *userdata) { ++ RemoteSource *source = userdata; ++ int r; ++ ++ assert(source->event); ++ assert(source->buffer_event); ++ ++ r = handle_raw_source(event, fd, EPOLLIN, server); ++ if (r == 1) ++ /* Might have more data. We need to rerun the handler ++ * until we are sure the buffer is exhausted. */ ++ sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON); ++ ++ return r; ++} ++ + static int dispatch_blocking_source_event(sd_event_source *event, + void *userdata) { + RemoteSource *source = userdata; + +- return dispatch_raw_source_event(event, source->fd, EPOLLIN, server); ++ return handle_raw_source(event, source->fd, EPOLLIN, server); + } + + static int accept_connection(const char* type, int fd, diff --git a/SOURCES/0098-man-update-example-2-in-systemd.network-5.patch b/SOURCES/0098-man-update-example-2-in-systemd.network-5.patch new file mode 100644 index 00000000..35908f5c --- /dev/null +++ b/SOURCES/0098-man-update-example-2-in-systemd.network-5.patch @@ -0,0 +1,26 @@ +From 131de4184e86e7096d987973d7c4918f8303fa4b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 13 Mar 2015 00:25:31 -0400 +Subject: [PATCH] man: update example 2 in systemd.network(5) + +none/both/v4/v6 are deprecated in favour of no/yes/ipv4/ipv6. + +https://bugs.freedesktop.org/show_bug.cgi?id=89221 +(cherry picked from commit 9c8ca3f7a69f82ca181b3cd2d5e1d3e621938abb) +--- + man/systemd.network.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemd.network.xml b/man/systemd.network.xml +index 485876b6a..24f8416ef 100644 +--- a/man/systemd.network.xml ++++ b/man/systemd.network.xml +@@ -643,7 +643,7 @@ Gateway=192.168.0.1 + Name=en* + + [Network] +-DHCP=both ++DHCP=yes + + + diff --git a/SOURCES/0099-gpt-auto-generator-fix-detection-of-srv.patch b/SOURCES/0099-gpt-auto-generator-fix-detection-of-srv.patch new file mode 100644 index 00000000..3a73255a --- /dev/null +++ b/SOURCES/0099-gpt-auto-generator-fix-detection-of-srv.patch @@ -0,0 +1,24 @@ +From a9c2be5c2e43bd5fb37dd45f84e6787f4abec23f Mon Sep 17 00:00:00 2001 +From: Mathieu Chevrier +Date: Fri, 13 Mar 2015 00:33:44 -0400 +Subject: [PATCH] gpt-auto-generator: fix detection of /srv + +https://bugs.freedesktop.org/show_bug.cgi?id=89226 +(cherry picked from commit d736e4f3e76daca4ab1b1fc444737e5ee20a27cd) +--- + src/gpt-auto-generator/gpt-auto-generator.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c +index 7d5a6c650..cceeeb845 100644 +--- a/src/gpt-auto-generator/gpt-auto-generator.c ++++ b/src/gpt-auto-generator/gpt-auto-generator.c +@@ -549,7 +549,7 @@ static int enumerate_partitions(dev_t devnum) { + srv_rw = !(flags & GPT_FLAG_READ_ONLY), + + free(srv); +- srv = strdup(node); ++ srv = strdup(subnode); + if (!srv) + return log_oom(); + } diff --git a/SOURCES/0100-sd-rtnl-never-set-serial-to-0.patch b/SOURCES/0100-sd-rtnl-never-set-serial-to-0.patch new file mode 100644 index 00000000..09542c23 --- /dev/null +++ b/SOURCES/0100-sd-rtnl-never-set-serial-to-0.patch @@ -0,0 +1,28 @@ +From fc9d7a3891dc293cccd4e127cfb1e2355f4e93da Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 13 Mar 2015 15:49:07 +0100 +Subject: [PATCH] sd-rtnl: never set serial to 0 + +In the unlikely event that we wrap the counter, skip 0 as this is used +for broadcasts. + +Suggested by Richard Maw. + +(cherry picked from commit 913b0eef1a01e0c78f0453b0174e75d5caae1023) +--- + src/libsystemd/sd-rtnl/sd-rtnl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c +index 7cdcc5d96..5df39e117 100644 +--- a/src/libsystemd/sd-rtnl/sd-rtnl.c ++++ b/src/libsystemd/sd-rtnl/sd-rtnl.c +@@ -262,7 +262,7 @@ static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) { + assert(m); + assert(m->hdr); + +- m->hdr->nlmsg_seq = rtnl->serial++; ++ m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++; + + rtnl_message_seal(m); + diff --git a/SOURCES/0101-gpt-auto-generator-allow-type-check-to-fail.patch b/SOURCES/0101-gpt-auto-generator-allow-type-check-to-fail.patch new file mode 100644 index 00000000..0061d564 --- /dev/null +++ b/SOURCES/0101-gpt-auto-generator-allow-type-check-to-fail.patch @@ -0,0 +1,45 @@ +From e2353e7c13808e47efb844f8fb10b7aa2142e619 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 13 Mar 2015 21:10:13 -0500 +Subject: [PATCH] gpt-auto-generator: allow type check to fail + +add_mount() is OK with unknow file type, but we have to initalize +the variable to NULL not to pass garbage on error. + +(cherry picked from commit a0b1209c4a59754f428894e0485413542da50014) +--- + src/gpt-auto-generator/gpt-auto-generator.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c +index cceeeb845..00a2141a5 100644 +--- a/src/gpt-auto-generator/gpt-auto-generator.c ++++ b/src/gpt-auto-generator/gpt-auto-generator.c +@@ -291,7 +291,7 @@ static int probe_and_add_mount( + const char *post) { + + _cleanup_blkid_free_probe_ blkid_probe b = NULL; +- const char *fstype; ++ const char *fstype = NULL; + int r; + + assert(id); +@@ -324,14 +324,11 @@ static int probe_and_add_mount( + r = blkid_do_safeprobe(b); + if (r == -2 || r == 1) /* no result or uncertain */ + return 0; +- else if (r != 0) { +- if (errno == 0) +- errno = EIO; +- log_error_errno(errno, "Failed to probe %s: %m", what); +- return -errno; +- } ++ else if (r != 0) ++ return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what); + +- blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); ++ /* add_mount is OK with fstype being NULL. */ ++ (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); + + return add_mount( + id, diff --git a/SOURCES/0102-man-fix-a-bunch-of-links.patch b/SOURCES/0102-man-fix-a-bunch-of-links.patch new file mode 100644 index 00000000..584f2a05 --- /dev/null +++ b/SOURCES/0102-man-fix-a-bunch-of-links.patch @@ -0,0 +1,1453 @@ +From a0def1365a2c50f7e1d4ec14c104bfe5cbd8bf8a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 13 Mar 2015 21:22:39 -0500 +Subject: [PATCH] man: fix a bunch of links + +All hail linkchecker! + +(cherry picked from commit 3ba3a79df4ae094d1008c04a9af8d1ff970124c4) + +Conflicts: + man/systemd-efi-boot-generator.xml +--- + man/busctl.xml | 4 ++-- + man/crypttab.xml | 20 +++++++++---------- + man/file-hierarchy.xml | 2 +- + man/kernel-command-line.xml | 2 +- + man/locale.conf.xml | 8 ++++---- + man/localectl.xml | 8 ++++---- + man/logind.conf.xml | 2 +- + man/machine-id.xml | 4 ++-- + man/modules-load.d.xml | 2 +- + man/os-release.xml | 2 +- + man/sd_bus_message_append.xml | 2 +- + man/sd_bus_open_user.xml | 2 +- + man/sd_event_add_signal.xml | 4 ++-- + man/sd_journal_get_catalog.xml | 2 +- + man/sd_journal_get_cursor.xml | 2 +- + man/sd_journal_print.xml | 14 ++++++------- + man/sysctl.d.xml | 8 ++++---- + man/systemctl.xml | 6 +++--- + man/systemd-activate.xml | 2 +- + man/systemd-analyze.xml | 4 ++-- + man/systemd-cat.xml | 2 +- + man/systemd-cryptsetup-generator.xml | 2 +- + man/systemd-cryptsetup@.service.xml | 2 +- + man/systemd-efi-boot-generator.xml | 4 ++-- + man/systemd-firstboot.xml | 14 ++++++------- + man/systemd-fstab-generator.xml | 4 ++-- + man/systemd-gpt-auto-generator.xml | 8 ++++---- + man/systemd-hibernate-resume-generator.xml | 2 +- + man/systemd-journald.service.xml | 2 +- + man/systemd-localed.service.xml | 8 ++++---- + man/systemd-nspawn.xml | 4 ++-- + man/systemd-quotacheck.service.xml | 2 +- + man/systemd-remount-fs.service.xml | 6 +++--- + man/systemd-socket-proxyd.xml | 8 ++++---- + man/systemd-sysctl.service.xml | 8 ++++---- + man/systemd-system.conf.xml | 2 +- + man/systemd-update-utmp.service.xml | 2 +- + man/systemd-vconsole-setup.service.xml | 8 ++++---- + man/systemd.automount.xml | 6 +++--- + man/systemd.exec.xml | 16 +++++++-------- + man/systemd.generator.xml | 2 +- + man/systemd.journal-fields.xml | 2 +- + man/systemd.kill.xml | 4 ++-- + man/systemd.mount.xml | 14 ++++++------- + man/systemd.network.xml | 8 ++++---- + man/systemd.path.xml | 4 ++-- + man/systemd.socket.xml | 32 +++++++++++++++--------------- + man/systemd.swap.xml | 10 +++++----- + man/systemd.unit.xml | 4 ++-- + man/systemd.xml | 6 +++--- + man/vconsole.conf.xml | 6 +++--- + 51 files changed, 151 insertions(+), 151 deletions(-) + +diff --git a/man/busctl.xml b/man/busctl.xml +index 251233bb9..cc1844b0a 100644 +--- a/man/busctl.xml ++++ b/man/busctl.xml +@@ -288,7 +288,7 @@ + url="http://wiki.wireshark.org/Development/LibpcapFileFormat">Libpcap + File Format description. Make sure to redirect the + output to STDOUT to a file. Tools like +- wireshark1 ++ wireshark1 + may be used to dissect and view the generated + files. + +@@ -472,7 +472,7 @@ o "/org/freedesktop/systemd1/job/42684" + systemd1, + systemd-bus-proxyd8, + machinectl1, +- wireshark1 ++ wireshark1 + + + +diff --git a/man/crypttab.xml b/man/crypttab.xml +index aeacc5797..3e249ad23 100644 +--- a/man/crypttab.xml ++++ b/man/crypttab.xml +@@ -75,7 +75,7 @@ + + Setting up encrypted block devices using this file supports + three encryption modes: LUKS, TrueCrypt and plain. See +- cryptsetup8 ++ cryptsetup8 + for more information about each mode. When no mode is specified in + the options field and the block device contains a LUKS signature, + it is opened as a LUKS device; otherwise, it is assumed to be in +@@ -117,7 +117,7 @@ + + + Specifies the cipher to use. See +- cryptsetup8 ++ cryptsetup8 + for possible values and the default value of this option. A + cipher with unpredictable IV values, such as + aes-cbc-essiv:sha256, is +@@ -129,7 +129,7 @@ + + Specifies the hash to use for password + hashing. See +- cryptsetup8 ++ cryptsetup8 + for possible values and the default value of this + option. + +@@ -140,7 +140,7 @@ + Use a detached (separated) metadata device or + file where the LUKS header is stored. This option is only + relevant for LUKS devices. See +- cryptsetup8 ++ cryptsetup8 + for possible values and the default value of this + option. + +@@ -150,7 +150,7 @@ + + Specifies the number of bytes to skip at the + start of the key file. See +- cryptsetup8 ++ cryptsetup8 + for possible values and the default value of this + option. + +@@ -160,7 +160,7 @@ + + Specifies the maximum number of bytes to read + from the key file. See +- cryptsetup8 ++ cryptsetup8 + for possible values and the default value of this option. This + option is ignored in plain encryption mode, as the key file + size is then given by the key size. +@@ -174,7 +174,7 @@ + given passphrase or key, but another would, the setup of the + device will fail regardless. This option implies + . See +- cryptsetup8 ++ cryptsetup8 + for possible values. The default is to try all key slots in + sequential order. + +@@ -221,7 +221,7 @@ + + + Specifies the key size in bits. See +- cryptsetup8 ++ cryptsetup8 + for possible values and the default value of this + option. + +@@ -278,7 +278,7 @@ + volume provided in the second field. Please note that there is + no protection for the hidden volume if the outer volume is + mounted instead. See +- cryptsetup8 ++ cryptsetup8 + for more information on this limitation. + + +@@ -383,7 +383,7 @@ hidden /mnt/tc_hidden /dev/null tcrypt-hidden,tcrypt-keyfile=/etc/keyfil + systemd1, + systemd-cryptsetup@.service8, + systemd-cryptsetup-generator8, +- cryptsetup8, ++ cryptsetup8, + mkswap8, + mke2fs8 + +diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml +index e9c894f5c..364e13079 100644 +--- a/man/file-hierarchy.xml ++++ b/man/file-hierarchy.xml +@@ -397,7 +397,7 @@ + /dev/shm + Place for POSIX shared memory segments, as + created via +- shm_open3. ++ shm_open3. + This directory is flushed on boot, and is a + tmpfs file system. Since all users have + write access to this directory, special care should be taken +diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml +index 3741cf9cc..919bd1374 100644 +--- a/man/kernel-command-line.xml ++++ b/man/kernel-command-line.xml +@@ -336,7 +336,7 @@ + + Enables resume from hibernation using the specified + device. All +- fstab5-like ++ fstab5-like + paths are supported. For details, see + systemd-hibernate-resume-generator8. + +diff --git a/man/locale.conf.xml b/man/locale.conf.xml +index 48c0006db..2c32d1609 100644 +--- a/man/locale.conf.xml ++++ b/man/locale.conf.xml +@@ -91,7 +91,7 @@ + might be checked for locale configuration as well, however only as + fallback. + +- localectl1 ++ localectl1 + may be used to alter the settings in this file during runtime from + the command line. Use + systemd-firstboot1 +@@ -121,7 +121,7 @@ + Note that LC_ALL may not be configured in this + file. For details about the meaning and semantics of these + settings, refer to +- locale7. ++ locale7. + + + +@@ -142,8 +142,8 @@ LC_MESSAGES=en_US.UTF-8 + See Also + + systemd1, +- locale7, +- localectl1, ++ locale7, ++ localectl1, + systemd-localed.service8, + systemd-firstboot1 + +diff --git a/man/localectl.xml b/man/localectl.xml +index aae6e0629..7def047f6 100644 +--- a/man/localectl.xml ++++ b/man/localectl.xml +@@ -124,7 +124,7 @@ + Set the system locale. This takes one or more + assignments such as "LANG=de_DE.utf8", + "LC_MESSAGES=en_GB.utf8", and so on. See +- locale7 ++ locale7 + for details on the available settings and their meanings. Use + list-locales for a list of available + locales (see below). +@@ -204,10 +204,10 @@ + See Also + + systemd1, +- locale7, +- locale.conf5, ++ locale7, ++ locale.conf5, + vconsole.conf5, +- loadkeys1, ++ loadkeys1, + kbd4, + + The XKB Configuration Guide +diff --git a/man/logind.conf.xml b/man/logind.conf.xml +index ca2b18783..d02d57356 100644 +--- a/man/logind.conf.xml ++++ b/man/logind.conf.xml +@@ -126,7 +126,7 @@ + + Note that setting KillUserProcesses=1 + will break tools like +- screen1. ++ screen1. + + + +diff --git a/man/machine-id.xml b/man/machine-id.xml +index 83e0b26ce..92d67a386 100644 +--- a/man/machine-id.xml ++++ b/man/machine-id.xml +@@ -75,7 +75,7 @@ + globally unique ID in the network, which does not change even if + the local network configuration changes. Due to this and its + greater length, it is a more useful replacement for the +- gethostid3 ++ gethostid3 + call that POSIX specifies. + + The +@@ -127,7 +127,7 @@ id[8] = (id[8] & 0x3F) | 0x80; + + systemd1, + systemd-machine-id-setup1, +- gethostid3, ++ gethostid3, + hostname5, + machine-info5, + os-release5, +diff --git a/man/modules-load.d.xml b/man/modules-load.d.xml +index 34a937db6..4b722aa12 100644 +--- a/man/modules-load.d.xml ++++ b/man/modules-load.d.xml +@@ -94,7 +94,7 @@ virtio-net + systemd1, + systemd-modules-load.service8, + systemd-delta1, +- modprobe8 ++ modprobe8 + + + +diff --git a/man/os-release.xml b/man/os-release.xml +index 1b71a49d0..8f4ab10fe 100644 +--- a/man/os-release.xml ++++ b/man/os-release.xml +@@ -316,7 +316,7 @@ BUG_REPORT_URL="https://bugzilla.redhat.com/" + See Also + + systemd1, +- lsb_release1, ++ lsb_release1, + hostname5, + machine-id5, + machine-info5 +diff --git a/man/sd_bus_message_append.xml b/man/sd_bus_message_append.xml +index 0c49a0c7c..11fa07c63 100644 +--- a/man/sd_bus_message_append.xml ++++ b/man/sd_bus_message_append.xml +@@ -245,7 +245,7 @@ sd_bus_message_append(m, "ynqiuxtd", y, n, q, i, u, x, t, d); + sd_bus_new3, + sd_bus_ref3, + sd_bus_unref3, +- ssh1, ++ ssh1, + systemd-machined.service8, + machinectl1 + +diff --git a/man/sd_bus_open_user.xml b/man/sd_bus_open_user.xml +index e7a765962..2bbb01069 100644 +--- a/man/sd_bus_open_user.xml ++++ b/man/sd_bus_open_user.xml +@@ -208,7 +208,7 @@ along with systemd; If not, see . + sd_bus_new3, + sd_bus_ref3, + sd_bus_unref3, +- ssh1, ++ ssh1, + systemd-machined.service8, + machinectl1 + +diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml +index 0299aa5a5..7c8df7df8 100644 +--- a/man/sd_event_add_signal.xml ++++ b/man/sd_event_add_signal.xml +@@ -86,7 +86,7 @@ along with systemd; If not, see . + the source parameter. The + signal parameter specifies the signal to be handled + (see +- signal7). ++ signal7). + The handler must reference a function to + call when the signal is delivered or be NULL. + The handler function will be passed the +@@ -94,7 +94,7 @@ along with systemd; If not, see . + freely by the caller. The handler also receives a pointer to a + const struct signalfd_siginfo containing + the information about the received signal. See +- signalfd2 ++ signalfd2 + for further information. + + Only a single handler may be installed for a specific +diff --git a/man/sd_journal_get_catalog.xml b/man/sd_journal_get_catalog.xml +index 1dcbadd18..c19eb11b2 100644 +--- a/man/sd_journal_get_catalog.xml ++++ b/man/sd_journal_get_catalog.xml +@@ -130,7 +130,7 @@ + sd_journal_open3, + sd_journal_next3, + sd_journal_get_data3, +- malloc3 ++ malloc3 + + + +diff --git a/man/sd_journal_get_cursor.xml b/man/sd_journal_get_cursor.xml +index 2b7f443f2..a400d8b1b 100644 +--- a/man/sd_journal_get_cursor.xml ++++ b/man/sd_journal_get_cursor.xml +@@ -84,7 +84,7 @@ + time) available entry. The call takes two arguments: a journal + context object and a pointer to a string pointer where the cursor + string will be placed. The string is allocated via libc +- malloc3 ++ malloc3 + and should be freed after use with + free3. + +diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml +index 068b10e7c..0cd0b45b9 100644 +--- a/man/sd_journal_print.xml ++++ b/man/sd_journal_print.xml +@@ -119,7 +119,7 @@ + sd_journal_print() but takes a variable + argument list encapsulated in an object of type + va_list (see +- stdarg3 ++ stdarg3 + for more information) instead of the format string. It is + otherwise equivalent in behavior. + +@@ -145,7 +145,7 @@ + sd_journal_send() but takes an array of + struct iovec (as defined in + uio.h, see +- readv3 ++ readv3 + for details) instead of the format string. Each structure should + reference one field of the entry to submit. The second argument + specifies the number of structures in the array. +@@ -154,7 +154,7 @@ + necessary. + + sd_journal_perror() is a similar to +- perror3 ++ perror3 + and writes a message to the journal that consists of the passed + string, suffixed with ": " and a human readable representation of + the current error code stored in +@@ -219,7 +219,7 @@ sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid( + Async signal safety + sd_journal_sendv() is "async signal + safe" in the meaning of +- signal7. ++ signal7. + + + sd_journal_print, +@@ -249,11 +249,11 @@ sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid( + sd-journal3, + sd_journal_stream_fd3, + syslog3, +- perror3, ++ perror3, + errno3, + systemd.journal-fields7, +- signal7, +- socket7 ++ signal7, ++ socket7 + + + +diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml +index 5a35cfe2c..8a131791a 100644 +--- a/man/sysctl.d.xml ++++ b/man/sysctl.d.xml +@@ -57,7 +57,7 @@ + At boot, + systemd-sysctl.service8 + reads configuration files from the above directories to configure +- sysctl8 ++ sysctl8 + kernel parameters. + + +@@ -162,9 +162,9 @@ net.bridge.bridge-nf-call-arptables = 0 + systemd1, + systemd-sysctl.service8, + systemd-delta1, +- sysctl8, +- sysctl.conf5, +- modprobe8 ++ sysctl8, ++ sysctl.conf5, ++ modprobe8 + + + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 6f30474c3..07eb43165 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -1703,9 +1703,9 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + $VISUAL are present or if it is set to an empty + string or if their execution failed, systemctl will try to execute well + known editors in this order: +- nano1, +- vim1, +- vi1. ++ nano1, ++ vim1, ++ vi1. + + + +diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml +index e64894a28..cb68a79be 100644 +--- a/man/systemd-activate.xml ++++ b/man/systemd-activate.xml +@@ -165,7 +165,7 @@ + systemd1, + systemd.socket5, + systemd.service5, +- cat1 ++ cat1 + + + +diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml +index 1ff81d3d5..198315052 100644 +--- a/man/systemd-analyze.xml ++++ b/man/systemd-analyze.xml +@@ -145,7 +145,7 @@ + systemd-analyze dot generates textual + dependency graph description in dot format for further processing + with the GraphViz +- dot1 ++ dot1 + tool. Use a command line like systemd-analyze dot | dot + -Tsvg > systemd.svg to generate a graphical dependency + tree. Unless or +@@ -229,7 +229,7 @@ + dot command (see above), this selects which + relationships are shown in the dependency graph. Both options + require a +- glob7 ++ glob7 + pattern as an argument, which will be matched against the + left-hand and the right-hand, respectively, nodes of a + relationship. +diff --git a/man/systemd-cat.xml b/man/systemd-cat.xml +index 38ddf66d2..9b1a8809d 100644 +--- a/man/systemd-cat.xml ++++ b/man/systemd-cat.xml +@@ -171,7 +171,7 @@ + + systemd1, + systemctl1, +- logger1 ++ logger1 + + + +diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml +index 1974cd7a2..b6270358e 100644 +--- a/man/systemd-cryptsetup-generator.xml ++++ b/man/systemd-cryptsetup-generator.xml +@@ -185,7 +185,7 @@ + systemd1, + crypttab5, + systemd-cryptsetup@.service8, +- cryptsetup8, ++ cryptsetup8, + systemd-fstab-generator8 + + +diff --git a/man/systemd-cryptsetup@.service.xml b/man/systemd-cryptsetup@.service.xml +index bd03637de..ea524851e 100644 +--- a/man/systemd-cryptsetup@.service.xml ++++ b/man/systemd-cryptsetup@.service.xml +@@ -78,7 +78,7 @@ + systemd1, + systemd-cryptsetup-generator8, + crypttab5, +- cryptsetup8 ++ cryptsetup8 + + + +diff --git a/man/systemd-efi-boot-generator.xml b/man/systemd-efi-boot-generator.xml +index fd7ba7983..3431c3ce5 100644 +--- a/man/systemd-efi-boot-generator.xml ++++ b/man/systemd-efi-boot-generator.xml +@@ -62,7 +62,7 @@ + does not communicate the used ESP to the OS, on systems where + /boot is an explicitly configured mount (for + example, listed in +- fstab5) ++ fstab5) + or where the /boot mount point is non-empty. + Since this generator creates an automount unit, the mount will + only be activated on-demand, when accessed. +@@ -79,7 +79,7 @@ + systemd.automount5, + systemd-gpt-auto-generator8, + gummiboot8, +- fstab5 ++ fstab5 + + + +diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml +index 67d38ba31..67289daa2 100644 +--- a/man/systemd-firstboot.xml ++++ b/man/systemd-firstboot.xml +@@ -91,7 +91,7 @@ + + Note that this tool operates directly on the file system and + does not involve any running system services, unlike +- localectl1, ++ localectl1, + timedatectl1 + or + hostnamectl1. +@@ -125,7 +125,7 @@ + LANG= and LC_MESSAGES + settings. The argument should be a valid locale identifier, + such as de_DE.UTF-8. This controls the +- locale.conf5 ++ locale.conf5 + configuration file. + + +@@ -163,7 +163,7 @@ + + Sets the password of the system's root user. + This creates a +- shadow5 ++ shadow5 + file. This setting exists in two forms: + accepts the password to set + directly on the command line, +@@ -171,7 +171,7 @@ + Note that it is not recommended specifying passwords on the + command line as other users might be able to see them simply + by invoking +- ps1. ++ ps1. + + + +@@ -244,13 +244,13 @@ + See Also + + systemd1, +- locale.conf5, ++ locale.conf5, + localtime5, + hostname5, + machine-id5, +- shadow5, ++ shadow5, + systemd-machine-id-setup1, +- localectl1, ++ localectl1, + timedatectl1, + hostnamectl1 + +diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml +index 022efb413..bdc2dc1d0 100644 +--- a/man/systemd-fstab-generator.xml ++++ b/man/systemd-fstab-generator.xml +@@ -54,7 +54,7 @@ + + systemd-fstab-generator is a generator + that translates /etc/fstab (see +- fstab5 ++ fstab5 + for details) into native systemd units early at boot and when + configuration of the system manager is reloaded. This will + instantiate mount and swap units as necessary. +@@ -173,7 +173,7 @@ + See Also + + systemd1, +- fstab5, ++ fstab5, + systemd.mount5, + systemd.swap5, + systemd-cryptsetup-generator8 +diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml +index 8d2eaca4f..bcc64ec9b 100644 +--- a/man/systemd-gpt-auto-generator.xml ++++ b/man/systemd-gpt-auto-generator.xml +@@ -66,7 +66,7 @@ + Partitions Specification. Note that this generator has no + effect on non-GPT systems, on systems where the units are + explicitly configured (for example, listed in +- fstab5), ++ fstab5), + or where the mount points are non-empty. + + This generator will only look for root partitions on the +@@ -169,9 +169,9 @@ + systemd-fstab-generator8, + systemd-efi-boot-generator8, + systemd-cryptsetup@.service8, +- cryptsetup8, +- fstab5, +- btrfs8 ++ cryptsetup8, ++ fstab5, ++ btrfs8 + + + +diff --git a/man/systemd-hibernate-resume-generator.xml b/man/systemd-hibernate-resume-generator.xml +index a21782cbf..d811b9b55 100644 +--- a/man/systemd-hibernate-resume-generator.xml ++++ b/man/systemd-hibernate-resume-generator.xml +@@ -73,7 +73,7 @@ + Takes a path to the resume device. Both + persistent block device paths like + /dev/disk/by-foo/bar and +- fstab5-style ++ fstab5-style + specifiers like FOO=bar are + supported. + +diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml +index 6b250b65e..8280d6c87 100644 +--- a/man/systemd-journald.service.xml ++++ b/man/systemd-journald.service.xml +@@ -241,7 +241,7 @@ + systemd.journal-fields7, + sd-journal3, + systemd-coredump8, +- setfacl1, ++ setfacl1, + sd_journal_print4, + pydoc systemd.journal. + +diff --git a/man/systemd-localed.service.xml b/man/systemd-localed.service.xml +index 899916638..06aa78c0e 100644 +--- a/man/systemd-localed.service.xml ++++ b/man/systemd-localed.service.xml +@@ -64,7 +64,7 @@ + unused. + + The tool +- localectl1 ++ localectl1 + is a command line client to this service. + + See the See Also + + systemd1, +- locale.conf5, ++ locale.conf5, + vconsole.conf5, +- localectl1, +- loadkeys1 ++ localectl1, ++ loadkeys1 + + + +diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml +index 4a936d326..65b4c2f29 100644 +--- a/man/systemd-nspawn.xml ++++ b/man/systemd-nspawn.xml +@@ -598,7 +598,7 @@ + + Control the architecture ("personality") + reported by +- uname2 ++ uname2 + in the container. Currently, only x86 and + x86-64 are supported. This is useful when + running a 32-bit container on a 64-bit host. If this setting +@@ -735,7 +735,7 @@ + pacman8, + systemd.slice5, + machinectl1, +- btrfs8 ++ btrfs8 + + + +diff --git a/man/systemd-quotacheck.service.xml b/man/systemd-quotacheck.service.xml +index 2179f11e9..9d4976274 100644 +--- a/man/systemd-quotacheck.service.xml ++++ b/man/systemd-quotacheck.service.xml +@@ -86,7 +86,7 @@ + See Also + + systemd1, +- quotacheck8, ++ quotacheck8, + systemd-fsck@.service8 + + +diff --git a/man/systemd-remount-fs.service.xml b/man/systemd-remount-fs.service.xml +index 7b88ac3f3..8e60e31b5 100644 +--- a/man/systemd-remount-fs.service.xml ++++ b/man/systemd-remount-fs.service.xml +@@ -56,7 +56,7 @@ + + systemd-remount-fs.service is an + early-boot service that applies mount options listed in +- fstab5 ++ fstab5 + to the root file system, the /usr file system + and the kernel API file systems. This is required so that the + mount options of these file systems -- which are pre-mounted by +@@ -80,8 +80,8 @@ + See Also + + systemd1, +- fstab5, +- mount8 ++ fstab5, ++ mount8 + + + +diff --git a/man/systemd-socket-proxyd.xml b/man/systemd-socket-proxyd.xml +index 1c78b656e..0b852e6bc 100644 +--- a/man/systemd-socket-proxyd.xml ++++ b/man/systemd-socket-proxyd.xml +@@ -72,7 +72,7 @@ + to a configured server for each client, and then bidirectionally + forwards data between the two. + This utility's behavior is similar to +- socat1. ++ socat1. + The main differences for systemd-socket-proxyd + are support for socket activation with + Accept=false and an event-driven +@@ -183,9 +183,9 @@ $ curl http://localhost:80/]]> + systemd.socket5, + systemd.service5, + systemctl1, +- socat1, +- nginx1, +- curl1 ++ socat1, ++ nginx1, ++ curl1 + + + +diff --git a/man/systemd-sysctl.service.xml b/man/systemd-sysctl.service.xml +index f35a18a4d..d4c1a7ebe 100644 +--- a/man/systemd-sysctl.service.xml ++++ b/man/systemd-sysctl.service.xml +@@ -56,11 +56,11 @@ + + systemd-sysctl.service is an early-boot + service that configures +- sysctl8 ++ sysctl8 + kernel parameters. + + See +- sysctl.d5 ++ sysctl.d5 + for information about the configuration of this service. + + +@@ -68,8 +68,8 @@ + See Also + + systemd1, +- sysctl.d5, +- sysctl8, ++ sysctl.d5, ++ sysctl8, + + + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index c7bcfaee4..1b74ed38f 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -172,7 +172,7 @@ + capabilities7 + for details. Takes a whitespace-separated list of capability + names as read by +- cap_from_name3. ++ cap_from_name3. + Capabilities listed will be included in the bounding set, all + others are removed. If the list of capabilities is prefixed + with ~, all but the listed capabilities will be included, the +diff --git a/man/systemd-update-utmp.service.xml b/man/systemd-update-utmp.service.xml +index b842d2972..c8a9cb7c9 100644 +--- a/man/systemd-update-utmp.service.xml ++++ b/man/systemd-update-utmp.service.xml +@@ -69,7 +69,7 @@ + + systemd1, + utmp5, +- auditd8 ++ auditd8 + + + +diff --git a/man/systemd-vconsole-setup.service.xml b/man/systemd-vconsole-setup.service.xml +index 59bb5e4e8..7c6ed0899 100644 +--- a/man/systemd-vconsole-setup.service.xml ++++ b/man/systemd-vconsole-setup.service.xml +@@ -57,9 +57,9 @@ + systemd-vconsole-setup.service is an + early-boot service that configures the virtual console font and + console keymap. Internally it calls +- loadkeys1 ++ loadkeys1 + and +- setfont8. ++ setfont8. + + See + vconsole.conf5 +@@ -105,8 +105,8 @@ + + systemd1, + vconsole.conf5, +- loadkeys1, +- setfont8, ++ loadkeys1, ++ setfont8, + systemd-localed.service8 + + +diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml +index 3db65d988..b5b5885cd 100644 +--- a/man/systemd.automount.xml ++++ b/man/systemd.automount.xml +@@ -96,7 +96,7 @@ + + Automount units may either be configured via unit files, or + via /etc/fstab (see +- fstab5 ++ fstab5 + for details). + + For details how systemd parses +@@ -145,8 +145,8 @@ + systemctl1, + systemd.unit5, + systemd.mount5, +- mount8, +- automount8, ++ mount8, ++ automount8, + systemd.directives7 + + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index fdb157864..56b53e601 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -663,7 +663,7 @@ + capabilities7 + for details. Takes a whitespace-separated list of capability + names as read by +- cap_from_name3, ++ cap_from_name3, + e.g. CAP_SYS_ADMIN, + CAP_DAC_OVERRIDE, + CAP_SYS_PTRACE. Capabilities listed will +@@ -711,7 +711,7 @@ + set for the executed process. Take a capability string + describing the effective, permitted and inherited capability + sets as documented in +- cap_from_text3. ++ cap_from_text3. + Note that these capability sets are usually influenced (and + filtered) by the capabilities attached to the executed file. + Due to that CapabilityBoundingSet= is +@@ -881,7 +881,7 @@ + , which control whether mounts in the + file system namespace set up for this unit's processes will + receive or propagate mounts or unmounts. See +- mount2 ++ mount2 + for details. Defaults to . Use + to ensure that mounts and unmounts are + propagated from the host to the container and vice versa. Use +@@ -929,7 +929,7 @@ + authorize the transition. This directive is ignored if SELinux + is disabled. If prefixed by -, all errors + will be ignored. See +- setexeccon3 ++ setexeccon3 + for details. + + +@@ -1076,7 +1076,7 @@ + prefixed with ~ the listed address + families will be applied as blacklist, otherwise as whitelist. + Note that this restricts access to the +- socket2 ++ socket2 + system call only. Sockets passed into the process by other + means (for example, by using socket activation with socket + units, see +@@ -1104,7 +1104,7 @@ + Personality= + + Controls which kernel architecture +- uname2 ++ uname2 + shall report, when invoked by unit processes. Takes one of + x86 and x86-64. This + is useful when running 32-bit services on a 64-bit host +@@ -1166,7 +1166,7 @@ + $LANG + + Locale. Can be set in +- locale.conf5 ++ locale.conf5 + or on the kernel command line (see + systemd1 + and +@@ -1184,7 +1184,7 @@ + login shell. The variables are set for the units that have + User= set, which includes user + systemd instances. See +- passwd5. ++ passwd5. + + + +diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml +index ccb698752..9b39e732e 100644 +--- a/man/systemd.generator.xml ++++ b/man/systemd.generator.xml +@@ -333,7 +333,7 @@ find $dir + systemd-debug-generator8, + systemd-efi-boot-generator8, + systemd-fstab-generator8, +- fstab5, ++ fstab5, + systemd-getty-generator8, + systemd-gpt-auto-generator8, + systemd-hibernate-resume-generator8, +diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml +index 1fd46de31..7d6c5c715 100644 +--- a/man/systemd.journal-fields.xml ++++ b/man/systemd.journal-fields.xml +@@ -134,7 +134,7 @@ + derived from glibc's + program_invocation_short_name variable, + see +- program_invocation_short_name3.) ++ program_invocation_short_name3.) + + + +diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml +index c974e2248..e57f0e724 100644 +--- a/man/systemd.kill.xml ++++ b/man/systemd.kill.xml +@@ -135,7 +135,7 @@ + of shutting down a unit (see above), and is usually followed + by SIGKILL (see above and below). For a + list of valid signals, see +- signal7. ++ signal7. + Defaults to SIGTERM. + + +@@ -176,7 +176,7 @@ + systemd.exec5, + systemd.directives7, + kill2, +- signal7 ++ signal7 + + + +diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml +index 5cbde8b84..fcb9a4416 100644 +--- a/man/systemd.mount.xml ++++ b/man/systemd.mount.xml +@@ -68,7 +68,7 @@ + Additional options are listed in + systemd.exec5, + which define the execution environment the +- mount8 ++ mount8 + binary is executed in, and in + systemd.kill5, + which define the way the processes are terminated, and in +@@ -78,7 +78,7 @@ + particularly useful for mount units specifying a + Type= option or using configuration not + specified in /etc/fstab; +- mount8 ++ mount8 + will refuse options that are not listed in + /etc/fstab if it is not run as UID 0. + +@@ -118,7 +118,7 @@ + + Mount units may either be configured via unit files, or via + /etc/fstab (see +- fstab5 ++ fstab5 + for details). Mounts listed in /etc/fstab + will be converted into native units dynamically at boot and when + the configuration of the system manager is reloaded. In general, +@@ -231,7 +231,7 @@ + What= + Takes an absolute path of a device node, file + or other resource to mount. See +- mount8 ++ mount8 + for details. If this refers to a device node, a dependency on + the respective device unit is automatically created. (See + systemd.device5 +@@ -251,7 +251,7 @@ + + Type= + Takes a string for the file system type. See +- mount8 ++ mount8 + for details. This setting is optional. + + +@@ -270,7 +270,7 @@ + the options specified in Options= is + relaxed, and unknown mount options are tolerated. This + corresponds with +- mount8's ++ mount8's + -s switch. Defaults to + off. + +@@ -321,7 +321,7 @@ + systemd.service5, + systemd.device5, + proc5, +- mount8, ++ mount8, + systemd-fstab-generator8, + systemd.directives7 + +diff --git a/man/systemd.network.xml b/man/systemd.network.xml +index 24f8416ef..97386271d 100644 +--- a/man/systemd.network.xml ++++ b/man/systemd.network.xml +@@ -286,7 +286,7 @@ + separated by a / character. Specify + this key more than once to configure several addresses. + The format of the address must be as described in +- inet_pton3. ++ inet_pton3. + This is a short-hand for an [Address] section only + containing an Address key (see below). This option may be + specified more than once. +@@ -312,7 +312,7 @@ + + The gateway address, which must be in the format + described in +- inet_pton3. ++ inet_pton3. + This is a short-hand for a [Route] section only containing + a Gateway key. This option may be specified more than + once. +@@ -323,7 +323,7 @@ + + A DNS server address, which must be in the format + described in +- inet_pton3. ++ inet_pton3. + This option may be specified more than once. + + +@@ -429,7 +429,7 @@ + + The broadcast address, which must be in the format + described in +- inet_pton3. ++ inet_pton3. + This key only applies to IPv4 addresses. If it is not + given, it is derived from the Address + key. +diff --git a/man/systemd.path.xml b/man/systemd.path.xml +index 08a7ec897..d02bc92ae 100644 +--- a/man/systemd.path.xml ++++ b/man/systemd.path.xml +@@ -74,7 +74,7 @@ + (see below). + + Internally, path units use the +- inotify7 ++ inotify7 + API to monitor file systems. Due to that, it suffers by the same + limitations as inotify, and for example cannot be used to monitor + files or directories changed by other machines on remote NFS file +@@ -187,7 +187,7 @@ + systemctl1, + systemd.unit5, + systemd.service5, +- inotify7, ++ inotify7, + systemd.directives7 + + +diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml +index 3938345fa..2f541937f 100644 +--- a/man/systemd.socket.xml ++++ b/man/systemd.socket.xml +@@ -265,7 +265,7 @@ + Takes a one of , + or . Controls + the IPV6_V6ONLY socket option (see +- ipv67 ++ ipv67 + for details). If , IPv6 sockets bound + will be accessible via both IPv4 and IPv6. If + , they will be accessible via IPv6 +@@ -294,7 +294,7 @@ + this socket to. If set, traffic will only be accepted from the + specified network interfaces. This controls the + SO_BINDTODEVICE socket option (see +- socket7 ++ socket7 + for details). If this option is used, an automatic dependency + from this socket unit on the network interface device unit + (systemd.device5 +@@ -380,7 +380,7 @@ + /proc/sys/net/ipv4/tcp_keepalive_time) + for all TCP streams accepted on this socket. This controls the + SO_KEEPALIVE socket option (see +- socket7 ++ socket7 + and the TCP + Keepalive HOWTO for details.) Defaults to +@@ -392,7 +392,7 @@ + Takes time (in seconds) as argument . The connection needs to remain + idle before TCP starts sending keepalive probes. This controls the TCP_KEEPIDLE + socket option (see +- socket7 ++ socket7 + and the TCP + Keepalive HOWTO for details.) +@@ -405,7 +405,7 @@ + individual keepalive probes, if the socket option SO_KEEPALIVE + has been set on this socket seconds as argument. This controls + the TCP_KEEPINTVL socket option (see +- socket7 ++ socket7 + and the TCP + Keepalive HOWTO for details.) Defaults value is 75 +@@ -418,7 +418,7 @@ + unacknowledged probes to send before considering the + connection dead and notifying the application layer. This + controls the TCP_KEEPCNT socket option (see +- socket7 ++ socket7 + and the TCP + Keepalive HOWTO for details.) Defaults value is +@@ -431,7 +431,7 @@ + algorithm works by combining a number of small outgoing + messages, and sending them all at once. This controls the + TCP_NODELAY socket option (see +- tcp7 ++ tcp7 + Defaults to . + + +@@ -440,7 +440,7 @@ + Takes an integer argument controlling the + priority for all traffic sent from this socket. This controls + the SO_PRIORITY socket option (see +- socket7 ++ socket7 + for details.). + + +@@ -453,7 +453,7 @@ + established. When this option is set, the + TCP_DEFER_ACCEPT socket option will be + used (see +- tcp7), ++ tcp7), + and the kernel will ignore initial ACK packets without any + data. The argument specifies the approximate amount of time + the kernel should wait for incoming data before falling back +@@ -480,7 +480,7 @@ + Takes an integer argument controlling the + receive or send buffer sizes of this socket, respectively. + This controls the SO_RCVBUF and SO_SNDBUF socket options (see +- socket7 ++ socket7 + for details.). The usual suffixes K, M, G are supported and + are understood to the base of 1024. + +@@ -490,7 +490,7 @@ + Takes an integer argument controlling the IP + Type-Of-Service field for packets generated from this socket. + This controls the IP_TOS socket option (see +- ip7 ++ ip7 + for details.). Either a numeric string or one of + , , + or may +@@ -503,9 +503,9 @@ + Time-To-Live/IPv6 Hop-Count field for packets generated from + this socket. This sets the IP_TTL/IPV6_UNICAST_HOPS socket + options (see +- ip7 ++ ip7 + and +- ipv67 ++ ipv67 + for details.) + + +@@ -515,7 +515,7 @@ + mark of packets generated by this socket. This can be used in + the firewall logic to filter packets from this socket. This + sets the SO_MARK socket option. See +- iptables8 ++ iptables8 + for details. + + +@@ -526,7 +526,7 @@ + bind2s + to this TCP or UDP port. This controls the SO_REUSEPORT socket + option. See +- socket7 ++ socket7 + for details. + + +@@ -578,7 +578,7 @@ + control the mq_maxmsg field or the mq_msgsize field, + respectively, when creating the message queue. Note that + either none or both of these variables need to be set. See +- mq_setattr3 ++ mq_setattr3 + for details. + + +diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml +index 23b9c712e..5016f453d 100644 +--- a/man/systemd.swap.xml ++++ b/man/systemd.swap.xml +@@ -69,7 +69,7 @@ + Additional options are listed in + systemd.exec5, + which define the execution environment the +- swapon8 ++ swapon8 + binary is executed in, and in + systemd.kill5, + which define the way the processes are terminated, and in +@@ -100,7 +100,7 @@ + + Swap units may either be configured via unit files, or via + /etc/fstab (see +- fstab5 ++ fstab5 + for details). Swaps listed in /etc/fstab will + be converted into native units dynamically at boot and when the + configuration of the system manager is reloaded. See +@@ -161,7 +161,7 @@ + What= + Takes an absolute path of a device node or + file to use for paging. See +- swapon8 ++ swapon8 + for details. If this refers to a device node, a dependency on + the respective device unit is automatically created. (See + systemd.device5 +@@ -187,7 +187,7 @@ + device. This may be used for controlling discard options among + other functionality, if the swap backing device supports the + discard or trim operation. (See +- swapon8 ++ swapon8 + for more information.) + + +@@ -229,7 +229,7 @@ + systemd.resource-control5, + systemd.device5, + systemd.mount5, +- swapon8, ++ swapon8, + systemd-fstab-generator8, + systemd.directives7 + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index a452f87ba..c2e374a94 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -826,7 +826,7 @@ + cris to test + against a specific architecture. The architecture is + determined from the information returned by +- uname2 ++ uname2 + and is thus subject to + personality2. + Note that a Personality= setting in the +@@ -1438,7 +1438,7 @@ PrivateTmp=yes + systemd-analyze1, + capabilities7, + systemd.directives7, +- uname1 ++ uname1 + + + +diff --git a/man/systemd.xml b/man/systemd.xml +index 9b92140e6..d006b0bb9 100644 +--- a/man/systemd.xml ++++ b/man/systemd.xml +@@ -1012,9 +1012,9 @@ + Set the system locale to use. This overrides + the settings in /etc/locale.conf. For + more information see +- locale.conf5 ++ locale.conf5 + and +- locale7. ++ locale7. + + + +@@ -1077,7 +1077,7 @@ + + The systemd Homepage, + systemd-system.conf5, +- locale.conf5, ++ locale.conf5, + systemctl1, + journalctl1, + systemd-notify1, +diff --git a/man/vconsole.conf.xml b/man/vconsole.conf.xml +index 17bea8b68..27196d44e 100644 +--- a/man/vconsole.conf.xml ++++ b/man/vconsole.conf.xml +@@ -129,9 +129,9 @@ FONT=eurlatgr + + systemd1, + systemd-vconsole-setup.service8, +- loadkeys1, +- setfont8, +- locale.conf5, ++ loadkeys1, ++ setfont8, ++ locale.conf5, + systemd-localed.service8 + + diff --git a/SOURCES/0103-man-link-to-fd.o-for-dbus-stuff.patch b/SOURCES/0103-man-link-to-fd.o-for-dbus-stuff.patch new file mode 100644 index 00000000..ad0c8c11 --- /dev/null +++ b/SOURCES/0103-man-link-to-fd.o-for-dbus-stuff.patch @@ -0,0 +1,90 @@ +From ec79f8b26d793d2e2ee1705ca86437049e0153c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 13 Mar 2015 21:24:30 -0500 +Subject: [PATCH] man: link to fd.o for dbus stuff + +(cherry picked from commit 3b5cfcdb580f5b766ff7fb1a2839bd37d74a98de) +--- + man/busctl.xml | 2 +- + man/custom-html.xsl | 13 +++++++++++++ + man/systemd-bus-proxyd.xml | 2 +- + man/systemd-bus-proxyd@.service.xml | 2 +- + man/systemd-machine-id-setup.xml | 2 +- + 5 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/man/busctl.xml b/man/busctl.xml +index cc1844b0a..807fc78e8 100644 +--- a/man/busctl.xml ++++ b/man/busctl.xml +@@ -465,7 +465,7 @@ o "/org/freedesktop/systemd1/job/42684" + See Also + + +- dbus-daemon1, ++ dbus-daemon1, + D-Bus, + kdbus, + sd-bus3, +diff --git a/man/custom-html.xsl b/man/custom-html.xsl +index 32299db71..706b95a1c 100644 +--- a/man/custom-html.xsl ++++ b/man/custom-html.xsl +@@ -91,6 +91,19 @@ + + + ++ ++ ++ ++ http://dbus.freedesktop.org/doc/ ++ ++ . ++ ++ .html ++ ++ ++ ++ ++ + + +

+diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml +index 2c7764047..e0efe9985 100644 +--- a/man/systemd-bus-proxyd.xml ++++ b/man/systemd-bus-proxyd.xml +@@ -101,7 +101,7 @@ along with systemd; If not, see . + See Also + + +- dbus-daemon1, ++ dbus-daemon1, + D-Bus, + kdbus + +diff --git a/man/systemd-bus-proxyd@.service.xml b/man/systemd-bus-proxyd@.service.xml +index 141b43f6d..dc4f07ff1 100644 +--- a/man/systemd-bus-proxyd@.service.xml ++++ b/man/systemd-bus-proxyd@.service.xml +@@ -73,7 +73,7 @@ + + + systemd-bus-proxyd8, +- dbus-daemon1, ++ dbus-daemon1, + D-Bus, + kdbus + +diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml +index 22bad3e5f..182717f52 100644 +--- a/man/systemd-machine-id-setup.xml ++++ b/man/systemd-machine-id-setup.xml +@@ -122,7 +122,7 @@ + + systemd1, + machine-id5, +- dbus-uuidgen1, ++ dbus-uuidgen1, + systemd-firstboot1 + + diff --git a/SOURCES/0104-man-fix-name-of-systemd.resource-control-5.patch b/SOURCES/0104-man-fix-name-of-systemd.resource-control-5.patch new file mode 100644 index 00000000..9b3e2ba5 --- /dev/null +++ b/SOURCES/0104-man-fix-name-of-systemd.resource-control-5.patch @@ -0,0 +1,23 @@ +From 28dd732dd917b9832c4c39b7fd44a566516815db Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 13 Mar 2015 21:25:37 -0500 +Subject: [PATCH] man: fix name of systemd.resource-control(5) + +(cherry picked from commit ee41f6028189819c728316e917ca09b9eb0a7850) +--- + man/systemctl.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 07eb43165..3c4c9cb92 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -1732,7 +1732,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + loginctl1, + machinectl1, + systemd.unit5, +- systemd.resource-management5, ++ systemd.resource-control5, + systemd.special7, + wall1, + systemd.preset5, diff --git a/SOURCES/0105-selinux-fix-SEGV-during-switch-root-if-SELinux-polic.patch b/SOURCES/0105-selinux-fix-SEGV-during-switch-root-if-SELinux-polic.patch new file mode 100644 index 00000000..80d8d4fb --- /dev/null +++ b/SOURCES/0105-selinux-fix-SEGV-during-switch-root-if-SELinux-polic.patch @@ -0,0 +1,37 @@ +From 3a82f8be03b07b84fa470c6e42cd87865aeaf701 Mon Sep 17 00:00:00 2001 +From: Will Woods +Date: Fri, 13 Mar 2015 17:24:46 -0400 +Subject: [PATCH] selinux: fix SEGV during switch-root if SELinux policy loaded + +If you've got SELinux policy loaded, label_hnd is your labeling handle. +When systemd is shutting down, we free that handle via mac_selinux_finish(). + +But: switch_root() calls mkdir_p_label(), which tries to look up a label +using that freed handle, and so we get a bunch of garbage and eventually +SEGV in libselinux. + +(This doesn't happen in the switch-root from initramfs to real root because +there's no SELinux policy loaded in initramfs, so label_hnd is NULL and we +never attempt any lookups.) + +So: make sure that mac_selinux_finish() actually sets label_hnd to NULL, so +nobody tries to use it after it becomes invalid. + +https://bugzilla.redhat.com/show_bug.cgi?id=1185604 +(cherry picked from commit f5ce2b49585a14cefb6d02f61c8dcdf7628a8605) +--- + src/shared/selinux-util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c +index a2233e0cf..a46ddf849 100644 +--- a/src/shared/selinux-util.c ++++ b/src/shared/selinux-util.c +@@ -117,6 +117,7 @@ void mac_selinux_finish(void) { + return; + + selabel_close(label_hnd); ++ label_hnd = NULL; + #endif + } + diff --git a/SOURCES/0106-service-don-t-add-After-dependencies-on-.busname-uni.patch b/SOURCES/0106-service-don-t-add-After-dependencies-on-.busname-uni.patch new file mode 100644 index 00000000..345a3be9 --- /dev/null +++ b/SOURCES/0106-service-don-t-add-After-dependencies-on-.busname-uni.patch @@ -0,0 +1,35 @@ +From 7c1b21bad54714f04d0d2a8c77008408affe7067 Mon Sep 17 00:00:00 2001 +From: Michael Biebl +Date: Sat, 14 Mar 2015 16:48:54 +0100 +Subject: [PATCH] service: don't add After= dependencies on .busname units if + kdbus support is disabled + +(cherry picked from commit 6962fd3bd28cb5d3aaff69c1e3b6cc006e7c8426) +--- + src/core/service.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 7781b4e62..ae5e61000 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -556,14 +556,16 @@ static int service_add_extras(Service *s) { + s->notify_access = NOTIFY_MAIN; + + if (s->bus_name) { ++#ifdef ENABLE_KDBUS + const char *n; + +- r = unit_watch_bus_name(UNIT(s), s->bus_name); ++ n = strjoina(s->bus_name, ".busname"); ++ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); + if (r < 0) + return r; ++#endif + +- n = strjoina(s->bus_name, ".busname"); +- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); ++ r = unit_watch_bus_name(UNIT(s), s->bus_name); + if (r < 0) + return r; + } diff --git a/SOURCES/0107-libudev-monitor-fix-error-path-in-send_device.patch b/SOURCES/0107-libudev-monitor-fix-error-path-in-send_device.patch new file mode 100644 index 00000000..4093a682 --- /dev/null +++ b/SOURCES/0107-libudev-monitor-fix-error-path-in-send_device.patch @@ -0,0 +1,38 @@ +From dfd0017561730f675d65cc826815ce7c932892aa Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 11 Mar 2015 22:23:38 +0100 +Subject: [PATCH] libudev: monitor - fix error path in send_device + +Return -errno rather than -1 in case sendmsg() fails. + +(cherry picked from commit a4445e88cece0444c66d70876b03065158dd4685) +--- + src/libudev/libudev-monitor.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c +index 3f1fee7f7..d0486e3d1 100644 +--- a/src/libudev/libudev-monitor.c ++++ b/src/libudev/libudev-monitor.c +@@ -749,12 +749,20 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, + * If we send to a multicast group, we will get + * ECONNREFUSED, which is expected. + */ +- if (destination != NULL) ++ if (destination) + smsg.msg_name = &destination->snl; + else + smsg.msg_name = &udev_monitor->snl_destination; + smsg.msg_namelen = sizeof(struct sockaddr_nl); + count = sendmsg(udev_monitor->sock, &smsg, 0); ++ if (count < 0) { ++ if (!destination && errno == ECONNREFUSED) { ++ log_debug("passed unknown number of bytes to netlink monitor %p", udev_monitor); ++ return 0; ++ } else ++ return -errno; ++ } ++ + log_debug("passed %zi bytes to netlink monitor %p", count, udev_monitor); + return count; + } diff --git a/SOURCES/0108-core-remove-left-over-debug-message.patch b/SOURCES/0108-core-remove-left-over-debug-message.patch new file mode 100644 index 00000000..75fc9fa3 --- /dev/null +++ b/SOURCES/0108-core-remove-left-over-debug-message.patch @@ -0,0 +1,23 @@ +From ea76eeb44ef5c8e5fc8e44328c2c455a2b9a0db0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 17:41:53 -0400 +Subject: [PATCH] core: remove left-over debug message + +(cherry picked from commit bdb26d423a7f992bec5c28e17894c684d770d6f3) +--- + src/core/load-fragment.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 90bf5634c..f17a82fcd 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -634,8 +634,6 @@ int config_parse_exec(const char *unit, + + n[k] = NULL; + +- log_debug("path: %s", path ?: n[0]); +- + if (!n[0]) + reason = "Empty executable name or zeroeth argument"; + else if (!string_is_safe(path ?: n[0])) diff --git a/SOURCES/0109-units-there-is-no-systemd-udev-hwdb-update.service.patch b/SOURCES/0109-units-there-is-no-systemd-udev-hwdb-update.service.patch new file mode 100644 index 00000000..88522425 --- /dev/null +++ b/SOURCES/0109-units-there-is-no-systemd-udev-hwdb-update.service.patch @@ -0,0 +1,23 @@ +From e2d3644c855b9262508448abc5044e3e21103680 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 17:56:13 -0400 +Subject: [PATCH] units: there is no systemd-udev-hwdb-update.service + +(cherry picked from commit d99ce93383028f08470b6d334bc1a31ca8d16b22) +--- + units/systemd-udevd.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in +index f6acd6fe4..2791f73ac 100644 +--- a/units/systemd-udevd.service.in ++++ b/units/systemd-udevd.service.in +@@ -10,7 +10,7 @@ Description=udev Kernel Device Manager + Documentation=man:systemd-udevd.service(8) man:udev(7) + DefaultDependencies=no + Wants=systemd-udevd-control.socket systemd-udevd-kernel.socket +-After=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-hwdb-update.service systemd-sysusers.service ++After=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-hwdb-update.service systemd-sysusers.service + Before=sysinit.target + ConditionPathIsReadWrite=/sys + diff --git a/SOURCES/0110-util-remove-redundant-debug-message.patch b/SOURCES/0110-util-remove-redundant-debug-message.patch new file mode 100644 index 00000000..ce4d0687 --- /dev/null +++ b/SOURCES/0110-util-remove-redundant-debug-message.patch @@ -0,0 +1,29 @@ +From 5ad9a98a4c77949fd3519e11b44b8e0564dfc3a6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 20:14:39 -0400 +Subject: [PATCH] util: remove redundant debug message + +mar 14 20:05:34 fedora22 systemd[4058]: /usr/lib/systemd/system-generators/kdump-dep-generator.sh will be executed. +mar 14 20:05:34 fedora22 systemd[4058]: Spawned /usr/lib/systemd/system-generators/kdump-dep-generator.sh as 4059. + +The second line already says everything. + +(cherry picked from commit 7034e9db51d0b6f8e1dbbe9127393c6fbc06fe28) +--- + src/shared/util.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 85487230a..1e1bf944f 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -4115,8 +4115,7 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) { + if (null_or_empty_path(path)) { + log_debug("%s is empty (a mask).", path); + continue; +- } else +- log_debug("%s will be executed.", path); ++ } + + pid = fork(); + if (pid < 0) { diff --git a/SOURCES/0111-tmpfiles-remove-redundant-debug-message.patch b/SOURCES/0111-tmpfiles-remove-redundant-debug-message.patch new file mode 100644 index 00000000..ea7e02e5 --- /dev/null +++ b/SOURCES/0111-tmpfiles-remove-redundant-debug-message.patch @@ -0,0 +1,26 @@ +From b9de0cce0292983b62842990b9ce71c99b1bc434 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 20:24:47 -0400 +Subject: [PATCH] tmpfiles: remove redundant debug message + +Mar 13 19:48:30 adam.happyassassin.net systemd-tmpfiles[970]: "/var/lib/machines" has right mode 40700 +Mar 13 19:48:30 adam.happyassassin.net systemd-tmpfiles[970]: /var/lib/machines created successfully. + +(cherry picked from commit 51bfdaf66c381793d2f39ad891f3411a55927da6) +--- + src/tmpfiles/tmpfiles.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 1e1096816..73a9c9d5b 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1209,8 +1209,6 @@ static int create_item(Item *i) { + break; + } + +- log_debug("%s created successfully.", i->path); +- + return 0; + } + diff --git a/SOURCES/0112-sysv-generator-initialize-LookupPaths-just-once.patch b/SOURCES/0112-sysv-generator-initialize-LookupPaths-just-once.patch new file mode 100644 index 00000000..7694f9c6 --- /dev/null +++ b/SOURCES/0112-sysv-generator-initialize-LookupPaths-just-once.patch @@ -0,0 +1,275 @@ +From f8fd91c9f0f1f7feabf8567bdad61f57fe922011 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 21:46:59 -0400 +Subject: [PATCH] sysv-generator: initialize LookupPaths just once + +With debugging on, sysv-generator would print the full set of +lookup paths for *every* sysv script. + +While at it, pass LookupPaths as a pointer in sysv-generator, +and constify it everywhere. + +(cherry picked from commit a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0e) +--- + src/shared/install.c | 55 ++++++++++++++++++++++--------------- + src/shared/install.h | 11 +++++++- + src/shared/path-lookup.c | 1 + + src/shared/path-lookup.h | 3 +- + src/sysv-generator/sysv-generator.c | 14 +++++----- + 5 files changed, 53 insertions(+), 31 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 65f1c245c..92b8d6e8e 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1084,7 +1084,7 @@ static int unit_file_load( + static int unit_file_search( + InstallContext *c, + InstallInfo *info, +- LookupPaths *paths, ++ const LookupPaths *paths, + const char *root_dir, + bool allow_symlink, + bool load, +@@ -1153,7 +1153,7 @@ static int unit_file_search( + } + + static int unit_file_can_install( +- LookupPaths *paths, ++ const LookupPaths *paths, + const char *root_dir, + const char *name, + bool allow_symlink, +@@ -1317,7 +1317,7 @@ static int install_info_symlink_wants( + + static int install_info_symlink_link( + InstallInfo *i, +- LookupPaths *paths, ++ const LookupPaths *paths, + const char *config_path, + const char *root_dir, + bool force, +@@ -1345,7 +1345,7 @@ static int install_info_symlink_link( + + static int install_info_apply( + InstallInfo *i, +- LookupPaths *paths, ++ const LookupPaths *paths, + const char *config_path, + const char *root_dir, + bool force, +@@ -1377,7 +1377,7 @@ static int install_info_apply( + + static int install_context_apply( + InstallContext *c, +- LookupPaths *paths, ++ const LookupPaths *paths, + const char *config_path, + const char *root_dir, + bool force, +@@ -1424,7 +1424,7 @@ static int install_context_apply( + + static int install_context_mark_for_removal( + InstallContext *c, +- LookupPaths *paths, ++ const LookupPaths *paths, + Set **remove_symlinks_to, + const char *config_path, + const char *root_dir) { +@@ -1785,39 +1785,28 @@ int unit_file_get_default( + return -ENOENT; + } + +-UnitFileState unit_file_get_state( ++UnitFileState unit_file_lookup_state( + UnitFileScope scope, + const char *root_dir, ++ const LookupPaths *paths, + const char *name) { + +- _cleanup_lookup_paths_free_ LookupPaths paths = {}; + UnitFileState state = _UNIT_FILE_STATE_INVALID; + char **i; + _cleanup_free_ char *path = NULL; + int r; + +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); +- assert(name); +- +- if (root_dir && scope != UNIT_FILE_SYSTEM) +- return -EINVAL; ++ assert(paths); + + if (!unit_name_is_valid(name, TEMPLATE_VALID)) + return -EINVAL; + +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); +- if (r < 0) +- return r; +- +- STRV_FOREACH(i, paths.unit_path) { ++ STRV_FOREACH(i, paths->unit_path) { + struct stat st; + char *partial; + bool also = false; + + free(path); +- path = NULL; +- + path = path_join(root_dir, *i, name); + if (!path) + return -ENOMEM; +@@ -1858,7 +1847,7 @@ UnitFileState unit_file_get_state( + else if (r > 0) + return state; + +- r = unit_file_can_install(&paths, root_dir, partial, true, &also); ++ r = unit_file_can_install(paths, root_dir, partial, true, &also); + if (r < 0 && errno != ENOENT) + return r; + else if (r > 0) +@@ -1873,6 +1862,28 @@ UnitFileState unit_file_get_state( + return r < 0 ? r : state; + } + ++UnitFileState unit_file_get_state( ++ UnitFileScope scope, ++ const char *root_dir, ++ const char *name) { ++ ++ _cleanup_lookup_paths_free_ LookupPaths paths = {}; ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(name); ++ ++ if (root_dir && scope != UNIT_FILE_SYSTEM) ++ return -EINVAL; ++ ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ if (r < 0) ++ return r; ++ ++ return unit_file_lookup_state(scope, root_dir, &paths, name); ++} ++ + int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { + _cleanup_strv_free_ char **files = NULL; + char **p; +diff --git a/src/shared/install.h b/src/shared/install.h +index 357be0f92..3ca39397e 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -23,6 +23,7 @@ + + #include "hashmap.h" + #include "unit-name.h" ++#include "path-lookup.h" + + typedef enum UnitFileScope { + UNIT_FILE_SYSTEM, +@@ -98,7 +99,15 @@ int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char + int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name); + int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); + +-UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename); ++UnitFileState unit_file_lookup_state( ++ UnitFileScope scope, ++ const char *root_dir, ++ const LookupPaths *paths, ++ const char *name); ++UnitFileState unit_file_get_state( ++ UnitFileScope scope, ++ const char *root_dir, ++ const char *filename); + + int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); + +diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c +index 291a2f405..812730be1 100644 +--- a/src/shared/path-lookup.c ++++ b/src/shared/path-lookup.c +@@ -31,6 +31,7 @@ + #include "strv.h" + #include "path-util.h" + #include "path-lookup.h" ++#include "install.h" + + int user_config_home(char **config_home) { + const char *e; +diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h +index 2ec888da8..f1925eef6 100644 +--- a/src/shared/path-lookup.h ++++ b/src/shared/path-lookup.h +@@ -22,7 +22,8 @@ + ***/ + + #include "macro.h" +-#include "install.h" ++ ++typedef enum UnitFileScope UnitFileScope; + + typedef struct LookupPaths { + char **unit_path; +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 6e39b449e..0125ca27d 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -723,10 +723,10 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { + return 0; + } + +-static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) { ++static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + char **path; + +- STRV_FOREACH(path, lp.sysvinit_path) { ++ STRV_FOREACH(path, lp->sysvinit_path) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + +@@ -768,7 +768,7 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) { + if (!fpath) + return log_oom(); + +- if (unit_file_get_state(UNIT_FILE_SYSTEM, NULL, name) >= 0) { ++ if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) { + log_debug("Native unit for %s already exists, skipping", name); + continue; + } +@@ -793,7 +793,7 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) { + return 0; + } + +-static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) { ++static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) { + char **p; + unsigned i; + _cleanup_closedir_ DIR *d = NULL; +@@ -804,7 +804,7 @@ static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) { + _cleanup_set_free_ Set *shutdown_services = NULL; + int r = 0; + +- STRV_FOREACH(p, lp.sysvrcnd_path) ++ STRV_FOREACH(p, lp->sysvrcnd_path) + for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { + struct dirent *de; + +@@ -954,13 +954,13 @@ int main(int argc, char *argv[]) { + return EXIT_FAILURE; + } + +- r = enumerate_sysv(lp, all_services); ++ r = enumerate_sysv(&lp, all_services); + if (r < 0) { + log_error("Failed to generate units for all init scripts."); + return EXIT_FAILURE; + } + +- r = set_dependencies_from_rcnd(lp, all_services); ++ r = set_dependencies_from_rcnd(&lp, all_services); + if (r < 0) { + log_error("Failed to read runlevels from rcnd links."); + return EXIT_FAILURE; diff --git a/SOURCES/0113-core-do-not-use-quotes-around-virt-and-arch.patch b/SOURCES/0113-core-do-not-use-quotes-around-virt-and-arch.patch new file mode 100644 index 00000000..5d3073de --- /dev/null +++ b/SOURCES/0113-core-do-not-use-quotes-around-virt-and-arch.patch @@ -0,0 +1,31 @@ +From f7ef062a0fb0dd0a6560d00e579c496e164a1c85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 21:49:10 -0400 +Subject: [PATCH] core: do not use quotes around virt and arch + +Quotes are useful when the string can contain spaces or be otherwise +confusing. Not possible with those two. + +(cherry picked from commit d3f86679783aee216d60b125acfb5f39a0df555f) +--- + src/core/main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index ba2de85bd..fd527d4d6 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1537,11 +1537,11 @@ int main(int argc, char *argv[]) { + + detect_virtualization(&virtualization); + if (virtualization) +- log_info("Detected virtualization '%s'.", virtualization); ++ log_info("Detected virtualization %s.", virtualization); + + write_container_id(); + +- log_info("Detected architecture '%s'.", architecture_to_string(uname_architecture())); ++ log_info("Detected architecture %s.", architecture_to_string(uname_architecture())); + + if (in_initrd()) + log_info("Running in initial RAM disk."); diff --git a/SOURCES/0114-udev-downgrade-has-devpath-and-filled-with-db-file-m.patch b/SOURCES/0114-udev-downgrade-has-devpath-and-filled-with-db-file-m.patch new file mode 100644 index 00000000..bae47f10 --- /dev/null +++ b/SOURCES/0114-udev-downgrade-has-devpath-and-filled-with-db-file-m.patch @@ -0,0 +1,37 @@ +From b69fafa98f1185c4e95c350aac833fdae7de0612 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 22:22:49 -0400 +Subject: [PATCH] udev: downgrade "has devpath" and "filled with db file" + messages + +Udev debug messages have to be significantly overhauled... For now +just downgrade those two. They are responsible for approximately 25% +of debug output during boot and are rather useless. + +(cherry picked from commit cdd45c1ffbf790facd1817757832aa25d9211967) +--- + src/libudev/libudev-device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c +index 9863901a3..e40894222 100644 +--- a/src/libudev/libudev-device.c ++++ b/src/libudev/libudev-device.c +@@ -613,7 +613,7 @@ int udev_device_read_db(struct udev_device *udev_device, const char *dbfile) + } + fclose(f); + +- log_debug("device %p filled with db file data", udev_device); ++ log_trace("device %p filled with db file data", udev_device); + return 0; + } + +@@ -775,7 +775,7 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con + return NULL; + + udev_device_set_syspath(udev_device, path); +- log_debug("device %p has devpath '%s'", udev_device, udev_device_get_devpath(udev_device)); ++ log_trace("device %p has devpath '%s'", udev_device, udev_device_get_devpath(udev_device)); + + return udev_device; + } diff --git a/SOURCES/0115-cryptsetup-generator-remove-warning-about-crypttab-a.patch b/SOURCES/0115-cryptsetup-generator-remove-warning-about-crypttab-a.patch new file mode 100644 index 00000000..4b5bf95f --- /dev/null +++ b/SOURCES/0115-cryptsetup-generator-remove-warning-about-crypttab-a.patch @@ -0,0 +1,36 @@ +From d066c82a5a5c63c50617be27409ae0bb4bd3a356 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 22:35:30 -0400 +Subject: [PATCH] cryptsetup-generator: remove warning about crypttab access + mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This file contains no privileged data — just names of devices to decrypt +and files containing keys. On a running system most of this can be inferred from +the device tree anyway. + +(cherry picked from commit 71e4e1258436e7e81d772aed52a02bb5d9c87cb8) +--- + src/cryptsetup/cryptsetup-generator.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index dfbca8754..d191def5f 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -377,13 +377,6 @@ static int add_crypttab_devices(void) { + return 0; + } + +- /* If we readd support for specifying passphrases +- * directly in crypttab we should upgrade the warning +- * below, though possibly only if a passphrase is +- * specified directly. */ +- if (st.st_mode & 0005) +- log_debug("/etc/crypttab is world-readable. This is usually not a good idea."); +- + for (;;) { + int r, k; + char line[LINE_MAX], *l, *uuid; diff --git a/SOURCES/0116-sysctl-tweak-debug-message.patch b/SOURCES/0116-sysctl-tweak-debug-message.patch new file mode 100644 index 00000000..d3cc3ec1 --- /dev/null +++ b/SOURCES/0116-sysctl-tweak-debug-message.patch @@ -0,0 +1,23 @@ +From bea8dcb307f5978590d7371005eac46e20b29701 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 14 Mar 2015 22:56:01 -0400 +Subject: [PATCH] sysctl: tweak debug message + +(cherry picked from commit 924bc14fef39373f4523664207007a6c82c2b2d5) +--- + 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 b6945eda5..4fb293b9b 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -121,7 +121,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno + return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path); + } + +- log_debug("parse: %s", path); ++ log_debug("Parsing %s", path); + while (!feof(f)) { + char l[LINE_MAX], *p, *value, *new_value, *property, *existing; + void *v; diff --git a/SOURCES/0117-journald-add-syslog-fields-for-audit-messages.patch b/SOURCES/0117-journald-add-syslog-fields-for-audit-messages.patch new file mode 100644 index 00000000..944f4480 --- /dev/null +++ b/SOURCES/0117-journald-add-syslog-fields-for-audit-messages.patch @@ -0,0 +1,39 @@ +From 5e565da856cf4cf919ed1045b01ab461c586395a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 4 Mar 2015 10:31:42 -0500 +Subject: [PATCH] journald: add syslog fields for audit messages + +Audit messages would be displayed as "unknown[1]". + +Also specify AUTH as facility... This seems to be the closest match +(/* security/authorization messages */). + +(cherry picked from commit cd556b6ca8aec8dd371806afedec45f852f8f724) +--- + src/journal/journald-audit.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c +index 151097a6e..77abe2e63 100644 +--- a/src/journal/journald-audit.c ++++ b/src/journal/journald-audit.c +@@ -373,7 +373,7 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s + if (isempty(p)) + return; + +- n_iov_allocated = N_IOVEC_META_FIELDS + 5; ++ n_iov_allocated = N_IOVEC_META_FIELDS + 7; + iov = new(struct iovec, n_iov_allocated); + if (!iov) { + log_oom(); +@@ -392,6 +392,10 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s + sprintf(id_field, "_AUDIT_ID=%" PRIu64, id); + IOVEC_SET_STRING(iov[n_iov++], id_field); + ++ assert_cc(32 == LOG_AUTH); ++ IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=32"); ++ IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit"); ++ + m = alloca(strlen("MESSAGE= ") + strlen(p) + 1); + sprintf(m, "MESSAGE= %s", type, p); + IOVEC_SET_STRING(iov[n_iov++], m); diff --git a/SOURCES/0118-core-remove-useless-debug-message.patch b/SOURCES/0118-core-remove-useless-debug-message.patch new file mode 100644 index 00000000..493a3f27 --- /dev/null +++ b/SOURCES/0118-core-remove-useless-debug-message.patch @@ -0,0 +1,32 @@ +From 5efee680aa8f55c825be62e2e714f88d5c88066b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 15 Mar 2015 12:12:19 -0400 +Subject: [PATCH] core: remove useless debug message + +Mar 13 19:48:28 adam.happyassassin.net systemd[1]: Collecting (null) +Mar 13 19:48:28 adam.happyassassin.net systemd[1]: Collecting (null) +Mar 13 19:48:28 adam.happyassassin.net systemd[1]: Collecting (null) +Mar 13 19:48:28 adam.happyassassin.net systemd[1]: Collecting (null) +Mar 13 19:48:28 adam.happyassassin.net systemd[1]: Collecting (null) +Mar 13 19:48:28 adam.happyassassin.net systemd[1]: Collecting (null) +Mar 13 19:48:28 adam.happyassassin.net systemd[1]: Collecting (null) + +(cherry picked from commit cc3bc3e6203e0c615e31b8b68796362e1385f28a) +--- + src/core/manager.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 203a6a0a1..7483a96ec 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -844,7 +844,8 @@ static unsigned manager_dispatch_gc_queue(Manager *m) { + + if (u->gc_marker == gc_marker + GC_OFFSET_BAD || + u->gc_marker == gc_marker + GC_OFFSET_UNSURE) { +- log_unit_debug(u->id, "Collecting %s", u->id); ++ if (u->id) ++ log_unit_debug(u->id, "Collecting %s", u->id); + u->gc_marker = gc_marker + GC_OFFSET_BAD; + unit_add_to_cleanup_queue(u); + } diff --git a/SOURCES/0119-man-standard-conf-change-directory-reference-to-wild.patch b/SOURCES/0119-man-standard-conf-change-directory-reference-to-wild.patch new file mode 100644 index 00000000..557ffdb7 --- /dev/null +++ b/SOURCES/0119-man-standard-conf-change-directory-reference-to-wild.patch @@ -0,0 +1,23 @@ +From 6cf5c5d46e6eb06411dd8b180d3f1b3de1f93652 Mon Sep 17 00:00:00 2001 +From: Alison Chaiken +Date: Sun, 15 Mar 2015 16:26:14 -0700 +Subject: [PATCH] man: standard-conf: change directory reference to wildcard + +(cherry picked from commit 1d940aa32913c108e0282ebd359b2eb999ffeadf) +--- + man/standard-conf.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/standard-conf.xml b/man/standard-conf.xml +index 36af45927..004f53f70 100644 +--- a/man/standard-conf.xml ++++ b/man/standard-conf.xml +@@ -54,7 +54,7 @@ + directories, and has the lowest precedence; entries in a file in + any configuration directory override entries in the single + configuration file. Files in the +- logind.conf.d/ configuration subdirectories ++ *.conf.d/ configuration subdirectories + are sorted by their filename in lexicographic order, regardless of + which of the subdirectories they reside in. If multiple files + specify the same option, the entry in the file with the diff --git a/SOURCES/0120-core-don-t-change-removed-devices-to-state-tentative.patch b/SOURCES/0120-core-don-t-change-removed-devices-to-state-tentative.patch new file mode 100644 index 00000000..13f6b130 --- /dev/null +++ b/SOURCES/0120-core-don-t-change-removed-devices-to-state-tentative.patch @@ -0,0 +1,33 @@ +From 8e184ad6e23a8248e149cd5bf4f9bf56089a6dd1 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Fri, 13 Mar 2015 08:35:59 +0100 +Subject: [PATCH] core: don't change removed devices to state "tentative" + +Commit 628c89c introduced the "tentative" device state, which caused +devices to go from "plugged" to "tentative" on a remove uevent. This +breaks the cleanup of stale mounts (see commit 3b48ce4), as that only +applies to "dead" devices. + +The "tentative" state only really makes sense on adding a device when +we don't know where it was coming from (i. e. not from udev). But when +we get a device removal from udev we definitively know that it's gone, +so change the device state back to "dead" as before 628c89c. + +(cherry picked from commit 496068a8288084ab3ecf8b179a8403ecff1a6be8) +--- + src/core/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/device.c b/src/core/device.c +index 4ff882721..cc4ebd2c8 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -421,7 +421,7 @@ static void device_update_found_one(Device *d, bool add, DeviceFound found, bool + if (now) { + if (d->found & DEVICE_FOUND_UDEV) + device_set_state(d, DEVICE_PLUGGED); +- else if (d->found != DEVICE_NOT_FOUND) ++ else if (add && d->found != DEVICE_NOT_FOUND) + device_set_state(d, DEVICE_TENTATIVE); + else + device_set_state(d, DEVICE_DEAD); diff --git a/SOURCES/0121-fstab-generator-ignore-invalid-swap-priority.patch b/SOURCES/0121-fstab-generator-ignore-invalid-swap-priority.patch new file mode 100644 index 00000000..82f48c48 --- /dev/null +++ b/SOURCES/0121-fstab-generator-ignore-invalid-swap-priority.patch @@ -0,0 +1,75 @@ +From e819659256d139cd5faebb5c0ca3ad4ad95ccb27 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 21 Mar 2015 11:31:16 -0400 +Subject: [PATCH] fstab-generator: ignore invalid swap priority + +A failed priority is not something worth stopping boot over. Most people +have only one swap device, in which case priority is irrelevant, and even +if there is more than one swap device, they are all usable, and ignoring the +priority field should only result in some loss of performance. + +The kernel will report the priority as -1 if not set, so it's easy for +people to make this mistake. + +https://bugzilla.redhat.com/show_bug.cgi?id=1204336 +(cherry picked from commit e0952d9d021234e79f3a70f33a9e5d201872a417) +--- + src/fstab-generator/fstab-generator.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 5662b5fde..8e2f522bd 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -54,9 +54,10 @@ static int add_swap( + bool noauto, + bool nofail) { + +- _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; ++ _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL, *filtered = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r, pri = -1; ++ const char *opts; + + assert(what); + assert(me); +@@ -71,9 +72,17 @@ static int add_swap( + return 0; + } + +- r = fstab_find_pri(me->mnt_opts, &pri); +- if (r < 0) +- return log_error_errno(r, "Failed to parse priority: %m"); ++ opts = me->mnt_opts; ++ r = fstab_find_pri(opts, &pri); ++ if (r < 0) { ++ log_error_errno(r, "Failed to parse priority, ignoring: %m"); ++ ++ /* Remove invalid pri field */ ++ r = fstab_filter_options(opts, "pri\0", NULL, NULL, &filtered); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse options: %m"); ++ opts = filtered; ++ } + + name = unit_name_from_path(what, ".swap"); + if (!name) +@@ -106,15 +115,15 @@ static int add_swap( + if (pri >= 0) + fprintf(f, "Priority=%i\n", pri); + +- if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults")) +- fprintf(f, "Options=%s\n", me->mnt_opts); ++ if (!isempty(opts) && !streq(opts, "defaults")) ++ fprintf(f, "Options=%s\n", opts); + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write unit file %s: %m", unit); + + /* use what as where, to have a nicer error message */ +- r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL); ++ r = generator_write_timeouts(arg_dest, what, what, opts, NULL); + if (r < 0) + return r; + diff --git a/SOURCES/0122-missing.h-add-more-btrfs-types-and-defines.patch b/SOURCES/0122-missing.h-add-more-btrfs-types-and-defines.patch new file mode 100644 index 00000000..7d588725 --- /dev/null +++ b/SOURCES/0122-missing.h-add-more-btrfs-types-and-defines.patch @@ -0,0 +1,192 @@ +From cb18a928a4db39a0eac1ab1fda1c80fd4cc4e22b Mon Sep 17 00:00:00 2001 +From: Michael Olbrich +Date: Wed, 18 Mar 2015 14:04:55 +0100 +Subject: [PATCH] missing.h: add more btrfs types and defines + +(cherry picked from commit 8e8ba79229bb82248a568f5929143a66f4be45b7) +--- + src/shared/missing.h | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 151 insertions(+) + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 6ef4dbdf4..4b36a9c93 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -294,12 +294,59 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) { + #define BTRFS_UUID_SIZE 16 + #endif + ++#ifndef BTRFS_SUBVOL_RDONLY ++#define BTRFS_SUBVOL_RDONLY (1ULL << 1) ++#endif ++ ++#ifndef BTRFS_SUBVOL_NAME_MAX ++#define BTRFS_SUBVOL_NAME_MAX 4039 ++#endif ++ ++#ifndef BTRFS_INO_LOOKUP_PATH_MAX ++#define BTRFS_INO_LOOKUP_PATH_MAX 4080 ++#endif ++ ++#ifndef BTRFS_SEARCH_ARGS_BUFSIZE ++#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) ++#endif ++ + #ifndef HAVE_LINUX_BTRFS_H + struct btrfs_ioctl_vol_args { + int64_t fd; + char name[BTRFS_PATH_NAME_MAX + 1]; + }; + ++struct btrfs_qgroup_limit { ++ __u64 flags; ++ __u64 max_rfer; ++ __u64 max_excl; ++ __u64 rsv_rfer; ++ __u64 rsv_excl; ++}; ++ ++struct btrfs_qgroup_inherit { ++ __u64 flags; ++ __u64 num_qgroups; ++ __u64 num_ref_copies; ++ __u64 num_excl_copies; ++ struct btrfs_qgroup_limit lim; ++ __u64 qgroups[0]; ++}; ++ ++struct btrfs_ioctl_vol_args_v2 { ++ __s64 fd; ++ __u64 transid; ++ __u64 flags; ++ union { ++ struct { ++ __u64 size; ++ struct btrfs_qgroup_inherit *qgroup_inherit; ++ }; ++ __u64 unused[4]; ++ }; ++ char name[BTRFS_SUBVOL_NAME_MAX + 1]; ++}; ++ + struct btrfs_ioctl_dev_info_args { + uint64_t devid; /* in/out */ + uint8_t uuid[BTRFS_UUID_SIZE]; /* in/out */ +@@ -315,6 +362,68 @@ struct btrfs_ioctl_fs_info_args { + uint8_t fsid[BTRFS_FSID_SIZE]; /* out */ + uint64_t reserved[124]; /* pad to 1k */ + }; ++ ++struct btrfs_ioctl_ino_lookup_args { ++ __u64 treeid; ++ __u64 objectid; ++ char name[BTRFS_INO_LOOKUP_PATH_MAX]; ++}; ++ ++struct btrfs_ioctl_search_key { ++ /* which root are we searching. 0 is the tree of tree roots */ ++ __u64 tree_id; ++ ++ /* keys returned will be >= min and <= max */ ++ __u64 min_objectid; ++ __u64 max_objectid; ++ ++ /* keys returned will be >= min and <= max */ ++ __u64 min_offset; ++ __u64 max_offset; ++ ++ /* max and min transids to search for */ ++ __u64 min_transid; ++ __u64 max_transid; ++ ++ /* keys returned will be >= min and <= max */ ++ __u32 min_type; ++ __u32 max_type; ++ ++ /* ++ * how many items did userland ask for, and how many are we ++ * returning ++ */ ++ __u32 nr_items; ++ ++ /* align to 64 bits */ ++ __u32 unused; ++ ++ /* some extra for later */ ++ __u64 unused1; ++ __u64 unused2; ++ __u64 unused3; ++ __u64 unused4; ++}; ++ ++struct btrfs_ioctl_search_header { ++ __u64 transid; ++ __u64 objectid; ++ __u64 offset; ++ __u32 type; ++ __u32 len; ++}; ++ ++ ++struct btrfs_ioctl_search_args { ++ struct btrfs_ioctl_search_key key; ++ char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; ++}; ++ ++struct btrfs_ioctl_clone_range_args { ++ __s64 src_fd; ++ __u64 src_offset, src_length; ++ __u64 dest_offset; ++}; + #endif + + #ifndef BTRFS_IOC_DEFRAG +@@ -322,6 +431,48 @@ struct btrfs_ioctl_fs_info_args { + struct btrfs_ioctl_vol_args) + #endif + ++#ifndef BTRFS_IOC_CLONE ++#define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int) ++#endif ++ ++#ifndef BTRFS_IOC_CLONE_RANGE ++#define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ ++ struct btrfs_ioctl_clone_range_args) ++#endif ++ ++#ifndef BTRFS_IOC_SUBVOL_CREATE ++#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \ ++ struct btrfs_ioctl_vol_args) ++#endif ++ ++#ifndef BTRFS_IOC_SNAP_DESTROY ++#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ ++ struct btrfs_ioctl_vol_args) ++#endif ++ ++#ifndef BTRFS_IOC_TREE_SEARCH ++#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ ++ struct btrfs_ioctl_search_args) ++#endif ++ ++#ifndef BTRFS_IOC_INO_LOOKUP ++#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ ++ struct btrfs_ioctl_ino_lookup_args) ++#endif ++ ++#ifndef BTRFS_IOC_SNAP_CREATE_V2 ++#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ ++ struct btrfs_ioctl_vol_args_v2) ++#endif ++ ++#ifndef BTRFS_IOC_SUBVOL_GETFLAGS ++#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64) ++#endif ++ ++#ifndef BTRFS_IOC_SUBVOL_SETFLAGS ++#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) ++#endif ++ + #ifndef BTRFS_IOC_DEV_INFO + #define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ + struct btrfs_ioctl_dev_info_args) diff --git a/SOURCES/0123-build-sys-add-configure-option-to-disableLTO-gold.patch b/SOURCES/0123-build-sys-add-configure-option-to-disableLTO-gold.patch new file mode 100644 index 00000000..762c23db --- /dev/null +++ b/SOURCES/0123-build-sys-add-configure-option-to-disableLTO-gold.patch @@ -0,0 +1,42 @@ +From 2d5ee8de927f69784d8380c24ca5505b3f6e7672 Mon Sep 17 00:00:00 2001 +From: systemd team +Date: Tue, 14 Apr 2015 15:00:06 +0200 +Subject: [PATCH] build-sys: add configure option to disableLTO/gold + +--- + configure.ac | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 081ed0f6e..9103f9b92 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -208,10 +208,15 @@ AS_CASE([$CC], [*clang*], + -Wno-gnu-variable-sized-type-not-at-end \ + ])]) + +-AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], +- [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ +- -flto -ffat-lto-objects])], +- [AC_MSG_RESULT([skipping -flto, optimization not enabled])]) ++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\ ]]*], +@@ -227,7 +232,7 @@ CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\ + -Wl,-z,relro \ + -Wl,-z,now \ + -pie \ +- -Wl,-fuse-ld=gold]) ++ ]) + AC_SUBST([OUR_LDFLAGS], "$with_ldflags $sanitizer_ldflags") + + AC_CHECK_SIZEOF(pid_t) diff --git a/SOURCES/0124-rules-bring-back-80-net-name-slot.rules.patch b/SOURCES/0124-rules-bring-back-80-net-name-slot.rules.patch new file mode 100644 index 00000000..d296b2dc --- /dev/null +++ b/SOURCES/0124-rules-bring-back-80-net-name-slot.rules.patch @@ -0,0 +1,45 @@ +From 434e13b009b4bd829c4ac827bdb53e3df61e5a6f Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 14 Apr 2015 17:11:48 +0200 +Subject: [PATCH] rules: bring back 80-net-name-slot.rules + +--- + Makefile.am | 3 ++- + rules/80-net-name-slot.rules | 14 ++++++++++++++ + 2 files changed, 16 insertions(+), 1 deletion(-) + create mode 100644 rules/80-net-name-slot.rules + +diff --git a/Makefile.am b/Makefile.am +index 4933f76bd..bec32c39e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3570,7 +3570,8 @@ dist_udevrules_DATA += \ + rules/80-net-setup-link.rules \ + rules/95-udev-late.rules \ + rules/40-redhat.rules \ +- rules/73-idrac.rules ++ rules/73-idrac.rules \ ++ rules/80-net-name-slot.rules + + nodist_udevrules_DATA += \ + rules/99-systemd.rules +diff --git a/rules/80-net-name-slot.rules b/rules/80-net-name-slot.rules +new file mode 100644 +index 000000000..c5f1b3885 +--- /dev/null ++++ b/rules/80-net-name-slot.rules +@@ -0,0 +1,14 @@ ++# do not edit this file, it will be overwritten on update ++ ++ACTION!="add", GOTO="net_name_slot_end" ++SUBSYSTEM!="net", GOTO="net_name_slot_end" ++NAME!="", GOTO="net_name_slot_end" ++ ++IMPORT{cmdline}="net.ifnames" ++ENV{net.ifnames}=="0", GOTO="net_name_slot_end" ++ ++NAME=="", ENV{ID_NET_NAME_ONBOARD}!="", NAME="$env{ID_NET_NAME_ONBOARD}" ++NAME=="", ENV{ID_NET_NAME_SLOT}!="", NAME="$env{ID_NET_NAME_SLOT}" ++NAME=="", ENV{ID_NET_NAME_PATH}!="", NAME="$env{ID_NET_NAME_PATH}" ++ ++LABEL="net_name_slot_end" diff --git a/SOURCES/0125-Revert-journald-allow-restarting-journald-without-lo.patch b/SOURCES/0125-Revert-journald-allow-restarting-journald-without-lo.patch new file mode 100644 index 00000000..ab625b8a --- /dev/null +++ b/SOURCES/0125-Revert-journald-allow-restarting-journald-without-lo.patch @@ -0,0 +1,564 @@ +From 91cb89c1b79ef3c475d91319edb0c052cb9f2724 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 15 Apr 2015 13:52:02 +0200 +Subject: [PATCH] Revert "journald: allow restarting journald without losing + stream connections" + +This reverts commit 13790add4bf648fed816361794d8277a75253410. +--- + src/journal/journald-server.c | 26 +-- + src/journal/journald-stream.c | 376 ++++++-------------------------------- + src/journal/journald-stream.h | 3 +- + units/systemd-journald.service.in | 1 - + 4 files changed, 61 insertions(+), 345 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 7ee8174ea..04839c950 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1455,7 +1455,6 @@ static int server_open_hostname(Server *s) { + } + + int server_init(Server *s) { +- _cleanup_fdset_free_ FDSet *fds = NULL; + int n, r, fd; + + assert(s); +@@ -1552,33 +1551,26 @@ int server_init(Server *s) { + s->audit_fd = fd; + + } else { ++ log_warning("Unknown socket passed as file descriptor %d, ignoring.", fd); + +- if (!fds) { +- fds = fdset_new(); +- if (!fds) +- return log_oom(); +- } ++ /* 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. */ + +- r = fdset_put(fds, fd); +- if (r < 0) +- return log_oom(); ++ safe_close(fd); + } + } + +- r = server_open_stdout_socket(s, fds); ++ r = server_open_syslog_socket(s); + if (r < 0) + return r; + +- 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); ++ r = server_open_native_socket(s); + if (r < 0) + return r; + +- r = server_open_native_socket(s); ++ r = server_open_stdout_socket(s); + if (r < 0) + return r; + +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 942a85780..11b852d39 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -28,11 +28,8 @@ + #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" +@@ -72,153 +69,14 @@ 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); +- +-#ifdef HAVE_SELINUX +- if (s->security_context) +- freecon(s->security_context); +-#endif +- +- 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; +@@ -371,9 +229,6 @@ 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: +@@ -468,63 +323,40 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + return 1; + + terminate: +- stdout_stream_destroy(s); ++ stdout_stream_free(s); + return 0; + } + +-static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { +- _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL; +- int r; +- ++void stdout_stream_free(StdoutStream *s) { + assert(s); +- assert(fd >= 0); + +- stream = new0(StdoutStream, 1); +- if (!stream) +- return log_oom(); ++ 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->fd = -1; +- stream->priority = LOG_INFO; ++ 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); ++ } + +- r = getpeercred(fd, &stream->ucred); +- if (r < 0) +- return log_error_errno(r, "Failed to determine peer credentials: %m"); ++ safe_close(s->fd); + + #ifdef HAVE_SELINUX +- if (mac_selinux_use()) { +- if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT) +- log_error_errno(errno, "Failed to determine peer security context: %m"); +- } ++ if (s->security_context) ++ freecon(s->security_context); + #endif + +- (void) shutdown(fd, SHUT_WR); +- +- 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; ++ free(s->identifier); ++ free(s->unit_id); ++ free(s); + } + + 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; +- int r; ++ StdoutStream *stream; ++ int fd, r; + + assert(s); + +@@ -544,163 +376,60 @@ 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; + } + +- 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(); +- } +- +- 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); +- +- if (priority) { +- int p; +- +- p = log_level_from_string(priority); +- if (p >= 0) +- stream->priority = p; ++ stream = new0(StdoutStream, 1); ++ if (!stream) { ++ safe_close(fd); ++ return log_oom(); + } + +- if (level_prefix) { +- r = parse_boolean(level_prefix); +- if (r >= 0) +- stream->level_prefix = r; +- } ++ stream->fd = fd; + +- if (forward_to_syslog) { +- r = parse_boolean(forward_to_syslog); +- if (r >= 0) +- stream->forward_to_syslog = r; ++ r = getpeercred(fd, &stream->ucred); ++ if (r < 0) { ++ log_error_errno(errno, "Failed to determine peer credentials: %m"); ++ goto fail; + } + +- if (forward_to_kmsg) { +- r = parse_boolean(forward_to_kmsg); +- if (r >= 0) +- stream->forward_to_kmsg = r; ++#ifdef HAVE_SELINUX ++ if (mac_selinux_use()) { ++ if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT) ++ log_error_errno(errno, "Failed to determine peer security context: %m"); + } ++#endif + +- if (forward_to_console) { +- r = parse_boolean(forward_to_console); +- if (r >= 0) +- stream->forward_to_console = r; ++ if (shutdown(fd, SHUT_WR) < 0) { ++ log_error_errno(errno, "Failed to shutdown writing side of socket: %m"); ++ goto fail; + } + +- 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 = 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; + } + +- 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"); ++ 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; + } + +- 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); +- } ++ stream->server = s; ++ LIST_PREPEND(stdout_stream, s->stdout_streams, stream); ++ s->n_stdout_streams ++; + + return 0; + + fail: +- return log_error_errno(errno, "Failed to read streams directory: %m"); ++ stdout_stream_free(stream); ++ return 0; + } + +-int server_open_stdout_socket(Server *s, FDSet *fds) { ++int server_open_stdout_socket(Server *s) { + int r; + + assert(s); +@@ -736,8 +465,5 @@ int server_open_stdout_socket(Server *s, FDSet *fds) { + 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 94bf955d7..8cad01296 100644 +--- a/src/journal/journald-stream.h ++++ b/src/journal/journald-stream.h +@@ -21,9 +21,8 @@ + along with systemd; If not, see . + ***/ + +-#include "fdset.h" + #include "journald-server.h" + +-int server_open_stdout_socket(Server *s, FDSet *fds); ++int server_open_stdout_socket(Server *s); + + void stdout_stream_free(StdoutStream *s); +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index a3540c65d..87704bb9c 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -23,7 +23,6 @@ NotifyAccess=all + StandardOutput=null + CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE + WatchdogSec=1min +-FileDescriptorStoreMax=1024 + + # 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/0126-Revert-man-switch-yum-to-dnf-for-Fedora.patch b/SOURCES/0126-Revert-man-switch-yum-to-dnf-for-Fedora.patch new file mode 100644 index 00000000..bb8eab2a --- /dev/null +++ b/SOURCES/0126-Revert-man-switch-yum-to-dnf-for-Fedora.patch @@ -0,0 +1,66 @@ +From 597856130181473bff35f225d87b05c5825b1670 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 15 Apr 2015 14:04:52 +0200 +Subject: [PATCH] Revert "man: switch yum to dnf for Fedora" + +This reverts commit 74a6d87d0cd1f2213869e168b6ca55eded6f4ae8. + +Conflicts: + man/systemd-nspawn.xml +--- + man/custom-html.xsl | 12 ------------ + man/systemd-nspawn.xml | 4 +--- + 2 files changed, 1 insertion(+), 15 deletions(-) + +diff --git a/man/custom-html.xsl b/man/custom-html.xsl +index 706b95a1c..1df824cbb 100644 +--- a/man/custom-html.xsl ++++ b/man/custom-html.xsl +@@ -60,18 +60,6 @@ + + + +- +- +- +- https://www.mankier.com/ +- +- / +- +- +- +- +- +- + + + +diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml +index 65b4c2f29..cbd44d4ab 100644 +--- a/man/systemd-nspawn.xml ++++ b/man/systemd-nspawn.xml +@@ -98,7 +98,6 @@ + container. + + Use a tool like +- dnf8, + yum8, + debootstrap8, + or +@@ -668,7 +667,7 @@ + + Build and boot a minimal Fedora distribution in a container + +- # dnf -y --releasever=21 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd dnf fedora-release vim-minimal ++ # yum -y --releasever=21 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal + # systemd-nspawn -bD /srv/mycontainer + + This installs a minimal Fedora distribution into the +@@ -729,7 +728,6 @@ + + systemd1, + chroot1, +- dnf8, + yum8, + debootstrap8, + pacman8, diff --git a/SOURCES/0127-journal-remove-audit-socket-unit-files.patch b/SOURCES/0127-journal-remove-audit-socket-unit-files.patch new file mode 100644 index 00000000..2d4ab836 --- /dev/null +++ b/SOURCES/0127-journal-remove-audit-socket-unit-files.patch @@ -0,0 +1,80 @@ +From c45af40e61ab34508862f9e668f47cc6eb2f6d45 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 16 Apr 2015 10:50:10 +0200 +Subject: [PATCH] journal: remove audit socket unit-files + +--- + Makefile.am | 6 ++---- + units/systemd-journald-audit.socket | 19 ------------------- + units/systemd-journald.service.in | 4 ++-- + 3 files changed, 4 insertions(+), 25 deletions(-) + delete mode 100644 units/systemd-journald-audit.socket + +diff --git a/Makefile.am b/Makefile.am +index bec32c39e..6d6b650f2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4518,8 +4518,7 @@ bin_PROGRAMS += \ + + dist_systemunit_DATA += \ + units/systemd-journald.socket \ +- units/systemd-journald-dev-log.socket \ +- units/systemd-journald-audit.socket ++ units/systemd-journald-dev-log.socket + + nodist_systemunit_DATA += \ + units/systemd-journald.service \ +@@ -4539,8 +4538,7 @@ dist_catalog_DATA = \ + + SOCKETS_TARGET_WANTS += \ + systemd-journald.socket \ +- systemd-journald-dev-log.socket \ +- systemd-journald-audit.socket ++ systemd-journald-dev-log.socket + + SYSINIT_TARGET_WANTS += \ + systemd-journald.service \ +diff --git a/units/systemd-journald-audit.socket b/units/systemd-journald-audit.socket +deleted file mode 100644 +index 35397aaeb..000000000 +--- a/units/systemd-journald-audit.socket ++++ /dev/null +@@ -1,19 +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=Journal Audit Socket +-Documentation=man:systemd-journald.service(8) man:journald.conf(5) +-DefaultDependencies=no +-Before=sockets.target +-ConditionSecurity=audit +- +-[Socket] +-Service=systemd-journald.service +-ReceiveBuffer=128M +-ListenNetlink=audit 1 +-PassCredentials=yes +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index 87704bb9c..1bcc290ec 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -10,12 +10,12 @@ Description=Journal Service + Documentation=man:systemd-journald.service(8) man:journald.conf(5) + DefaultDependencies=no + Requires=systemd-journald.socket +-After=systemd-journald.socket systemd-journald-dev-log.socket systemd-journald-audit.socket syslog.socket ++After=systemd-journald.socket systemd-journald-dev-log.socket syslog.socket + Before=sysinit.target + + [Service] + Type=notify +-Sockets=systemd-journald.socket systemd-journald-dev-log.socket systemd-journald-audit.socket ++Sockets=systemd-journald.socket systemd-journald-dev-log.socket + ExecStart=@rootlibexecdir@/systemd-journald + Restart=always + RestartSec=0 diff --git a/SOURCES/0128-factory-we-don-t-want-that.patch b/SOURCES/0128-factory-we-don-t-want-that.patch new file mode 100644 index 00000000..3e4c3732 --- /dev/null +++ b/SOURCES/0128-factory-we-don-t-want-that.patch @@ -0,0 +1,47 @@ +From c5177fff7f87e08175f6a5c9dba204ea31bfd13a Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 16 Apr 2015 11:53:05 +0200 +Subject: [PATCH] factory: we don't want that + +--- + Makefile.am | 16 ++++++++-------- + tmpfiles.d/etc.conf.m4 | 2 -- + 2 files changed, 8 insertions(+), 10 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 6d6b650f2..8474b2912 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2288,14 +2288,14 @@ INSTALL_DIRS += \ + endif + + # ------------------------------------------------------------------------------ +-dist_factory_etc_DATA = \ +- factory/etc/nsswitch.conf +- +-if HAVE_PAM +-dist_factory_pam_DATA = \ +- factory/etc/pam.d/system-auth \ +- factory/etc/pam.d/other +-endif ++#dist_factory_etc_DATA = \ ++# factory/etc/nsswitch.conf ++# ++#if HAVE_PAM ++#dist_factory_pam_DATA = \ ++# factory/etc/pam.d/system-auth \ ++# factory/etc/pam.d/other ++#endif + + # ------------------------------------------------------------------------------ + if ENABLE_FIRSTBOOT +diff --git a/tmpfiles.d/etc.conf.m4 b/tmpfiles.d/etc.conf.m4 +index 125d6e0a1..4937719bd 100644 +--- a/tmpfiles.d/etc.conf.m4 ++++ b/tmpfiles.d/etc.conf.m4 +@@ -10,5 +10,3 @@ + L /etc/os-release - - - - ../usr/lib/os-release + L /etc/localtime - - - - ../usr/share/zoneinfo/UTC + L+ /etc/mtab - - - - ../proc/self/mounts +-C /etc/nsswitch.conf - - - - +-C /etc/pam.d - - - - diff --git a/SOURCES/0129-timedated-flip-internal-status-after-executing-opera.patch b/SOURCES/0129-timedated-flip-internal-status-after-executing-opera.patch new file mode 100644 index 00000000..f0725299 --- /dev/null +++ b/SOURCES/0129-timedated-flip-internal-status-after-executing-opera.patch @@ -0,0 +1,38 @@ +From d7ca3b22fce0f97fe10a7abe6e0edc5de785ef98 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 21 Mar 2015 17:40:20 -0400 +Subject: [PATCH] timedated: flip internal status after executing operation + +timedated would set the internal status before calling out to systemd to do +the actual change. When the operation was refused because of a SELinux denial, +the state kept in timedated would get out of sync, and the second call from +timedatectl would appear to succeed. + +https://bugzilla.redhat.com/show_bug.cgi?id=1014315 +(cherry picked from commit 192b98b8fe73c8fb4bb3d6540deb93f5fb6eb9d2) +--- + src/timedate/timedated.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index 66097ef74..c3113b081 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -679,8 +679,6 @@ static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus + if (r == 0) + return 1; + +- c->use_ntp = ntp; +- + r = context_enable_ntp(c, bus, error); + if (r < 0) + return r; +@@ -689,6 +687,8 @@ static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus + if (r < 0) + return r; + ++ c->use_ntp = ntp; ++ + log_info("Set NTP to %s", c->use_ntp ? "enabled" : "disabled"); + + sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL); diff --git a/SOURCES/0130-timedated-fix-enable-disable-reversal.patch b/SOURCES/0130-timedated-fix-enable-disable-reversal.patch new file mode 100644 index 00000000..4a280d0b --- /dev/null +++ b/SOURCES/0130-timedated-fix-enable-disable-reversal.patch @@ -0,0 +1,130 @@ +From 467145adad739b0426501d2fd7ce1c0afe977e67 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 16 Apr 2015 15:22:57 +0200 +Subject: [PATCH] timedated: fix enable/disable reversal + +The state was flipped later, +but the enable/disable routine made use of the state to decide +what to do. + +context_enable_ntp() and context_start_ntp() now get the desired +state directly, so the Context parameter can be removed. + +(based on 81b843990297ad8c813c531fccd8da30bb715bd6) +--- + src/timedate/timedated.c | 50 +++++++++++++++++------------------------------- + 1 file changed, 18 insertions(+), 32 deletions(-) + +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index c3113b081..f87514936 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -280,39 +280,26 @@ static int context_read_ntp(Context *c, sd_bus *bus) { + return 0; + } + +-static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) { ++static int context_start_ntp(sd_bus *bus, sd_bus_error *error, bool enabled) { + _cleanup_strv_free_ char **l = NULL; + char **i; + int r; + +- assert(c); + assert(bus); + assert(error); + + l = get_ntp_services(); + STRV_FOREACH(i, l) { + +- if (c->use_ntp) +- r = sd_bus_call_method( +- bus, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "StartUnit", +- error, +- NULL, +- "ss", *i, "replace"); +- else +- r = sd_bus_call_method( +- bus, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "StopUnit", +- error, +- NULL, +- "ss", *i, "replace"); +- ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ enabled ? "StartUnit" : "StopUnit", ++ error, ++ NULL, ++ "ss", *i, "replace"); + if (r < 0) { + if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) || + sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") || +@@ -332,18 +319,17 @@ static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) { + return -ENOTSUP; + } + +-static int context_enable_ntp(Context*c, sd_bus *bus, sd_bus_error *error) { ++static int context_enable_ntp(sd_bus *bus, sd_bus_error *error, bool enabled) { + _cleanup_strv_free_ char **l = NULL; + char **i; + int r; + +- assert(c); + assert(bus); + assert(error); + + l = get_ntp_services(); + STRV_FOREACH(i, l) { +- if (c->use_ntp) ++ if (enabled) + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", +@@ -662,15 +648,15 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bu + } + + static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { +- int ntp, interactive; ++ int enabled, interactive; + Context *c = userdata; + int r; + +- r = sd_bus_message_read(m, "bb", &ntp, &interactive); ++ r = sd_bus_message_read(m, "bb", &enabled, &interactive); + if (r < 0) + return r; + +- if ((bool)ntp == c->use_ntp) ++ if ((bool)enabled == c->use_ntp) + return sd_bus_reply_method_return(m, NULL); + + r = bus_verify_polkit_async(m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-ntp", interactive, &c->polkit_registry, error); +@@ -679,15 +665,15 @@ static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus + if (r == 0) + return 1; + +- r = context_enable_ntp(c, bus, error); ++ r = context_enable_ntp(bus, error, enabled); + if (r < 0) + return r; + +- r = context_start_ntp(c, bus, error); ++ r = context_start_ntp(bus, error, enabled); + if (r < 0) + return r; + +- c->use_ntp = ntp; ++ c->use_ntp = enabled; + + log_info("Set NTP to %s", c->use_ntp ? "enabled" : "disabled"); + diff --git a/SOURCES/0131-core-make-SELinux-enable-disable-check-symmetric.patch b/SOURCES/0131-core-make-SELinux-enable-disable-check-symmetric.patch new file mode 100644 index 00000000..f33144c0 --- /dev/null +++ b/SOURCES/0131-core-make-SELinux-enable-disable-check-symmetric.patch @@ -0,0 +1,43 @@ +From bfd900a5a995e3bc342acd50ac816df6da37bf62 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 21 Mar 2015 18:50:10 -0400 +Subject: [PATCH] core: make SELinux enable/disable check symmetric + +We'd use the generic check for disable, and a unit-file-specific one for enable. +Use the more specific one both ways. + +systemd[1]: SELinux access check scon=system_u:system_r:systemd_timedated_t:s0 tcon=system_u:system_r:init_t:s0 tclass=system perm=disable path=(null) cmdline=/usr/lib/systemd/systemd-timedated: -13 +systemd[1]: SELinux access check scon=system_u:system_r:systemd_timedated_t:s0 tcon=system_u:object_r:systemd_unit_file_t:s0 tclass=service perm=enable path=/usr/lib/systemd/system/systemd-timesyncd.service cmdline=/usr/lib/systemd/systemd-timedated: -13 + +https://bugzilla.redhat.com/show_bug.cgi?id=1014315 +(cherry picked from commit df823e23f04da832ad5fc078176f8c26597a9845) + +Conflicts: + src/core/dbus-manager.c +--- + src/core/dbus-manager.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 8ba665dc3..2bc37ba60 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1772,15 +1772,15 @@ static int method_disable_unit_files_generic( + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + +- r = mac_selinux_access_check(message, verb, error); ++ r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + +- r = sd_bus_message_read_strv(message, &l); ++ r = sd_bus_message_read(message, "b", &runtime); + if (r < 0) + return r; + +- r = sd_bus_message_read(message, "b", &runtime); ++ r = mac_selinux_unit_access_check_strv(l, message, m, verb, error); + if (r < 0) + return r; + diff --git a/SOURCES/0132-shared-add-path_compare-an-ordering-path-comparison.patch b/SOURCES/0132-shared-add-path_compare-an-ordering-path-comparison.patch new file mode 100644 index 00000000..e517a725 --- /dev/null +++ b/SOURCES/0132-shared-add-path_compare-an-ordering-path-comparison.patch @@ -0,0 +1,149 @@ +From 331328223912b66dd25d5cb6ed250d67419d54de Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Mon, 16 Mar 2015 21:58:35 +0100 +Subject: [PATCH] shared: add path_compare(), an ordering path comparison + +... and make path_equal() a simple wrapper around it. + +(cherry picked from commit 2230852bd9755e1b7bfd1260082471f559b0a005) +--- + src/shared/path-util.c | 37 +++++++++++++++++++++++++++---------- + src/shared/path-util.h | 1 + + src/test/test-path-util.c | 36 +++++++++++++++++++++++++----------- + 3 files changed, 53 insertions(+), 21 deletions(-) + +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index 70bc1caa2..d5510bf56 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -403,12 +403,18 @@ char* path_startswith(const char *path, const char *prefix) { + } + } + +-bool path_equal(const char *a, const char *b) { ++int path_compare(const char *a, const char *b) { ++ int d; ++ + assert(a); + assert(b); + +- if ((a[0] == '/') != (b[0] == '/')) +- return false; ++ /* A relative path and an abolute path must not compare as equal. ++ * Which one is sorted before the other does not really matter. ++ * Here a relative path is ordered before an absolute path. */ ++ d = (a[0] == '/') - (b[0] == '/'); ++ if (d) ++ return d; + + for (;;) { + size_t j, k; +@@ -417,25 +423,36 @@ bool path_equal(const char *a, const char *b) { + b += strspn(b, "/"); + + if (*a == 0 && *b == 0) +- return true; ++ return 0; + +- if (*a == 0 || *b == 0) +- return false; ++ /* Order prefixes first: "/foo" before "/foo/bar" */ ++ if (*a == 0) ++ return -1; ++ if (*b == 0) ++ return 1; + + j = strcspn(a, "/"); + k = strcspn(b, "/"); + +- if (j != k) +- return false; ++ /* Alphabetical sort: "/foo/aaa" before "/foo/b" */ ++ d = memcmp(a, b, MIN(j, k)); ++ if (d) ++ return (d > 0) - (d < 0); /* sign of d */ + +- if (memcmp(a, b, j) != 0) +- return false; ++ /* Sort "/foo/a" before "/foo/aaa" */ ++ d = (j > k) - (j < k); /* sign of (j - k) */ ++ if (d) ++ return d; + + a += j; + b += k; + } + } + ++bool path_equal(const char *a, const char *b) { ++ return path_compare(a, b) == 0; ++} ++ + bool path_equal_or_files_same(const char *a, const char *b) { + return path_equal(a, b) || files_same(a, b) > 0; + } +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index bcf116ed3..ca81b49cb 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -44,6 +44,7 @@ char* path_make_absolute_cwd(const char *p); + int path_make_relative(const char *from_dir, const char *to_path, char **_r); + char* path_kill_slashes(char *path); + char* path_startswith(const char *path, const char *prefix) _pure_; ++int path_compare(const char *a, const char *b) _pure_; + bool path_equal(const char *a, const char *b) _pure_; + bool path_equal_or_files_same(const char *a, const char *b); + char* path_join(const char *root, const char *path, const char *rest); +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index 11aa52aae..6396fcb39 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -27,23 +27,37 @@ + #include "macro.h" + #include "strv.h" + ++#define test_path_compare(a, b, result) { \ ++ assert_se(path_compare(a, b) == result); \ ++ assert_se(path_compare(b, a) == -result); \ ++ assert_se(path_equal(a, b) == !result); \ ++ assert_se(path_equal(b, a) == !result); \ ++ } + + static void test_path(void) { +- assert_se(path_equal("/goo", "/goo")); +- assert_se(path_equal("//goo", "/goo")); +- assert_se(path_equal("//goo/////", "/goo")); +- assert_se(path_equal("goo/////", "goo")); ++ test_path_compare("/goo", "/goo", 0); ++ test_path_compare("/goo", "/goo", 0); ++ test_path_compare("//goo", "/goo", 0); ++ test_path_compare("//goo/////", "/goo", 0); ++ test_path_compare("goo/////", "goo", 0); ++ ++ test_path_compare("/goo/boo", "/goo//boo", 0); ++ test_path_compare("//goo/boo", "/goo/boo//", 0); + +- assert_se(path_equal("/goo/boo", "/goo//boo")); +- assert_se(path_equal("//goo/boo", "/goo/boo//")); ++ test_path_compare("/", "///", 0); + +- assert_se(path_equal("/", "///")); ++ test_path_compare("/x", "x/", 1); ++ test_path_compare("x/", "/", -1); + +- assert_se(!path_equal("/x", "x/")); +- assert_se(!path_equal("x/", "/")); ++ test_path_compare("/x/./y", "x/y", 1); ++ test_path_compare("x/.y", "x/y", -1); + +- assert_se(!path_equal("/x/./y", "x/y")); +- assert_se(!path_equal("x/.y", "x/y")); ++ test_path_compare("foo", "/foo", -1); ++ test_path_compare("/foo", "/foo/bar", -1); ++ test_path_compare("/foo/aaa", "/foo/b", -1); ++ test_path_compare("/foo/aaa", "/foo/b/a", -1); ++ test_path_compare("/foo/a", "/foo/aaa", -1); ++ test_path_compare("/foo/a/b", "/foo/aaa", -1); + + assert_se(path_is_absolute("/")); + assert_se(!path_is_absolute("./")); diff --git a/SOURCES/0133-core-namespace-fix-path-sorting.patch b/SOURCES/0133-core-namespace-fix-path-sorting.patch new file mode 100644 index 00000000..49a47e6a --- /dev/null +++ b/SOURCES/0133-core-namespace-fix-path-sorting.patch @@ -0,0 +1,58 @@ +From 0881ff2b6842798836faef3a55a04a3e6e0cbb66 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Mon, 16 Mar 2015 22:04:21 +0100 +Subject: [PATCH] core/namespace: fix path sorting + +The comparison function we use for qsorting paths is overly indifferent. +Consider these 3 paths for sorting: + /foo + /bar + /foo/foo +qsort() may compare: + "/foo" with "/bar" => 0, indifference + "/bar" with "/foo/foo" => 0, indifference +and assume transitively that "/foo" and "/foo/foo" are also indifferent. + +But this is wrong, we want "/foo" sorted before "/foo/foo". +The comparison function must be transitive. + +Use path_compare(), which behaves properly. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1184016 +(cherry picked from commit a0827e2b123010c46cfe4f03eebba57d92f9efc4) +--- + src/core/namespace.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/src/core/namespace.c b/src/core/namespace.c +index 4fecd3236..d4f1c8621 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -91,9 +91,11 @@ static int append_mounts(BindMount **p, char **strv, MountMode mode) { + + static int mount_path_compare(const void *a, const void *b) { + const BindMount *p = a, *q = b; ++ int d; + +- if (path_equal(p->path, q->path)) { ++ d = path_compare(p->path, q->path); + ++ if (!d) { + /* If the paths are equal, check the mode */ + if (p->mode < q->mode) + return -1; +@@ -105,13 +107,7 @@ static int mount_path_compare(const void *a, const void *b) { + } + + /* If the paths are not equal, then order prefixes first */ +- if (path_startswith(p->path, q->path)) +- return 1; +- +- if (path_startswith(q->path, p->path)) +- return -1; +- +- return 0; ++ return d; + } + + static void drop_duplicates(BindMount *m, unsigned *n) { diff --git a/SOURCES/0134-machine-do-not-rely-on-asprintf-setting-arg-on-error.patch b/SOURCES/0134-machine-do-not-rely-on-asprintf-setting-arg-on-error.patch new file mode 100644 index 00000000..6b99b79a --- /dev/null +++ b/SOURCES/0134-machine-do-not-rely-on-asprintf-setting-arg-on-error.patch @@ -0,0 +1,44 @@ +From 4e78db7126779a9f6432ead9a73cdab1087405bc Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 17 Apr 2015 15:12:00 +0200 +Subject: [PATCH] machine: do not rely on asprintf setting arg on error + +Strictly speaking, the output variable is undefined if asprintf fails. +We use the return value not the arg everywhere, and should we do here. + +(Based on 2c07315225bef6be4830bce25a74da7f0ba4fcdc) +--- + src/machine/machine-dbus.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c +index b0f0f66e0..624a99f4e 100644 +--- a/src/machine/machine-dbus.c ++++ b/src/machine/machine-dbus.c +@@ -438,6 +438,7 @@ int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *us + _cleanup_close_ int master = -1; + Machine *m = userdata; + const char *p; ++ char *address; + int r; + + if (m->class != MACHINE_CONTAINER) +@@ -475,13 +476,14 @@ int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *us + return r; + + #ifdef ENABLE_KDBUS +- asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader); ++# define ADDRESS_FMT "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI + #else +- asprintf(&container_bus->address, "x-machine-unix:pid=" PID_FMT, m->leader); ++# define ADDRESS_FMT "x-machine-unix:pid=%1$" PID_PRI + #endif +- if (!container_bus->address) +- return -ENOMEM; ++ if (asprintf(&address, ADDRESS_FMT, m->leader) < 0) ++ return log_oom(); + ++ container_bus->address = address; + container_bus->bus_client = true; + container_bus->trusted = false; + container_bus->is_system = true; diff --git a/SOURCES/0135-some-compilators-don-t-support-__INCLUDE_LEVEL__.patch b/SOURCES/0135-some-compilators-don-t-support-__INCLUDE_LEVEL__.patch new file mode 100644 index 00000000..003982d4 --- /dev/null +++ b/SOURCES/0135-some-compilators-don-t-support-__INCLUDE_LEVEL__.patch @@ -0,0 +1,22 @@ +From 5a21b0644425a8f1decdb6d52b93e2a73d5c75bf Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 21 Apr 2015 17:02:22 +0200 +Subject: [PATCH] some compilators don't support __INCLUDE_LEVEL__ + +--- + src/systemd/_sd-common.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h +index 896a027eb..e9426a450 100644 +--- a/src/systemd/_sd-common.h ++++ b/src/systemd/_sd-common.h +@@ -24,7 +24,7 @@ + + /* This is a private header; never even think of including this directly! */ + +-#if __INCLUDE_LEVEL__ <= 1 ++#if defined __INCLUDE_LEVEL__ && __INCLUDE_LEVEL__ <= 1 + #error "Do not include _sd-common.h directly; it is a private header." + #endif + diff --git a/SOURCES/0136-udev-net_id-support-multi-port-enpo-device-names.patch b/SOURCES/0136-udev-net_id-support-multi-port-enpo-device-names.patch new file mode 100644 index 00000000..7a4763ac --- /dev/null +++ b/SOURCES/0136-udev-net_id-support-multi-port-enpo-device-names.patch @@ -0,0 +1,72 @@ +From 88eb414beca3ab29f40a6e422faa790ddaae2918 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 1 Apr 2015 16:51:02 +0200 +Subject: [PATCH] udev: net_id - support multi-port enpo* device names + +I'd argue that having firmware labels for such devices makes +no sense, but they exist, so make sure we handle them as best +as we can. +--- + src/udev/udev-builtin-net_id.c | 33 +++++++++++++++++++++++++-------- + 1 file changed, 25 insertions(+), 8 deletions(-) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 99caa0a2a..6a5ada688 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -35,7 +35,7 @@ + * Type of names: + * b -- BCMA bus core number + * ccw -- CCW bus group name +- * o -- on-board device index number ++ * o[d] -- on-board device index number + * s[f][d] -- hotplug slot index number + * x -- MAC address + * [P]ps[f][d/] +@@ -128,22 +128,39 @@ struct netnames { + + /* retrieve on-board index number and label from firmware */ + static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { +- const char *index; ++ unsigned dev_port = 0; ++ size_t l; ++ char *s; ++ const char *attr; + int idx; + + /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ +- index = udev_device_get_sysattr_value(names->pcidev, "acpi_index"); ++ attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index"); + /* SMBIOS type 41 -- Onboard Devices Extended Information */ +- if (!index) +- index = udev_device_get_sysattr_value(names->pcidev, "index"); +- if (!index) ++ if (!attr) ++ attr = udev_device_get_sysattr_value(names->pcidev, "index"); ++ if (!attr) + return -ENOENT; +- idx = strtoul(index, NULL, 0); ++ ++ idx = strtoul(attr, NULL, 0); + if (idx <= 0) + return -EINVAL; +- snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx); ++ ++ /* kernel provided multi-device index */ ++ attr = udev_device_get_sysattr_value(dev, "dev_port"); ++ if (attr) ++ dev_port = strtol(attr, NULL, 10); ++ ++ s = names->pci_onboard; ++ l = sizeof(names->pci_onboard); ++ l = strpcpyf(&s, l, "o%d", idx); ++ if (dev_port > 0) ++ l = strpcpyf(&s, l, "d%d", dev_port); ++ if (l == 0) ++ names->pci_onboard[0] = '\0'; + + names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label"); ++ + return 0; + } + diff --git a/SOURCES/0137-udev-net_id-improve-comments.patch b/SOURCES/0137-udev-net_id-improve-comments.patch new file mode 100644 index 00000000..fb67f9a9 --- /dev/null +++ b/SOURCES/0137-udev-net_id-improve-comments.patch @@ -0,0 +1,35 @@ +From 127c3f7b5ca3158851dc4a747f664ce43b2a94ee Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 1 Apr 2015 23:34:19 +0200 +Subject: [PATCH] udev: net_id - improve comments + +The dev_port concept is a bit confusing, expand on the comment a bit. + +Conflicts: + src/udev/udev-builtin-net_id.c +--- + src/udev/udev-builtin-net_id.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 6a5ada688..2cc1fd409 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -146,7 +146,7 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + if (idx <= 0) + return -EINVAL; + +- /* kernel provided multi-device index */ ++ /* kernel provided port index for multiple ports on a single PCI function */ + attr = udev_device_get_sysattr_value(dev, "dev_port"); + if (attr) + dev_port = strtol(attr, NULL, 10); +@@ -199,7 +199,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4) + return -ENOENT; + +- /* kernel provided multi-device index */ ++ /* kernel provided port index for multiple ports on a single PCI function */ + attr = udev_device_get_sysattr_value(dev, "dev_id"); + if (attr) { + dev_id = strtol(attr, NULL, 16); diff --git a/SOURCES/0138-udev-restore-udevadm-settle-timeout.patch b/SOURCES/0138-udev-restore-udevadm-settle-timeout.patch new file mode 100644 index 00000000..32103df3 --- /dev/null +++ b/SOURCES/0138-udev-restore-udevadm-settle-timeout.patch @@ -0,0 +1,53 @@ +From b2575f7d4f06ab9df5c5744e0324160effda437e Mon Sep 17 00:00:00 2001 +From: Nir Soffer +Date: Wed, 8 Apr 2015 04:04:16 +0300 +Subject: [PATCH] udev: restore udevadm settle timeout + +Commit 9ea28c55a2 (udev: remove seqnum API and all assumptions about +seqnums) introduced a regresion, ignoring the timeout option when +waiting until the event queue is empty. + +Previously, if the udev event queue was not empty when the timeout was +expired, udevadm settle was returning with exit code 1. To check if the +queue is empty, you could invoke udevadm settle with timeout=0. This +patch restores the previous behavior. + +(David: fixed timeout==0 handling and dropped redundant assignment) + +Cherry-picked from: 0736455b1186c9515e0f093e1e686e684d225787 +Resolves: #1210981 +--- + src/udev/udevadm-settle.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c +index fff5de7a8..e60c4623b 100644 +--- a/src/udev/udevadm-settle.c ++++ b/src/udev/udevadm-settle.c +@@ -56,6 +56,7 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) { + { "quiet", no_argument, NULL, 'q' }, /* removed */ + {} + }; ++ usec_t deadline; + const char *exists = NULL; + unsigned int timeout = 120; + struct pollfd pfd[1] = { {.fd = -1}, }; +@@ -105,6 +106,8 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) { + return EXIT_FAILURE; + } + ++ deadline = now(CLOCK_MONOTONIC) + timeout * USEC_PER_SEC; ++ + /* guarantee that the udev daemon isn't pre-processing */ + if (getuid() == 0) { + struct udev_ctrl *uctrl; +@@ -146,6 +149,9 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) { + break; + } + ++ if (timeout > 0 && now(CLOCK_MONOTONIC) >= deadline) ++ break; ++ + /* wake up when queue is empty */ + if (poll(pfd, 1, MSEC_PER_SEC) > 0 && pfd[0].revents & POLLIN) + udev_queue_flush(queue); diff --git a/SOURCES/0139-udev-settle-should-return-immediately-when-timeout-i.patch b/SOURCES/0139-udev-settle-should-return-immediately-when-timeout-i.patch new file mode 100644 index 00000000..426c8d72 --- /dev/null +++ b/SOURCES/0139-udev-settle-should-return-immediately-when-timeout-i.patch @@ -0,0 +1,38 @@ +From 98b78068d13095fdd40883b2b6c815a9ebb59435 Mon Sep 17 00:00:00 2001 +From: Nir Soffer +Date: Sun, 19 Apr 2015 03:41:26 +0300 +Subject: [PATCH] udev: settle should return immediately when timeout is 0 + +udevadm manual says: + + A value of 0 will check if the queue is empty and always return + immediately. + +However, currently we ignore the deadline if the value is 0, and wait +without any limit. + +Zero timeout behaved according to the documentation until commit +ead7c62ab7 (udevadm: settle - kill alarm()). Looking at this patch, it +seems that the behavior change was unintended. + +This patch restores the documented behavior. + +Cherry-picked from: bf23b9f86f6807c3029a6a46e1999ae0c87ca22a +Resolves: #1210981 +--- + src/udev/udevadm-settle.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c +index e60c4623b..40e3e28b1 100644 +--- a/src/udev/udevadm-settle.c ++++ b/src/udev/udevadm-settle.c +@@ -149,7 +149,7 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) { + break; + } + +- if (timeout > 0 && now(CLOCK_MONOTONIC) >= deadline) ++ if (now(CLOCK_MONOTONIC) >= deadline) + break; + + /* wake up when queue is empty */ diff --git a/SOURCES/0140-udev-Fix-ping-timeout-when-settle-timeout-is-0.patch b/SOURCES/0140-udev-Fix-ping-timeout-when-settle-timeout-is-0.patch new file mode 100644 index 00000000..60da9778 --- /dev/null +++ b/SOURCES/0140-udev-Fix-ping-timeout-when-settle-timeout-is-0.patch @@ -0,0 +1,30 @@ +From e7cd53f60cc2cb5e98efa0e88cfd0e7dd8325085 Mon Sep 17 00:00:00 2001 +From: Nir Soffer +Date: Sun, 19 Apr 2015 02:49:47 +0300 +Subject: [PATCH] udev: Fix ping timeout when settle timeout is 0 + +When running udevadm settle --timeout=0, the ping always times out, and +udevadm will return 0 without checking the queue state. + +(David: Use a reasonable timeout to still get the barrier provided by + ctrl-ping) + +Cherry-picked from: 7375b3c4871861f100860ea4c2848e66b60e6ca4 +Resolves: #1210981 +--- + src/udev/udevadm-settle.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c +index 40e3e28b1..33597bc20 100644 +--- a/src/udev/udevadm-settle.c ++++ b/src/udev/udevadm-settle.c +@@ -114,7 +114,7 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) { + + uctrl = udev_ctrl_new(udev); + if (uctrl != NULL) { +- if (udev_ctrl_send_ping(uctrl, timeout) < 0) { ++ if (udev_ctrl_send_ping(uctrl, MAX(5U, timeout)) < 0) { + log_debug("no connection to daemon"); + udev_ctrl_unref(uctrl); + return EXIT_SUCCESS; diff --git a/SOURCES/0141-detect-virt-use-proc-device-tree.patch b/SOURCES/0141-detect-virt-use-proc-device-tree.patch new file mode 100644 index 00000000..04a3a33b --- /dev/null +++ b/SOURCES/0141-detect-virt-use-proc-device-tree.patch @@ -0,0 +1,29 @@ +From 436a001a5a28b9e3dd0988cc5a88bd3d7ec0acc8 Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Tue, 31 Mar 2015 11:08:11 +0200 +Subject: [PATCH] detect-virt: use /proc/device-tree + +Kernel doc Documentation/ABI/testing/sysfs-firmware-ofw says that +the /proc/device-tree symlink should be used, as opposed to +directly accessing /sys/firmware/devicetree/base. The former is +ABI, but not the later. + +Cherry-picked from: b8f1df82646d2 +Resolves: #1207773 +--- + src/shared/virt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/virt.c b/src/shared/virt.c +index 7c1381f4b..aa3501f42 100644 +--- a/src/shared/virt.c ++++ b/src/shared/virt.c +@@ -106,7 +106,7 @@ static int detect_vm_devicetree(const char **_id) { + _cleanup_free_ char *hvtype = NULL; + int r; + +- r = read_one_line_file("/sys/firmware/devicetree/base/hypervisor/compatible", &hvtype); ++ r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype); + if (r >= 0) { + if (streq(hvtype, "linux,kvm")) { + *_id = "kvm"; diff --git a/SOURCES/0142-ARM-detect-virt-detect-Xen.patch b/SOURCES/0142-ARM-detect-virt-detect-Xen.patch new file mode 100644 index 00000000..1948e9a3 --- /dev/null +++ b/SOURCES/0142-ARM-detect-virt-detect-Xen.patch @@ -0,0 +1,34 @@ +From 6378069c62b2e5b1005df6bd243709181c178d1c Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Tue, 31 Mar 2015 11:08:12 +0200 +Subject: [PATCH] ARM: detect-virt: detect Xen + +Cherry-picked from: db6a86897efb3 +Resolves: #1207773 +--- + src/shared/virt.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/shared/virt.c b/src/shared/virt.c +index aa3501f42..712523210 100644 +--- a/src/shared/virt.c ++++ b/src/shared/virt.c +@@ -102,7 +102,7 @@ static int detect_vm_cpuid(const char **_id) { + } + + static int detect_vm_devicetree(const char **_id) { +-#if defined(__powerpc__) || defined(__powerpc64__) ++#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__) + _cleanup_free_ char *hvtype = NULL; + int r; + +@@ -111,6 +111,9 @@ static int detect_vm_devicetree(const char **_id) { + if (streq(hvtype, "linux,kvm")) { + *_id = "kvm"; + return 1; ++ } else if (strstr(hvtype, "xen")) { ++ *_id = "xen"; ++ return 1; + } + } + #endif diff --git a/SOURCES/0143-ARM-detect-virt-detect-QEMU-KVM.patch b/SOURCES/0143-ARM-detect-virt-detect-QEMU-KVM.patch new file mode 100644 index 00000000..4dc9a041 --- /dev/null +++ b/SOURCES/0143-ARM-detect-virt-detect-QEMU-KVM.patch @@ -0,0 +1,55 @@ +From fa2237b9987c39147704274937895547c8c8d647 Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Tue, 31 Mar 2015 11:08:13 +0200 +Subject: [PATCH] ARM: detect-virt: detect QEMU/KVM + +QEMU/KVM guests do not have hypervisor nodes, but they do have +fw-cfg nodes (since qemu v2.3.0-rc0). fw-cfg nodes are documented, +see kernel doc Documentation/devicetree/bindings/arm/fw-cfg.txt, +and therefore we should be able to rely on it in this detection. + +Unfortunately, we currently don't have enough information in the +DT, or elsewhere, to determine if we're using KVM acceleration +with QEMU or not, so we can only report 'qemu' at this time, even +if KVM is in use. This shouldn't really matter in practice though, +because if detect-virt is used interactively it will be clear to +the user whether or not KVM acceleration is present by the overall +speed of the guest. If used by a script, then the script's behavior +should not change whether it's 'qemu' or 'kvm'. QEMU emulated +guests and QEMU/KVM guests of the same type should behave +identically, only the speed at which they run should differ. + +Cherry-picked from: ce09c71d56a11 +Resolves: #1207773 +--- + src/shared/virt.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/src/shared/virt.c b/src/shared/virt.c +index 712523210..54c465520 100644 +--- a/src/shared/virt.c ++++ b/src/shared/virt.c +@@ -115,6 +115,23 @@ static int detect_vm_devicetree(const char **_id) { + *_id = "xen"; + return 1; + } ++ } else if (r == -ENOENT) { ++ _cleanup_closedir_ DIR *dir = NULL; ++ struct dirent *dent; ++ ++ dir = opendir("/proc/device-tree"); ++ if (!dir) { ++ if (errno == ENOENT) ++ return 0; ++ return -errno; ++ } ++ ++ FOREACH_DIRENT(dent, dir, return -errno) { ++ if (strstr(dent->d_name, "fw-cfg")) { ++ *_id = "qemu"; ++ return 1; ++ } ++ } + } + #endif + return 0; diff --git a/SOURCES/0144-Persistent-by_path-links-for-ata-devices.patch b/SOURCES/0144-Persistent-by_path-links-for-ata-devices.patch new file mode 100644 index 00000000..ef159bce --- /dev/null +++ b/SOURCES/0144-Persistent-by_path-links-for-ata-devices.patch @@ -0,0 +1,104 @@ +From 8572638ab99090b016ccc28ac1f69aa7759e43cf Mon Sep 17 00:00:00 2001 +From: Robert Milasan +Date: Thu, 12 Jul 2012 15:56:34 +0000 +Subject: [PATCH] Persistent by_path links for ata devices + +With newer kernel we have the 'port_no' attribute, +which allows us to construct a valid ata by-path link. + +With this patch ATA links of the form + +ata-.[01] + +(for master/slave devices) or + +ata-..0 + +(for devices behind port multipliers) +are generated. + +References: bnc#770910,FATE#317063 + +Signed-off-by: Robert Milasan +Signed-off-by: Hannes Reinecke + +Downstream patch +https://build.opensuse.org/package/view_file/Base:System/systemd/1001-re-enable-by_path-links-for-ata-devices.patch + +Resolves: #1045498 +--- + src/udev/udev-builtin-path_id.c | 53 +++++++++++++++++++++++++++++++---------- + 1 file changed, 41 insertions(+), 12 deletions(-) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index b6749aab7..bb0a6242a 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -426,6 +426,46 @@ static struct udev_device *handle_scsi_hyperv(struct udev_device *parent, char * + return parent; + } + ++static struct udev_device *handle_ata(struct udev_device *parent, char **path) ++{ ++ struct udev *udev = udev_device_get_udev(parent); ++ struct udev_device *hostdev, *portdev; ++ int host, bus, target, lun, port_no; ++ const char *name, *atahost, *port; ++ ++ hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host"); ++ if (hostdev == NULL) ++ return NULL; ++ ++ name = udev_device_get_sysname(parent); ++ if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) ++ return NULL; ++ ++ /* The ata port is the parent of the SCSI host */ ++ hostdev = udev_device_get_parent(hostdev); ++ atahost = udev_device_get_sysname(hostdev); ++ if (strncmp(atahost, "ata", 3)) ++ return NULL; ++ ++ /* ATA port number is found in 'port_no' attribute */ ++ portdev = udev_device_new_from_subsystem_sysname(udev, "ata_port", ++ atahost); ++ port = udev_device_get_sysattr_value(portdev, "port_no"); ++ if (!port || sscanf(port, "%d", &port_no) != 1) { ++ hostdev = NULL; ++ goto out; ++ } ++ if (bus != 0) ++ /* Devices behind port multiplier have a bus != 0*/ ++ path_prepend(path, "ata-%u.%u.0", port_no, bus); ++ else ++ /* Master/slave are distinguished by target id */ ++ path_prepend(path, "ata-%u.%u", port_no, target); ++out: ++ udev_device_unref(portdev); ++ return hostdev; ++} ++ + static struct udev_device *handle_scsi(struct udev_device *parent, char **path, bool *supported_parent) { + const char *devtype; + const char *name; +@@ -465,19 +505,8 @@ static struct udev_device *handle_scsi(struct udev_device *parent, char **path, + goto out; + } + +- /* +- * We do not support the ATA transport class, it uses global counters +- * to name the ata devices which numbers spread across multiple +- * controllers. +- * +- * The real link numbers are not exported. Also, possible chains of ports +- * behind port multipliers cannot be composed that way. +- * +- * Until all that is solved at the kernel level, there are no by-path/ +- * links for ATA devices. +- */ + if (strstr(name, "/ata") != NULL) { +- parent = NULL; ++ parent = handle_ata(parent, path); + goto out; + } + diff --git a/SOURCES/0145-man-document-forwarding-to-syslog-better.patch b/SOURCES/0145-man-document-forwarding-to-syslog-better.patch new file mode 100644 index 00000000..5a5e5300 --- /dev/null +++ b/SOURCES/0145-man-document-forwarding-to-syslog-better.patch @@ -0,0 +1,118 @@ +From 24d007a0a8a77a6b75c6c7a403fc8d107875ebdc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 9 May 2015 16:20:51 -0500 +Subject: [PATCH] man: document forwarding to syslog better + +https://bugzilla.redhat.com/show_bug.cgi?id=1147651 + +Cherry-picked from: 589532d0 +Resolves: #1177336 +--- + man/journald.conf.xml | 70 ++++++++++++++++++++++++++++++++------------------- + 1 file changed, 44 insertions(+), 26 deletions(-) + +diff --git a/man/journald.conf.xml b/man/journald.conf.xml +index 85146b0d8..abfe3130d 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -97,7 +97,7 @@ + needed, so that its existence controls where log data goes. + none turns off all storage, all log data + received will be dropped. Forwarding to other targets, such as +- the console, the kernel log buffer or a syslog daemon will ++ the console, the kernel log buffer, or a syslog socket will + still work however. Defaults to + auto. + +@@ -220,27 +220,19 @@ + journald will stop using more space, but it will not be + removing existing files to go reduce footprint either. + +- SystemMaxFileSize= +- and +- RuntimeMaxFileSize= +- control how large individual journal +- files may grow at maximum. This +- influences the granularity in which +- disk space is made available through +- rotation, i.e. deletion of historic +- data. Defaults to one eighth of the +- values configured with ++ SystemMaxFileSize= and ++ RuntimeMaxFileSize= control how large ++ individual journal files may grow at maximum. This influences ++ the granularity in which disk space is made available through ++ rotation, i.e. deletion of historic data. Defaults to one ++ eighth of the values configured with + SystemMaxUse= and +- RuntimeMaxUse=, so +- that usually seven rotated journal +- files are kept as history. Specify +- values in bytes or use K, M, G, T, P, +- E as units for the specified sizes +- (equal to 1024, 1024²,... bytes). +- Note that size limits are enforced +- synchronously when journal files are +- extended, and no explicit rotation +- step triggered by time is ++ RuntimeMaxUse=, so that usually seven ++ rotated journal files are kept as history. Specify values in ++ bytes or use K, M, G, T, P, E as units for the specified sizes ++ (equal to 1024, 1024²,... bytes). Note that size limits are ++ enforced synchronously when journal files are extended, and no ++ explicit rotation step triggered by time is + needed. + + +@@ -308,13 +300,13 @@ + daemon, to the kernel log buffer (kmsg), to the system + console, or sent as wall messages to all logged-in users. + These options take boolean arguments. If forwarding to syslog +- is enabled but no syslog daemon is running, the respective +- option has no effect. By default, only forwarding wall is +- enabled. These settings may be overridden at boot time with +- the kernel command line options ++ is enabled but nothing reads messages from the socket, ++ forwarding to syslog has no effect. By default, only ++ forwarding to wall is enabled. These settings may be ++ overridden at boot time with the kernel command line options + systemd.journald.forward_to_syslog=, + systemd.journald.forward_to_kmsg=, +- systemd.journald.forward_to_console= and ++ systemd.journald.forward_to_console=, and + systemd.journald.forward_to_wall=. When + forwarding to the console, the TTY to log to can be changed + with TTYPath=, described +@@ -365,6 +357,32 @@ + + + ++ ++ Forwarding to traditional syslog daemons ++ ++ ++ Journal events can be transfered to a different logging daemon ++ in two different ways. In the first method, messages are ++ immediately forwarded to a socket ++ (/run/systemd/journal/syslog), where the ++ traditional syslog daemon can read them. This method is ++ controlled by ForwardToSyslog= option. In a ++ second method, a syslog daemon behaves like a normal journal ++ client, and reads messages from the journal files, similarly to ++ journalctl1. ++ In this method, messages do not have to be read immediately, ++ which allows a logging daemon which is only started late in boot ++ to access all messages since the start of the system. In ++ addition, full structured meta-data is available to it. This ++ method of course is available only if the messages are stored in ++ a journal file at all. So it will work if ++ Storage=none is set. It should be noted that ++ usualy the second method is used by syslog ++ daemons, so the Storage= option, and not the ++ ForwardToSyslog= option, is relevant for them. ++ ++ ++ + + See Also + diff --git a/SOURCES/0146-man-fix-typos-in-previous-comimt.patch b/SOURCES/0146-man-fix-typos-in-previous-comimt.patch new file mode 100644 index 00000000..82736f89 --- /dev/null +++ b/SOURCES/0146-man-fix-typos-in-previous-comimt.patch @@ -0,0 +1,36 @@ +From 363e3817cc3462c42e837677768f10fa549966f7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 9 May 2015 19:46:15 -0400 +Subject: [PATCH] man: fix typos in previous comimt + +Cherry-picked from: 7703bd4d +Resolves: #1177336 +--- + man/journald.conf.xml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/man/journald.conf.xml b/man/journald.conf.xml +index abfe3130d..2cbe58bc1 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -361,7 +361,7 @@ + Forwarding to traditional syslog daemons + + +- Journal events can be transfered to a different logging daemon ++ Journal events can be transferred to a different logging daemon + in two different ways. In the first method, messages are + immediately forwarded to a socket + (/run/systemd/journal/syslog), where the +@@ -375,9 +375,9 @@ + to access all messages since the start of the system. In + addition, full structured meta-data is available to it. This + method of course is available only if the messages are stored in +- a journal file at all. So it will work if ++ a journal file at all. So it will not work if + Storage=none is set. It should be noted that +- usualy the second method is used by syslog ++ usually the second method is used by syslog + daemons, so the Storage= option, and not the + ForwardToSyslog= option, is relevant for them. + diff --git a/SOURCES/0147-LSB-always-add-network-online.target-to-services-wit.patch b/SOURCES/0147-LSB-always-add-network-online.target-to-services-wit.patch new file mode 100644 index 00000000..54b30985 --- /dev/null +++ b/SOURCES/0147-LSB-always-add-network-online.target-to-services-wit.patch @@ -0,0 +1,31 @@ +From 47ad778fc50382b916683a628b3f6f62754cc17d Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 13 May 2015 15:20:30 +0200 +Subject: [PATCH] LSB: always add network-online.target to services with + priority over 10 + +rhel-only + +Resolves: #1189253 +--- + src/sysv-generator/sysv-generator.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 0125ca27d..cfc4a99e4 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -692,6 +692,13 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { + if (s->sysv_start_priority < 0) + return 0; + ++ /* RHEL-only, services with more than 10 should be start after network */ ++ if (s->sysv_start_priority > 10) { ++ r = strv_extend(&s->after, SPECIAL_NETWORK_ONLINE_TARGET); ++ if (r < 0) ++ return log_oom(); ++ } ++ + HASHMAP_FOREACH(other, all_services, j) { + if (s == other) + continue; diff --git a/SOURCES/0148-rules-enable-memory-hotplug.patch b/SOURCES/0148-rules-enable-memory-hotplug.patch new file mode 100644 index 00000000..2b3aad82 --- /dev/null +++ b/SOURCES/0148-rules-enable-memory-hotplug.patch @@ -0,0 +1,24 @@ +From 57adc4317ee2553d2d3ac84ef9625ed9c1cf5700 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 13 May 2015 16:56:44 +0200 +Subject: [PATCH] rules: enable memory hotplug + +rhel-only + +Resolves: #1105020 +--- + rules/40-redhat.rules | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 2b494e57c..8231caae9 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -1,3 +1,7 @@ + # do not edit this file, it will be overwritten on update + ++# CPU hotadd request + SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" ++ ++# Memory hotadd request ++SUBSYSTEM=="memory", ACTION=="add", ATTR{state}=="offline", ATTR{state}="online" diff --git a/SOURCES/0149-rules-reload-sysctl-settings-when-the-bridge-module-.patch b/SOURCES/0149-rules-reload-sysctl-settings-when-the-bridge-module-.patch new file mode 100644 index 00000000..cc7d2372 --- /dev/null +++ b/SOURCES/0149-rules-reload-sysctl-settings-when-the-bridge-module-.patch @@ -0,0 +1,22 @@ +From 05f3e4b89d6503a4a327be9bee9802097bc8c860 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 13 May 2015 17:11:48 +0200 +Subject: [PATCH] rules: reload sysctl settings when the bridge module is + loaded + +Resolves: #1182105 +--- + rules/40-redhat.rules | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 8231caae9..556a3a3a9 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -5,3 +5,6 @@ SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online} + + # Memory hotadd request + SUBSYSTEM=="memory", ACTION=="add", ATTR{state}=="offline", ATTR{state}="online" ++ ++# reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded ++ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge" diff --git a/SOURCES/0150-console-getty.service-don-t-start-when-dev-console-i.patch b/SOURCES/0150-console-getty.service-don-t-start-when-dev-console-i.patch new file mode 100644 index 00000000..16c4488d --- /dev/null +++ b/SOURCES/0150-console-getty.service-don-t-start-when-dev-console-i.patch @@ -0,0 +1,54 @@ +From c37bc5ac3a7282cccd090d20a3cf7120e31c4ee5 Mon Sep 17 00:00:00 2001 +From: Jan Pazdziora +Date: Fri, 13 Mar 2015 12:57:18 +0100 +Subject: [PATCH] console-getty.service: don't start when /dev/console is + missing + +Create minimal image which runs systemd + + FROM rhel7.1 + RUN yum install -y /usr/bin/ps + ENV container docker + CMD [ "/usr/sbin/init" ] + +When you run the container without -t, the process + + /sbin/agetty --noclear --keep-baud console 115200 38400 9600 + +is not happy and checking the journal in the container, there is a stream of + +Mar 13 04:50:15 11bf07f59fff agetty[66]: /dev/console: No such file or directory +Mar 13 04:50:25 11bf07f59fff systemd[1]: console-getty.service holdoff time over, scheduling restart. +Mar 13 04:50:25 11bf07f59fff systemd[1]: Stopping Console Getty... +Mar 13 04:50:25 11bf07f59fff systemd[1]: Starting Console Getty... +Mar 13 04:50:25 11bf07f59fff systemd[1]: Started Console Getty. +Mar 13 04:50:25 11bf07f59fff agetty[67]: /dev/console: No such file or directory +Mar 13 04:50:35 11bf07f59fff systemd[1]: console-getty.service holdoff time over, scheduling restart. +Mar 13 04:50:35 11bf07f59fff systemd[1]: Stopping Console Getty... +Mar 13 04:50:35 11bf07f59fff systemd[1]: Starting Console Getty... +Mar 13 04:50:35 11bf07f59fff systemd[1]: Started Console Getty. +Mar 13 04:50:35 11bf07f59fff agetty[74]: /dev/console: No such file or directory +Mar 13 04:50:45 11bf07f59fff systemd[1]: console-getty.service holdoff time over, scheduling restart. +Mar 13 04:50:45 11bf07f59fff systemd[1]: Stopping Console Getty... +Mar 13 04:50:45 11bf07f59fff systemd[1]: Starting Console Getty... + +(cherry picked from commit 1b41981d9a62443d566df6bcabc1b5024e9f5e4a) + +Cherry-picked from: 77d83ce +Resolves: #1222517 +--- + units/console-getty.service.m4.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/console-getty.service.m4.in b/units/console-getty.service.m4.in +index 8ac51a471..413d94094 100644 +--- a/units/console-getty.service.m4.in ++++ b/units/console-getty.service.m4.in +@@ -9,6 +9,7 @@ + Description=Console Getty + 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 + )m4_dnl diff --git a/SOURCES/0151-resolved-Do-not-add-.busname-dependencies-when-compi.patch b/SOURCES/0151-resolved-Do-not-add-.busname-dependencies-when-compi.patch new file mode 100644 index 00000000..06c76da2 --- /dev/null +++ b/SOURCES/0151-resolved-Do-not-add-.busname-dependencies-when-compi.patch @@ -0,0 +1,63 @@ +From 33ee9624d4fb50f29f2e3c8ffd0c7efa95a03f02 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Tue, 17 Mar 2015 16:37:07 +0100 +Subject: [PATCH] resolved: Do not add .busname dependencies, when compiling + without kdbus. + +(cherry picked from commit defa8e675b2903ad53e093bb2847c7256f0779a5) + +Cherry-picked from: 33ff64c +Resolves: #1222517 +--- + Makefile.am | 2 +- + units/.gitignore | 1 + + units/{systemd-resolved.service.in => systemd-resolved.service.m4.in} | 2 ++ + 3 files changed, 4 insertions(+), 1 deletion(-) + rename units/{systemd-resolved.service.in => systemd-resolved.service.m4.in} (96%) + +diff --git a/Makefile.am b/Makefile.am +index 8474b2912..604eaf2f1 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5520,7 +5520,7 @@ dist_dbussystemservice_DATA += \ + src/resolve/org.freedesktop.resolve1.service + + EXTRA_DIST += \ +- units/systemd-resolved.service.in ++ units/systemd-resolved.service.m4.in + + SYSTEM_UNIT_ALIASES += \ + systemd-resolved.service dbus-org.freedesktop.resolve1.service +diff --git a/units/.gitignore b/units/.gitignore +index 638a7abc4..7f3e0d093 100644 +--- a/units/.gitignore ++++ b/units/.gitignore +@@ -58,6 +58,7 @@ + /systemd-reboot.service + /systemd-remount-fs.service + /systemd-resolved.service ++/systemd-resolved.service.m4 + /systemd-hibernate-resume@.service + /systemd-rfkill@.service + /systemd-shutdownd.service +diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.m4.in +similarity index 96% +rename from units/systemd-resolved.service.in +rename to units/systemd-resolved.service.m4.in +index b643da9a7..d133847d5 100644 +--- a/units/systemd-resolved.service.in ++++ b/units/systemd-resolved.service.m4.in +@@ -10,11 +10,13 @@ Description=Network Name Resolution + Documentation=man:systemd-resolved.service(8) + After=systemd-networkd.service network.service + ++m4_ifdef(`ENABLE_KDBUS', + # On kdbus systems we pull in the busname explicitly, because it + # carries policy that allows the daemon to acquire its name. + Wants=org.freedesktop.resolve1.busname + After=org.freedesktop.resolve1.busname + ++)m4_dnl + [Service] + Type=notify + Restart=always diff --git a/SOURCES/0152-man-add-journal-remote.conf-5.patch b/SOURCES/0152-man-add-journal-remote.conf-5.patch new file mode 100644 index 00000000..f4c43f23 --- /dev/null +++ b/SOURCES/0152-man-add-journal-remote.conf-5.patch @@ -0,0 +1,181 @@ +From 825d40b7ccdde8b4b9a5299d6e6747c80b9519e2 Mon Sep 17 00:00:00 2001 +From: Chris Morgan +Date: Sat, 21 Mar 2015 20:47:46 -0400 +Subject: [PATCH] man: add journal-remote.conf(5) + +(cherry picked from commit eaa5251d9167027275d8275862e23e0b7dc8866e) + +Cherry-picked from: 90d2614 +Resolves: #1222517 +--- + Makefile-man.am | 7 +++ + man/journal-remote.conf.xml | 114 +++++++++++++++++++++++++++++++++++++++++ + man/systemd-journal-remote.xml | 1 + + 3 files changed, 122 insertions(+) + create mode 100644 man/journal-remote.conf.xml + +diff --git a/Makefile-man.am b/Makefile-man.am +index ac6f69af7..084df754a 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -1358,14 +1358,20 @@ endif + + if HAVE_MICROHTTPD + MANPAGES += \ ++ man/journal-remote.conf.5 \ + man/systemd-journal-gatewayd.service.8 \ + man/systemd-journal-remote.8 \ + man/systemd-journal-upload.8 + MANPAGES_ALIAS += \ ++ man/journal-remote.conf.d.5 \ + man/systemd-journal-gatewayd.8 \ + man/systemd-journal-gatewayd.socket.8 ++man/journal-remote.conf.d.5: man/journal-remote.conf.5 + man/systemd-journal-gatewayd.8: man/systemd-journal-gatewayd.service.8 + man/systemd-journal-gatewayd.socket.8: man/systemd-journal-gatewayd.service.8 ++man/journal-remote.conf.d.html: man/journal-remote.conf.html ++ $(html-alias) ++ + man/systemd-journal-gatewayd.html: man/systemd-journal-gatewayd.service.html + $(html-alias) + +@@ -1662,6 +1668,7 @@ EXTRA_DIST += \ + man/hostname.xml \ + man/hostnamectl.xml \ + man/hwdb.xml \ ++ man/journal-remote.conf.xml \ + man/journalctl.xml \ + man/journald.conf.xml \ + man/kernel-command-line.xml \ +diff --git a/man/journal-remote.conf.xml b/man/journal-remote.conf.xml +new file mode 100644 +index 000000000..a7b222718 +--- /dev/null ++++ b/man/journal-remote.conf.xml +@@ -0,0 +1,114 @@ ++ ++ ++ ++ ++ ++ ++ ++ journal-remote.conf ++ systemd ++ ++ ++ ++ Developer ++ Chris ++ Morgan ++ chmorgan@gmail.com ++ ++ ++ ++ ++ ++ journal-remote.conf ++ 5 ++ ++ ++ ++ journal-remote.conf ++ journal-remote.conf.d ++ Journal remote service configuration files ++ ++ ++ ++ /etc/systemd/journal-remote.conf ++ /etc/systemd/journald.conf.d/*.conf ++ /run/systemd/journald.conf.d/*.conf ++ /usr/lib/systemd/journald.conf.d/*.conf ++ ++ ++ ++ Description ++ ++ These files configure various parameters of the systemd-remote-journal ++ application, ++ systemd-journal-remote8. ++ ++ ++ ++ ++ ++ Options ++ ++ All options are configured in the ++ [Remote] section: ++ ++ ++ ++ ++ SplitMode= ++ ++ One of host or none. ++ ++ ++ ++ ++ ServerKeyFile= ++ ++ SSL key in PEM format ++ ++ ++ ++ ServerCertificateFile= ++ ++ SSL CA certificate in PEM format. ++ ++ ++ ++ TrustedCertificateFile= ++ ++ SSL CA certificate. ++ ++ ++ ++ ++ ++ ++ ++ See Also ++ ++ systemd-journal-remote1, ++ systemd1, ++ systemd-journald.service8 ++ ++ ++ ++ +diff --git a/man/systemd-journal-remote.xml b/man/systemd-journal-remote.xml +index 2687662a1..d5bda635c 100644 +--- a/man/systemd-journal-remote.xml ++++ b/man/systemd-journal-remote.xml +@@ -310,6 +310,7 @@ systemd-journal-remote --url http://some.host:19531/ + journalctl1, + systemd-journald.service8, + systemd-journal-gatewayd.service8 ++ journal-remote.conf5 + + + diff --git a/SOURCES/0153-mount-don-t-run-quotaon-only-for-network-filesystems.patch b/SOURCES/0153-mount-don-t-run-quotaon-only-for-network-filesystems.patch new file mode 100644 index 00000000..8ed9da9a --- /dev/null +++ b/SOURCES/0153-mount-don-t-run-quotaon-only-for-network-filesystems.patch @@ -0,0 +1,32 @@ +From 1ab30e0ea4b78ea20e64dccf729668d18a0fac51 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 30 Mar 2015 14:42:02 +0200 +Subject: [PATCH] mount: don't run quotaon only for network filesystems + +If you have for example ext4 on iscsi devices it is possible to setup +qoutas there. Unfortunately, because such fstab entry contains _netdev, +systemd will not add dependency to quotaon.service. + +(cherry picked from commit 11041c8488e956924870379a9203d7f1cac3b038) + +Cherry-picked from: f66964d +Resolves: #1222517 +--- + src/core/mount.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 3ae0eb462..335922025 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -107,7 +107,9 @@ static bool mount_is_auto(const MountParameters *p) { + static bool needs_quota(const MountParameters *p) { + assert(p); + +- if (mount_is_network(p)) ++ /* Quotas are not enabled on network filesystems, ++ * but we them, for example, on storages connected via iscsi */ ++ if (p->fstype && fstype_is_network(p->fstype)) + return false; + + if (mount_is_bind(p)) diff --git a/SOURCES/0154-mount-fix-up-wording-in-the-comment.patch b/SOURCES/0154-mount-fix-up-wording-in-the-comment.patch new file mode 100644 index 00000000..5eb315c0 --- /dev/null +++ b/SOURCES/0154-mount-fix-up-wording-in-the-comment.patch @@ -0,0 +1,26 @@ +From 07ce9278fbfc06ce14cd16d463788c55442ee163 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 1 Apr 2015 13:08:25 +0200 +Subject: [PATCH] mount: fix up wording in the comment + +(cherry picked from commit 340a1d2330ddc1dd18ad75bcdddf32f63c84b4a1) + +Cherry-picked from: 375af09 +Resolves: #1222517 +--- + src/core/mount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 335922025..fd4fb6f1b 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -108,7 +108,7 @@ static bool needs_quota(const MountParameters *p) { + assert(p); + + /* Quotas are not enabled on network filesystems, +- * but we them, for example, on storages connected via iscsi */ ++ * but we want them, for example, on storage connected via iscsi */ + if (p->fstype && fstype_is_network(p->fstype)) + return false; + diff --git a/SOURCES/0155-udev-net_id-fix-copy-paste-error.patch b/SOURCES/0155-udev-net_id-fix-copy-paste-error.patch new file mode 100644 index 00000000..9c4f603c --- /dev/null +++ b/SOURCES/0155-udev-net_id-fix-copy-paste-error.patch @@ -0,0 +1,28 @@ +From 400756b14b8272138ba27fdac9a3ec1fddeff676 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 1 Apr 2015 16:41:41 +0200 +Subject: [PATCH] udev: net_id - fix copy-paste error + +In case pci_slot overflows we were truncating pci_path instead. + +(cherry picked from commit 16f948cb208f1db9a1665f07ac9b22e416dc19d4) + +Cherry-picked from: 1269e4e +Resolves: #1222517 +--- + src/udev/udev-builtin-net_id.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 2cc1fd409..66474f772 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -271,7 +271,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + if (dev_id > 0) + l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) +- names->pci_path[0] = '\0'; ++ names->pci_slot[0] = '\0'; + } + out: + udev_device_unref(pci); diff --git a/SOURCES/0156-man-don-t-mention-journalctl-dev-sda.patch b/SOURCES/0156-man-don-t-mention-journalctl-dev-sda.patch new file mode 100644 index 00000000..a1fed43b --- /dev/null +++ b/SOURCES/0156-man-don-t-mention-journalctl-dev-sda.patch @@ -0,0 +1,31 @@ +From 3f1ad9b2a6658cd7fc59049d00def3280fd8df5a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Apr 2015 12:14:57 +0200 +Subject: [PATCH] man: don't mention "journalctl /dev/sda" + +It never worked, and nobody ever worked on it, hence don't mention it. + +(cherry picked from commit c4f54721175bde35e2051d61d3d23285def9619d) + +Cherry-picked from: a9a9aa6 +Resolves: #1222517 +--- + man/journalctl.xml | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index 770cf9bb2..08de0ff06 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -817,11 +817,6 @@ + + journalctl /usr/bin/dbus-daemon + +- Show all logs of the kernel device node +- /dev/sda: +- +- journalctl /dev/sda +- + Show all kernel logs from previous boot: + + journalctl -k -b -1 diff --git a/SOURCES/0157-units-move-After-systemd-hwdb-update.service-depende.patch b/SOURCES/0157-units-move-After-systemd-hwdb-update.service-depende.patch new file mode 100644 index 00000000..b4b496f7 --- /dev/null +++ b/SOURCES/0157-units-move-After-systemd-hwdb-update.service-depende.patch @@ -0,0 +1,46 @@ +From 09d583399bf41a61b9b3a96d9eefa51ad4219a6a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Apr 2015 14:27:16 +0200 +Subject: [PATCH] units: move After=systemd-hwdb-update.service dependency from + udev to udev-trigger + +Let's move the hwdb regeneration a bit later. Given that hwdb is +non-essential it should be OK to allow udev to run without it until we +do the full trigger. + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/030074.html +(cherry picked from commit d8f0930eec248c2f54c85aa5029e1b3775c8dc75) + +Cherry-picked from: 84a1e05 +Resolves: #1222517 +--- + units/systemd-udev-trigger.service.in | 2 +- + units/systemd-udevd.service.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/units/systemd-udev-trigger.service.in b/units/systemd-udev-trigger.service.in +index 0c33909ce..1e04d11fe 100644 +--- a/units/systemd-udev-trigger.service.in ++++ b/units/systemd-udev-trigger.service.in +@@ -10,7 +10,7 @@ Description=udev Coldplug all Devices + Documentation=man:udev(7) man:systemd-udevd.service(8) + DefaultDependencies=no + Wants=systemd-udevd.service +-After=systemd-udevd-kernel.socket systemd-udevd-control.socket ++After=systemd-udevd-kernel.socket systemd-udevd-control.socket systemd-hwdb-update.service + Before=sysinit.target + ConditionPathIsReadWrite=/sys + +diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in +index 2791f73ac..a13304400 100644 +--- a/units/systemd-udevd.service.in ++++ b/units/systemd-udevd.service.in +@@ -10,7 +10,7 @@ Description=udev Kernel Device Manager + Documentation=man:systemd-udevd.service(8) man:udev(7) + DefaultDependencies=no + Wants=systemd-udevd-control.socket systemd-udevd-kernel.socket +-After=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-hwdb-update.service systemd-sysusers.service ++After=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-sysusers.service + Before=sysinit.target + ConditionPathIsReadWrite=/sys + diff --git a/SOURCES/0158-units-explicitly-order-systemd-user-sessions.service.patch b/SOURCES/0158-units-explicitly-order-systemd-user-sessions.service.patch new file mode 100644 index 00000000..2b46fc83 --- /dev/null +++ b/SOURCES/0158-units-explicitly-order-systemd-user-sessions.service.patch @@ -0,0 +1,29 @@ +From d7087b71c5b31bae35cb32a4b87e83d578a2d694 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Apr 2015 14:31:35 +0200 +Subject: [PATCH] units: explicitly order systemd-user-sessions.service after + nss-user-lookup.target + +We should not allow logins before NIS/LDAP users are available. + +(cherry picked from commit efb3e19be9c568974b221990b9e84fb5304c5537) + +Cherry-picked from: 6446de5 +Resolves: #1222517 +--- + units/systemd-user-sessions.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/systemd-user-sessions.service.in b/units/systemd-user-sessions.service.in +index 0869e7399..c09c05d4d 100644 +--- a/units/systemd-user-sessions.service.in ++++ b/units/systemd-user-sessions.service.in +@@ -8,7 +8,7 @@ + [Unit] + Description=Permit User Sessions + Documentation=man:systemd-user-sessions.service(8) +-After=remote-fs.target ++After=remote-fs.target nss-user-lookup.target + + [Service] + Type=oneshot diff --git a/SOURCES/0159-zsh-completion-update-loginctl.patch b/SOURCES/0159-zsh-completion-update-loginctl.patch new file mode 100644 index 00000000..63511f1b --- /dev/null +++ b/SOURCES/0159-zsh-completion-update-loginctl.patch @@ -0,0 +1,31 @@ +From caa80561b4acad9d66747ff6eb2b499ea67139e9 Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Tue, 7 Apr 2015 19:35:13 +0200 +Subject: [PATCH] zsh-completion: update loginctl + +(cherry picked from commit 8470025541039f39391815b2ac93952003b7eee8) + +Cherry-picked from: def740b +Resolves: #1222517 +--- + shell-completion/zsh/_loginctl | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/shell-completion/zsh/_loginctl b/shell-completion/zsh/_loginctl +index 0de66e191..bd33b66fa 100644 +--- a/shell-completion/zsh/_loginctl ++++ b/shell-completion/zsh/_loginctl +@@ -102,10 +102,11 @@ _arguments -s \ + '--kill-who=[Who to send signal to]:killwho:(main control all)' \ + {-s+,--signal=}'[Which signal to send]:signal:_signals' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ +- {-M+,--machine=}'[Operate on local container]:machine' \ +- {-P,--privileged}'[Acquire privileges before execution]' \ ++ {-M+,--machine=}'[Operate on local container]:machine:_sd_machines' \ + {-l,--full}'[Do not ellipsize output]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-legend[Do not show the headers and footers]' \ + '--no-ask-password[Do not ask for system passwords]' \ ++ {-n+,--lines=}'[Number of journal entries to show]' \ ++ {-o+,--output=}'[Change journal output mode]:output modes:_sd_outputmodes' \ + '*::loginctl command:_loginctl_command' diff --git a/SOURCES/0160-zsh-completion-add-missing-M-completion-for-journalc.patch b/SOURCES/0160-zsh-completion-add-missing-M-completion-for-journalc.patch new file mode 100644 index 00000000..4236c61b --- /dev/null +++ b/SOURCES/0160-zsh-completion-add-missing-M-completion-for-journalc.patch @@ -0,0 +1,25 @@ +From 6cc26ef0b749f56f184faacde210c6674ab83cf4 Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Tue, 7 Apr 2015 19:35:57 +0200 +Subject: [PATCH] zsh-completion: add missing -M completion for journalctl + +(cherry picked from commit b178d279d92fdf002b18dd2f06f2353af14d0a6e) + +Cherry-picked from: 6ff6bbf +Resolves: #1222517 +--- + shell-completion/zsh/_journalctl | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl +index a469bbc9a..863348e05 100644 +--- a/shell-completion/zsh/_journalctl ++++ b/shell-completion/zsh/_journalctl +@@ -76,6 +76,7 @@ _arguments -s \ + {-F,--field=}'[List all values a certain field takes]:Fields:_list_fields' \ + '--system[Show system and kernel messages]' \ + '--user[Show messages from user services]' \ ++ {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \ + {-D+,--directory=}'[Show journal files from directory]:directories:_directories' \ + '--file=[Operate on specified journal files]:file:_files' \ + '--root=[Operate on catalog hierarchy under specified directory]:directories:_directories' \ diff --git a/SOURCES/0161-zsh-completion-update-hostnamectl.patch b/SOURCES/0161-zsh-completion-update-hostnamectl.patch new file mode 100644 index 00000000..2aa0b866 --- /dev/null +++ b/SOURCES/0161-zsh-completion-update-hostnamectl.patch @@ -0,0 +1,48 @@ +From 2cfba1646374d8d10431d0bd647b734ad4f59a49 Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Tue, 7 Apr 2015 20:14:28 +0200 +Subject: [PATCH] zsh-completion: update hostnamectl + +(cherry picked from commit d67b1f525f488e5dfc076972cccf2a6411257fb8) + +Cherry-picked from: c5b43a4 +Resolves: #1222517 +--- + shell-completion/zsh/_hostnamectl | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/shell-completion/zsh/_hostnamectl b/shell-completion/zsh/_hostnamectl +index a7217a199..7528e0649 100644 +--- a/shell-completion/zsh/_hostnamectl ++++ b/shell-completion/zsh/_hostnamectl +@@ -33,6 +33,14 @@ _hostnamectl_set-deployment() { + fi + } + ++_hostnamectl_set-location() { ++ if (( CURRENT <= 3 )); then ++ _message "new location" ++ else ++ _message "no more options" ++ fi ++} ++ + _hostnamectl_command() { + local -a _hostnamectl_cmds + _hostnamectl_cmds=( +@@ -40,7 +48,8 @@ _hostnamectl_command() { + "set-hostname:Set system hostname" + "set-icon-name:Set icon name for host" + "set-chassis:Set chassis type for host" +- "set-deployment:Set deployment environment" ++ "set-deployment:Set deployment environment for host" ++ "set-location:Set location for host" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'hostnamectl commands' _hostnamectl_cmds || compadd "$@" +@@ -67,4 +76,5 @@ _arguments -s \ + '--pretty[Only set pretty hostname]' \ + '--no-ask-password[Do not prompt for password]' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ ++ {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \ + '*::hostnamectl commands:_hostnamectl_command' diff --git a/SOURCES/0162-shell-completion-systemctl-switch-root-verb.patch b/SOURCES/0162-shell-completion-systemctl-switch-root-verb.patch new file mode 100644 index 00000000..c83141ef --- /dev/null +++ b/SOURCES/0162-shell-completion-systemctl-switch-root-verb.patch @@ -0,0 +1,53 @@ +From 15e2a6ebee7eab4a9b2ef57082e949ead17cdd85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 2 Apr 2015 22:54:35 -0400 +Subject: [PATCH] shell-completion: systemctl switch-root verb + +The completion is rudimentary (all files). I think this is OK since +this is used so rarely. But not having it proposed at all is annoying. + +(cherry picked from commit 7b742b3130941b5c8d5e178b6694428fb3b61086) + +Cherry-picked from: 166cee1 +Resolves: #1222517 +--- + shell-completion/bash/systemctl.in | 2 +- + shell-completion/zsh/_systemctl.in | 5 +++++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in +index 8063316ec..3d787cdb7 100644 +--- a/shell-completion/bash/systemctl.in ++++ b/shell-completion/bash/systemctl.in +@@ -160,7 +160,7 @@ _systemctl () { + reboot rescue show-environment suspend get-default + is-system-running' + [NAME]='snapshot' +- [FILE]='link' ++ [FILE]='link switch-root' + [TARGETS]='set-default' + ) + +diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in +index 7f2d5ac0f..82edfd3d7 100644 +--- a/shell-completion/zsh/_systemctl.in ++++ b/shell-completion/zsh/_systemctl.in +@@ -59,6 +59,7 @@ + "reboot:Shut down and reboot the system" + "kexec:Shut down and reboot the system with kexec" + "exit:Ask for user instance termination" ++ "switch-root:Change root directory" + ) + + if (( CURRENT == 1 )); then +@@ -297,6 +298,10 @@ done + _sd_unit_files + } + ++(( $+functions[_systemctl_switch-root] )) || _systemctl_switch-root() { ++ _files ++} ++ + # no systemctl completion for: + # [STANDALONE]='daemon-reexec daemon-reload default + # emergency exit halt kexec list-jobs list-units diff --git a/SOURCES/0163-core-automount-beef-up-error-message.patch b/SOURCES/0163-core-automount-beef-up-error-message.patch new file mode 100644 index 00000000..19a415de --- /dev/null +++ b/SOURCES/0163-core-automount-beef-up-error-message.patch @@ -0,0 +1,29 @@ +From 64b6bcb807fdafc3609ab0019b3d8e9186fed632 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 2 Apr 2015 22:58:39 -0400 +Subject: [PATCH] core/automount: beef up error message + +This should not happen... but when it does more information is nice. + +(cherry picked from commit 50b03c8ea1248f2d35a9042a3fa959adc0ceb819) + +Cherry-picked from: 5670709 +Resolves: #1222517 +--- + src/core/automount.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index e4c79415d..b391f6198 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -734,7 +734,8 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo + assert(fd == a->pipe_fd); + + if (events != EPOLLIN) { +- log_unit_error(UNIT(a)->id, "Got invalid poll event on pipe."); ++ log_unit_error(UNIT(a)->id, "%s: got invalid poll event %"PRIu32" on pipe (fd=%d)", ++ UNIT(a)->id, events, fd); + goto fail; + } + diff --git a/SOURCES/0164-man-remove-fs-from-rootfsflags.patch b/SOURCES/0164-man-remove-fs-from-rootfsflags.patch new file mode 100644 index 00000000..e95be723 --- /dev/null +++ b/SOURCES/0164-man-remove-fs-from-rootfsflags.patch @@ -0,0 +1,28 @@ +From 3231718bd58d86cc52da68d72fabf0cef48aebbd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Apr 2015 08:28:21 -0400 +Subject: [PATCH] man: remove 'fs' from 'rootfsflags' + +rootfsflags does not appear anywhere else. + +(cherry picked from commit d6a12e7ca3a17ce0224fd6c95d827e4f97fe2c9a) + +Cherry-picked from: 589a5b6 +Resolves: #1222517 +--- + man/kernel-command-line.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml +index 919bd1374..eb7372702 100644 +--- a/man/kernel-command-line.xml ++++ b/man/kernel-command-line.xml +@@ -295,7 +295,7 @@ + + root= + rootfstype= +- rootfsflags= ++ rootflags= + ro + rw + diff --git a/SOURCES/0165-shared-fix-memleak.patch b/SOURCES/0165-shared-fix-memleak.patch new file mode 100644 index 00000000..87de1562 --- /dev/null +++ b/SOURCES/0165-shared-fix-memleak.patch @@ -0,0 +1,56 @@ +From 60cf5a261b6b521b92801447aeace9c63a282ddc Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Fri, 10 Apr 2015 15:44:02 +0200 +Subject: [PATCH] shared: fix memleak + +path was used for 2 purposes but it was not freed before being reused. + +(cherry picked from commit 0d67448869bd881fd6aea57de6da98800395cf1f) + +Cherry-picked from: 146ec8e +Resolves: #1222517 +--- + src/shared/install.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 92b8d6e8e..efd489ec0 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -515,7 +515,7 @@ static int find_symlinks_in_scope( + UnitFileState *state) { + + int r; +- _cleanup_free_ char *path = NULL; ++ _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL; + bool same_name_link_runtime = false, same_name_link = false; + + assert(scope >= 0); +@@ -523,11 +523,11 @@ static int find_symlinks_in_scope( + assert(name); + + /* First look in runtime config path */ +- r = get_config_path(scope, true, root_dir, &path); ++ r = get_config_path(scope, true, root_dir, &normal_path); + if (r < 0) + return r; + +- r = find_symlinks(name, path, &same_name_link_runtime); ++ r = find_symlinks(name, normal_path, &same_name_link_runtime); + if (r < 0) + return r; + else if (r > 0) { +@@ -536,11 +536,11 @@ static int find_symlinks_in_scope( + } + + /* Then look in the normal config path */ +- r = get_config_path(scope, false, root_dir, &path); ++ r = get_config_path(scope, false, root_dir, &runtime_path); + if (r < 0) + return r; + +- r = find_symlinks(name, path, &same_name_link); ++ r = find_symlinks(name, runtime_path, &same_name_link); + if (r < 0) + return r; + else if (r > 0) { diff --git a/SOURCES/0166-udevd-fix-synchronization-with-settle-when-handling-.patch b/SOURCES/0166-udevd-fix-synchronization-with-settle-when-handling-.patch new file mode 100644 index 00000000..6bbc7958 --- /dev/null +++ b/SOURCES/0166-udevd-fix-synchronization-with-settle-when-handling-.patch @@ -0,0 +1,70 @@ +From e55efa99fd829a4699aae6505e02fae7b50a40bc Mon Sep 17 00:00:00 2001 +From: Daniel Drake +Date: Mon, 6 Apr 2015 16:03:43 -0600 +Subject: [PATCH] udevd: fix synchronization with settle when handling inotify + events + +udev uses inotify to implement a scheme where when the user closes +a writable device node, a change uevent is forcefully generated. +In the case of block devices, it actually requests a partition rescan. + +This currently can't be synchronized with "udevadm settle", i.e. this +is not reliable in a script: + + sfdisk --change-id /dev/sda 1 81 + udevadm settle + mount /dev/sda1 /foo + +The settle call doesn't synchronize there, so at the same time we try +to mount the device, udevd is busy removing the partition device nodes and +readding them again. The mount call often happens in that moment where the +partition node has been removed but not readded yet. + +This exact issue was fixed long ago: +http://git.kernel.org/cgit/linux/hotplug/udev.git/commit/?id=bb38678e3ccc02bcd970ccde3d8166a40edf92d3 + +but that fix is no longer valid now that sequence numbers are no longer +used. + +Fix this by forcing another mainloop iteration after handling inotify events +before unblocking settle. If the inotify event caused us to generate a +"change" event, we'll pick that up in the following loop iteration, before +we reach the end of the loop where we respond to settle's control message, +unblocking it. + +(cherry picked from commit 07ba8037bf2a2d6a683fa107ee6f2b9545fca23e) + +Cherry-picked from: 7a2e024 +Resolves: #1222517 +--- + src/udev/udevd.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index e98c1fd6d..87a3f69e9 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1502,9 +1502,22 @@ int main(int argc, char *argv[]) { + continue; + + /* device node watch */ +- if (is_inotify) ++ if (is_inotify) { + handle_inotify(udev); + ++ /* ++ * settle might be waiting on us to determine the queue ++ * state. If we just handled an inotify event, we might have ++ * generated a "change" event, but we won't have queued up ++ * the resultant uevent yet. ++ * ++ * Before we go ahead and potentially tell settle that the ++ * queue is empty, lets loop one more time to update the ++ * queue state again before deciding. ++ */ ++ continue; ++ } ++ + /* tell settle that we are busy or idle, this needs to be before the + * PING handling + */ diff --git a/SOURCES/0167-python-systemd-fix-is_socket_inet-to-cope-with-ports.patch b/SOURCES/0167-python-systemd-fix-is_socket_inet-to-cope-with-ports.patch new file mode 100644 index 00000000..e92f9e32 --- /dev/null +++ b/SOURCES/0167-python-systemd-fix-is_socket_inet-to-cope-with-ports.patch @@ -0,0 +1,42 @@ +From bac3b41f700542d3944a2e95c7cee1681f2936f4 Mon Sep 17 00:00:00 2001 +From: Simon Farnsworth +Date: Wed, 25 Mar 2015 17:00:09 +0000 +Subject: [PATCH] python-systemd: fix is_socket_inet to cope with ports + +Just a couple of trivial oversights. + +(cherry picked from commit 9f1a574d50c1ffd19f18805cc8a3a433c4f2da37) + +Cherry-picked from: 81b3dd9 +Resolves: #1222517 +--- + src/python-systemd/_daemon.c | 2 +- + src/python-systemd/daemon.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/python-systemd/_daemon.c b/src/python-systemd/_daemon.c +index 65cfec7ce..7c5f1b2bb 100644 +--- a/src/python-systemd/_daemon.c ++++ b/src/python-systemd/_daemon.c +@@ -225,7 +225,7 @@ static PyObject* is_socket_inet(PyObject *self, PyObject *args) { + &fd, &family, &type, &listening, &port)) + return NULL; + +- if (port < 0 || port > INT16_MAX) { ++ if (port < 0 || port > UINT16_MAX) { + set_error(-EINVAL, NULL, "port must fit into uint16_t"); + return NULL; + } +diff --git a/src/python-systemd/daemon.py b/src/python-systemd/daemon.py +index 1c386bb6f..82011ca60 100644 +--- a/src/python-systemd/daemon.py ++++ b/src/python-systemd/daemon.py +@@ -26,7 +26,7 @@ def is_socket(fileobj, family=_AF_UNSPEC, type=0, listening=-1): + + def is_socket_inet(fileobj, family=_AF_UNSPEC, type=0, listening=-1, port=0): + fd = _convert_fileobj(fileobj) +- return _is_socket_inet(fd, family, type, listening) ++ return _is_socket_inet(fd, family, type, listening, port) + + def is_socket_unix(fileobj, type=0, listening=-1, path=None): + fd = _convert_fileobj(fileobj) diff --git a/SOURCES/0168-man-fix-examples-indentation-in-tmpfiles.d-5.patch b/SOURCES/0168-man-fix-examples-indentation-in-tmpfiles.d-5.patch new file mode 100644 index 00000000..d0c9c0e5 --- /dev/null +++ b/SOURCES/0168-man-fix-examples-indentation-in-tmpfiles.d-5.patch @@ -0,0 +1,36 @@ +From fc3494e5b171b36621b7bc95ba65ee4b58789283 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 13 Apr 2015 15:23:07 +0200 +Subject: [PATCH] man: fix examples indentation in tmpfiles.d(5) + +(cherry picked from commit bd1100898d63e9e2d8f6327b6895454f9abd5bd0) + +Cherry-picked from: c784558 +Resolves: #1222517 +--- + man/tmpfiles.d.xml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml +index 4bd0fcf75..9b4e11c1b 100644 +--- a/man/tmpfiles.d.xml ++++ b/man/tmpfiles.d.xml +@@ -504,15 +504,15 @@ + boot with specific modes and ownership. + + d /run/screens 1777 root root 10d +- d /run/uscreens 0755 root root 10d12h +- t /run/screen - - - - user.name="John Smith" security.SMACK64=screen ++d /run/uscreens 0755 root root 10d12h ++t /run/screen - - - - user.name="John Smith" security.SMACK64=screen + + + /etc/tmpfiles.d/abrt.conf example + abrt needs a directory created at boot with specific mode and ownership and its content should be preserved. + + d /var/tmp/abrt 0755 abrt abrt +- x /var/tmp/abrt/* ++x /var/tmp/abrt/* + + + diff --git a/SOURCES/0169-systemctl-avoid-bumping-NOFILE-rlimit-unless-needed.patch b/SOURCES/0169-systemctl-avoid-bumping-NOFILE-rlimit-unless-needed.patch new file mode 100644 index 00000000..1346a64c --- /dev/null +++ b/SOURCES/0169-systemctl-avoid-bumping-NOFILE-rlimit-unless-needed.patch @@ -0,0 +1,46 @@ +From f98f6ed9a27871cd2ce505b977ba8c2390e104b6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 14 Apr 2015 20:47:20 -0500 +Subject: [PATCH] systemctl: avoid bumping NOFILE rlimit unless needed + +We actually only use the journal when showing status. Move setrlimit call +so it is only called for status. + +https://bugzilla.redhat.com/show_bug.cgi?id=1184712 +(cherry picked from commit 40acc203c043fd419f3c045dc6f116c3a28411d8) + +Cherry-picked from: e87fa61 +Resolves: #1222517 +--- + src/systemctl/systemctl.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 4ec0cff21..089c25f83 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4449,6 +4449,12 @@ static int show(sd_bus *bus, char **args) { + if (show_properties) + pager_open_if_enabled(); + ++ if (show_status) ++ /* Increase max number of open files to 16K if we can, we ++ * might needs this when browsing journal files, which might ++ * be split up into many files. */ ++ setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); ++ + /* If no argument is specified inspect the manager itself */ + + if (show_properties && strv_length(args) <= 1) +@@ -7207,11 +7213,6 @@ found: + } + } + +- /* Increase max number of open files to 16K if we can, we +- * might needs this when browsing journal files, which might +- * be split up into many files. */ +- setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); +- + return verb->dispatch(bus, argv + optind); + } + diff --git a/SOURCES/0170-exit-status-Fix-NOTINSSTALLED-typo.patch b/SOURCES/0170-exit-status-Fix-NOTINSSTALLED-typo.patch new file mode 100644 index 00000000..c57af311 --- /dev/null +++ b/SOURCES/0170-exit-status-Fix-NOTINSSTALLED-typo.patch @@ -0,0 +1,26 @@ +From 1eef7cbf1ab594fe00c83044763d41a0b29be6c6 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Sat, 18 Apr 2015 22:38:13 +0100 +Subject: [PATCH] exit-status: Fix "NOTINSSTALLED" typo + +(cherry picked from commit 9f8f87e375175536a972feab79c2ff8901c47f8e) + +Cherry-picked from: 02e0056 +Resolves: #1222517 +--- + src/shared/exit-status.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c +index 5c73b4d3c..90c83a47a 100644 +--- a/src/shared/exit-status.c ++++ b/src/shared/exit-status.c +@@ -167,7 +167,7 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { + return "NOPERMISSION"; + + case EXIT_NOTINSTALLED: +- return "NOTINSSTALLED"; ++ return "NOTINSTALLED"; + + case EXIT_NOTCONFIGURED: + return "NOTCONFIGURED"; diff --git a/SOURCES/0171-tmpfiles-there-s-no-systemd-forbid-user-logins.servi.patch b/SOURCES/0171-tmpfiles-there-s-no-systemd-forbid-user-logins.servi.patch new file mode 100644 index 00000000..6d9c2266 --- /dev/null +++ b/SOURCES/0171-tmpfiles-there-s-no-systemd-forbid-user-logins.servi.patch @@ -0,0 +1,27 @@ +From 0756d902734c3d4353264d1b4c2ccec87359bd4a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 21 Apr 2015 17:26:56 +0200 +Subject: [PATCH] tmpfiles: there's no systemd-forbid-user-logins.service + service + +(cherry picked from commit 451d691ae110a600497348d9f6288bc84efb8642) + +Cherry-picked from: 0d2b365 +Resolves: #1222517 +--- + tmpfiles.d/systemd-nologin.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tmpfiles.d/systemd-nologin.conf b/tmpfiles.d/systemd-nologin.conf +index d61232b53..a30a8da60 100644 +--- a/tmpfiles.d/systemd-nologin.conf ++++ b/tmpfiles.d/systemd-nologin.conf +@@ -5,7 +5,7 @@ + # the Free Software Foundation; either version 2.1 of the License, or + # (at your option) any later version. + +-# See tmpfiles.d(5) and systemd-forbid-user-logins.service(5). ++# See tmpfiles.d(5), systemd-user-session.service(5) and pam_nologin(8). + # This file has special suffix so it is not run by mistake. + + F! /run/nologin 0644 - - - "System is booting up. See pam_nologin(8)" diff --git a/SOURCES/0172-kmod-setup-load-ip_tables-kmod-at-boot.patch b/SOURCES/0172-kmod-setup-load-ip_tables-kmod-at-boot.patch new file mode 100644 index 00000000..a2eaebd3 --- /dev/null +++ b/SOURCES/0172-kmod-setup-load-ip_tables-kmod-at-boot.patch @@ -0,0 +1,49 @@ +From 6df5513d294ae368f2a09fb47917e11048347885 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 22 Apr 2015 13:50:56 +0200 +Subject: [PATCH] kmod-setup: load ip_tables kmod at boot + +The module is currently no auto-loadable (and this is unlikely to change +anytime soon, given it's API is via getsockopt/setsockopt). It is needed +by networkd and nspawn currently. + +Users who really don't like the module to be loaded have the option to +blacklist it still, or not compile it at all. But for all others this +should make things work out-of-the-box. + +(cherry picked from commit 1d3087978a8ee23107cb64aa55ca97aefe9531e2) + +Cherry-picked from: f801bf8 +Resolves: #1222517 +--- + src/core/kmod-setup.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c +index c0a05b97a..97f3b9b34 100644 +--- a/src/core/kmod-setup.c ++++ b/src/core/kmod-setup.c +@@ -63,16 +63,19 @@ int kmod_setup(void) { + bool (*condition_fn)(void); + } kmod_table[] = { + /* auto-loading on use doesn't work before udev is up */ +- { "autofs4", "/sys/class/misc/autofs", true, NULL }, ++ { "autofs4", "/sys/class/misc/autofs", true, NULL }, + + /* early configure of ::1 on the loopback device */ +- { "ipv6", "/sys/module/ipv6", true, NULL }, ++ { "ipv6", "/sys/module/ipv6", true, NULL }, + + /* this should never be a module */ +- { "unix", "/proc/net/unix", true, NULL }, ++ { "unix", "/proc/net/unix", true, NULL }, + + /* IPC is needed before we bring up any other services */ +- { "kdbus", "/sys/fs/kdbus", false, cmdline_check_kdbus }, ++ { "kdbus", "/sys/fs/kdbus", false, cmdline_check_kdbus }, ++ ++ /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */ ++ { "ip_tables", "/proc/net/ip_tables_names", false, NULL }, + }; + struct kmod_ctx *ctx = NULL; + unsigned int i; diff --git a/SOURCES/0173-util-Fix-assertion-in-split-on-missing.patch b/SOURCES/0173-util-Fix-assertion-in-split-on-missing.patch new file mode 100644 index 00000000..732df71b --- /dev/null +++ b/SOURCES/0173-util-Fix-assertion-in-split-on-missing.patch @@ -0,0 +1,81 @@ +From 030a063371f4f4fd0d4366ebd3cebfa9930773da Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Wed, 22 Apr 2015 23:09:43 +0100 +Subject: [PATCH] util: Fix assertion in split() on missing ' + +When parsing a unit with a trailing slash after an escaped line break, like + + ExecStart=/bin/echo 'foo \ + bar' + +the split() function (through config_parse()) asserted and crashed pid 1: + + Assertion 'current[*l + 1] == quotechars[0]' failed at ../src/shared/util.c:583, function split(). Aborting. + +Fix this by returning an error in this case ("trailing garbage"). + +Add corresponding test case. Also fix the missing "unit" argument of +config_parse_exec() in the comment. + +https://launchpad.net/bugs/1447243 +(cherry picked from commit 470dca63cd2b1579f45f72b6b9777494abeff105) + +Cherry-picked from: 8f93633 +Resolves: #1222517 +--- + src/shared/util.c | 3 +-- + src/test/test-unit-file.c | 15 +++++++++++++++ + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 1e1bf944f..649344d88 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -571,13 +571,12 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo + char quotechars[2] = {*current, '\0'}; + + *l = strcspn_escaped(current + 1, quotechars); +- if (current[*l + 1] == '\0' || ++ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || + (current[*l + 2] && !strchr(separator, current[*l + 2]))) { + /* right quote missing or garbage at the end */ + *state = current; + return NULL; + } +- assert(current[*l + 1] == quotechars[0]); + *state = current++ + *l + 2; + } else if (quoted) { + *l = strcspn_escaped(current, separator); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index e517f571d..9f3e3a227 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -92,6 +92,7 @@ static void check_execcommand(ExecCommand *c, + + static void test_config_parse_exec(void) { + /* int config_parse_exec( ++ const char *unit, + const char *filename, + unsigned line, + const char *section, +@@ -303,6 +304,20 @@ static void test_config_parse_exec(void) { + assert_se(r == 0); + assert_se(c1->command_next == NULL); + ++ log_info("/* missing ending ' */"); ++ r = config_parse_exec(NULL, "fake", 4, "section", 1, ++ "LValue", 0, "/path 'foo", ++ &c, NULL); ++ assert_se(r == 0); ++ assert_se(c1->command_next == NULL); ++ ++ log_info("/* missing ending ' with trailing backslash */"); ++ r = config_parse_exec(NULL, "fake", 4, "section", 1, ++ "LValue", 0, "/path 'foo\\", ++ &c, NULL); ++ assert_se(r == 0); ++ assert_se(c1->command_next == NULL); ++ + exec_command_free_list(c); + } + diff --git a/SOURCES/0174-units-set-KillMode-mixed-for-our-daemons-that-fork-w.patch b/SOURCES/0174-units-set-KillMode-mixed-for-our-daemons-that-fork-w.patch new file mode 100644 index 00000000..a9e12860 --- /dev/null +++ b/SOURCES/0174-units-set-KillMode-mixed-for-our-daemons-that-fork-w.patch @@ -0,0 +1,37 @@ +From b0204b37bd8275f95885548277acf5bda383173d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Apr 2015 16:12:28 +0200 +Subject: [PATCH] units: set KillMode=mixed for our daemons that fork worker + processes + +The daemons should really have the time to kill the workers first, +before systemd does it, hence use KillMode=mixed for these daemons. + +https://bugs.freedesktop.org/show_bug.cgi?id=90051 +(cherry picked from commit 658f26b828fdd7007cfe82d794f610525b21cb99) + +Cherry-picked from: 7396ceb +Resolves: #1222517 +--- + units/systemd-importd.service.in | 1 + + units/systemd-udevd.service.in | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/units/systemd-importd.service.in b/units/systemd-importd.service.in +index 26759ea0f..5534a49ed 100644 +--- a/units/systemd-importd.service.in ++++ b/units/systemd-importd.service.in +@@ -18,3 +18,4 @@ WatchdogSec=1min + PrivateTmp=yes + ProtectSystem=full + ProtectHome=yes ++KillMode=mixed +diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in +index a13304400..32f04d901 100644 +--- a/units/systemd-udevd.service.in ++++ b/units/systemd-udevd.service.in +@@ -22,3 +22,4 @@ Restart=always + RestartSec=0 + ExecStart=@rootlibexecdir@/systemd-udevd + MountFlags=slave ++KillMode=mixed diff --git a/SOURCES/0175-unit-don-t-add-automatic-dependencies-on-device-unit.patch b/SOURCES/0175-unit-don-t-add-automatic-dependencies-on-device-unit.patch new file mode 100644 index 00000000..e257d611 --- /dev/null +++ b/SOURCES/0175-unit-don-t-add-automatic-dependencies-on-device-unit.patch @@ -0,0 +1,41 @@ +From 33cca921994d30abfb03ce0f681c6fc58f5c0703 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Apr 2015 17:28:06 +0200 +Subject: [PATCH] unit: don't add automatic dependencies on device units if + they aren't supported + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/031187.html +(cherry picked from commit 47bc12e1ba35d38edda737dae232088d6d3ae688) + +Cherry-picked from: c20cdaa +Resolves: #1222517 +--- + src/core/unit.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 565455bd6..b9e1f13ea 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2830,14 +2830,18 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { + + assert(u); + +- if (!what) +- return 0; +- + /* Adds in links to the device node that this unit is based on */ ++ if (isempty(what)) ++ return 0; + + if (!is_device_path(what)) + return 0; + ++ /* When device units aren't supported (such as in a ++ * container), don't create dependencies on them. */ ++ if (unit_vtable[UNIT_DEVICE]->supported && !unit_vtable[UNIT_DEVICE]->supported(u->manager)) ++ return 0; ++ + e = unit_name_from_path(what, ".device"); + if (!e) + return -ENOMEM; diff --git a/SOURCES/0176-update-done-ignore-nanosecond-file-timestamp-compone.patch b/SOURCES/0176-update-done-ignore-nanosecond-file-timestamp-compone.patch new file mode 100644 index 00000000..5d04190d --- /dev/null +++ b/SOURCES/0176-update-done-ignore-nanosecond-file-timestamp-compone.patch @@ -0,0 +1,38 @@ +From 6503fbef433da29fe1f450e44c8eaca61888bcda Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 27 Apr 2015 17:25:57 +0200 +Subject: [PATCH] update-done: ignore nanosecond file timestamp components, + they are not reliable + +https://bugs.freedesktop.org/show_bug.cgi?id=90192 +(cherry picked from commit 329c542585cd92cb905990e3bf59eda16fd88cfb) + +Cherry-picked from: a38a3e0 +Resolves: #1222517 +--- + src/update-done/update-done.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c +index 561963e5e..cb5cd6f4a 100644 +--- a/src/update-done/update-done.c ++++ b/src/update-done/update-done.c +@@ -36,9 +36,15 @@ static int apply_timestamp(const char *path, struct timespec *ts) { + assert(ts); + + if (stat(path, &st) >= 0) { +- /* Is the timestamp file already newer than the OS? If so, there's nothing to do. */ +- if (st.st_mtim.tv_sec > ts->tv_sec || +- (st.st_mtim.tv_sec == ts->tv_sec && st.st_mtim.tv_nsec >= ts->tv_nsec)) ++ /* Is the timestamp file already newer than the OS? If ++ * so, there's nothing to do. We ignore the nanosecond ++ * component of the timestamp, since some file systems ++ * do not support any better accuracy than 1s and we ++ * have no way to identify the accuracy ++ * available. Most notably ext4 on small disks (where ++ * 128 byte inodes are used) does not support better ++ * accuracy than 1s. */ ++ if (st.st_mtim.tv_sec > ts->tv_sec) + return 0; + + /* It is older? Then let's update it */ diff --git a/SOURCES/0177-sd-daemon-simplify-sd_pid_notify_with_fds.patch b/SOURCES/0177-sd-daemon-simplify-sd_pid_notify_with_fds.patch new file mode 100644 index 00000000..a61fbe39 --- /dev/null +++ b/SOURCES/0177-sd-daemon-simplify-sd_pid_notify_with_fds.patch @@ -0,0 +1,119 @@ +From f065b88b17bd569dda412b2e6f34d921f7badb79 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 13 Mar 2015 21:22:05 -0500 +Subject: [PATCH] sd-daemon: simplify sd_pid_notify_with_fds + +Coverity was complaining that CMSG_NXTHDR is used without +checking the return value. In this case it cannot fail, but +it is a good excuse to simplify the function a bit. + +CID #1261726. + +(cherry picked from commit 64144440a5d2d94482f882b992fd2a4e0dca7a05) + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/031348.html + +Cherry-picked from: c1258d6 +Resolves: #1222517 +--- + src/libsystemd/sd-daemon/sd-daemon.c | 61 ++++++++++++++++-------------------- + 1 file changed, 27 insertions(+), 34 deletions(-) + +diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c +index 22a3a5347..1474321c9 100644 +--- a/src/libsystemd/sd-daemon/sd-daemon.c ++++ b/src/libsystemd/sd-daemon/sd-daemon.c +@@ -352,12 +352,10 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char + .msg_iovlen = 1, + .msg_name = &sockaddr, + }; +- struct cmsghdr *control; + _cleanup_close_ int fd = -1; + struct cmsghdr *cmsg = NULL; + const char *e; +- size_t controllen_without_ucred = 0; +- bool try_without_ucred = false; ++ bool have_pid; + int r; + + if (!state) { +@@ -396,42 +394,37 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char + if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) + msghdr.msg_namelen = sizeof(struct sockaddr_un); + +- control = alloca(CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * n_fds)); ++ have_pid = pid != 0 && pid != getpid(); + +- if (n_fds > 0) { +- msghdr.msg_control = control; +- msghdr.msg_controllen = CMSG_LEN(sizeof(int) * n_fds); ++ if (n_fds > 0 || have_pid) { ++ msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) + ++ CMSG_SPACE(sizeof(struct ucred) * have_pid); ++ msghdr.msg_control = alloca(msghdr.msg_controllen); + + cmsg = CMSG_FIRSTHDR(&msghdr); +- cmsg->cmsg_level = SOL_SOCKET; +- cmsg->cmsg_type = SCM_RIGHTS; +- cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds); ++ if (n_fds > 0) { ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds); + +- memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds); +- } +- +- if (pid != 0 && pid != getpid()) { +- struct ucred *ucred; +- +- try_without_ucred = true; +- controllen_without_ucred = msghdr.msg_controllen; ++ memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds); + +- msghdr.msg_control = control; +- msghdr.msg_controllen += CMSG_LEN(sizeof(struct ucred)); ++ if (have_pid) ++ assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg)); ++ } + +- if (cmsg) +- cmsg = CMSG_NXTHDR(&msghdr, cmsg); +- else +- cmsg = CMSG_FIRSTHDR(&msghdr); ++ if (have_pid) { ++ struct ucred *ucred; + +- cmsg->cmsg_level = SOL_SOCKET; +- cmsg->cmsg_type = SCM_CREDENTIALS; +- cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_CREDENTIALS; ++ cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + +- ucred = (struct ucred*) CMSG_DATA(cmsg); +- ucred->pid = pid; +- ucred->uid = getuid(); +- ucred->gid = getgid(); ++ ucred = (struct ucred*) CMSG_DATA(cmsg); ++ ucred->pid = pid; ++ ucred->uid = getuid(); ++ ucred->gid = getgid(); ++ } + } + + /* First try with fake ucred data, as requested */ +@@ -441,10 +434,10 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char + } + + /* If that failed, try with our own ucred instead */ +- if (try_without_ucred) { +- if (controllen_without_ucred <= 0) ++ if (have_pid) { ++ msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred)); ++ if (msghdr.msg_controllen == 0) + msghdr.msg_control = NULL; +- msghdr.msg_controllen = controllen_without_ucred; + + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) { + r = 1; diff --git a/SOURCES/0178-fstab-generator-add-x-systemd.requires-and-x-systemd.patch b/SOURCES/0178-fstab-generator-add-x-systemd.requires-and-x-systemd.patch new file mode 100644 index 00000000..eb64610b --- /dev/null +++ b/SOURCES/0178-fstab-generator-add-x-systemd.requires-and-x-systemd.patch @@ -0,0 +1,248 @@ +From 8f149756435998d009a8edc7206c5de038e5cbf1 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 18 May 2015 12:30:37 +0200 +Subject: [PATCH] fstab-generator: add x-systemd.requires and + x-systemd.requires-mounts-for + +Currently we have no way how to specify dependencies between fstab +entries (or another units) in the /etc/fstab. It means that users are +forced to bypass fstab and write .mount units manually. + +The patch introduces new systemd fstab options: + +x-systemd.requires= + + - to specify dependence an another mount (PATH is translated to unit name) + +x-systemd.requires= + + - to specify dependence on arbitrary UNIT + +x-systemd.requires-mounts-for= + + - to specify dependence on another paths, implemented by + RequiresMountsFor=. The option may be specified more than once. + +For example two bind mounts where B depends on A: + + /mnt/test/A /mnt/test/A none bind,defaults + /mnt/test/A /mnt/test/B none bind,x-systemd.requires=/mnt/test/A + +More complex example with overlay FS where one mount point depends on +"low" and "upper" directories: + + /dev/sdc1 /mnt/low ext4 defaults + /dev/sdc2 /mnt/high ext4 defaults + overlay /mnt/merged overlay lowerdir=/mnt/low,upperdir=/mnt/high/data,workdir=/mnt/high/work,x-systemd.requires-mounts-for=/mnt/low,x-systemd.requires-mounts-for=mnt/high + +https://bugzilla.redhat.com/show_bug.cgi?id=812826 +https://bugzilla.redhat.com/show_bug.cgi?id=1164334 + +Conflicts: + src/fstab-generator/fstab-generator.c + +Cherry-picked from: 3519d230c8bafe834b2dac26ace49fcfba139823 +Resolves: #1164334 +--- + man/systemd.mount.xml | 30 ++++++++++++++ + src/fstab-generator/fstab-generator.c | 76 +++++++++++++++++++++++++++++++++++ + src/shared/fstab-util.c | 30 ++++++++++++++ + src/shared/fstab-util.h | 2 + + 4 files changed, 138 insertions(+) + +diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml +index fcb9a4416..8e652e133 100644 +--- a/man/systemd.mount.xml ++++ b/man/systemd.mount.xml +@@ -138,6 +138,36 @@ + + + ++ ++ ++ ++ Configures a Requires= and ++ an After= dependency between the created ++ mount unit and another systemd unit, such as a device or mount ++ unit. The argument should be a unit name, or an absolute path ++ to a device node or mount point. This option may be specified ++ more than once. This option is particularly useful for mount ++ point declarations that need an additional device to be around ++ (such as an external journal device for journal file systems) ++ or an additional mount to be in place (such as an overlay file ++ system that merges multiple mount points). See ++ After= and Requires= in ++ systemd.unit5 ++ for details. ++ ++ ++ ++ ++ ++ Configures a ++ RequiresMountsFor= dependency between the ++ created mount unit and other mount units. The argument must be ++ an absolute path. This option may be specified more than once. ++ See RequiresMountsFor= in ++ systemd.unit5 ++ for details. ++ ++ + + + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 8e2f522bd..65ed20579 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -155,6 +155,64 @@ static bool mount_in_initrd(struct mntent *me) { + streq(me->mnt_dir, "/usr"); + } + ++static int write_requires_after(FILE *f, const char *opts) { ++ _cleanup_strv_free_ char **names = NULL, **units = NULL; ++ _cleanup_free_ char *res = NULL; ++ char **s; ++ int r; ++ ++ assert(f); ++ assert(opts); ++ ++ r = fstab_extract_values(opts, "x-systemd.requires", &names); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to parse options: %m"); ++ if (r == 0) ++ return 0; ++ ++ STRV_FOREACH(s, names) { ++ char *x; ++ ++ x = unit_name_mangle_with_suffix(*s, MANGLE_NOGLOB, ".mount"); ++ if (!x) ++ return log_error_errno(r, "Failed to generate unit name: %m"); ++ r = strv_consume(&units, x); ++ if (r < 0) ++ return log_oom(); ++ } ++ ++ if (units) { ++ res = strv_join(units, " "); ++ if (!res) ++ return log_oom(); ++ fprintf(f, "After=%1$s\nRequires=%1$s\n", res); ++ } ++ ++ return 0; ++} ++ ++static int write_requires_mounts_for(FILE *f, const char *opts) { ++ _cleanup_strv_free_ char **paths = NULL; ++ _cleanup_free_ char *res = NULL; ++ int r; ++ ++ assert(f); ++ assert(opts); ++ ++ r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to parse options: %m"); ++ if (r == 0) ++ return 0; ++ ++ res = strv_join(paths, " "); ++ if (!res) ++ return log_oom(); ++ ++ fprintf(f, "RequiresMountsFor=%s\n", res); ++ ++ return 0; ++} + static int add_mount( + const char *what, + const char *where, +@@ -225,6 +283,15 @@ static int add_mount( + if (post && !noauto && !nofail && !automount) + fprintf(f, "Before=%s\n", post); + ++ if (!automount && opts) { ++ r = write_requires_after(f, opts); ++ if (r < 0) ++ return r; ++ r = write_requires_mounts_for(f, opts); ++ if (r < 0) ++ return r; ++ } ++ + if (passno != 0) { + r = generator_write_fsck_deps(f, arg_dest, what, where, fstype); + if (r < 0) +@@ -289,6 +356,15 @@ static int add_mount( + "Before=%s\n", + post); + ++ if (opts) { ++ r = write_requires_after(f, opts); ++ if (r < 0) ++ return r; ++ r = write_requires_mounts_for(f, opts); ++ if (r < 0) ++ return r; ++ } ++ + fprintf(f, + "[Automount]\n" + "Where=%s\n", +diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c +index cf317e17b..e231a0ff8 100644 +--- a/src/shared/fstab-util.c ++++ b/src/shared/fstab-util.c +@@ -125,6 +125,36 @@ answer: + return !!n; + } + ++int fstab_extract_values(const char *opts, const char *name, char ***values) { ++ _cleanup_strv_free_ char **optsv = NULL, **res = NULL; ++ char **s; ++ ++ assert(opts); ++ assert(name); ++ assert(values); ++ ++ optsv = strv_split(opts, ","); ++ if (!optsv) ++ return -ENOMEM; ++ ++ STRV_FOREACH(s, optsv) { ++ char *arg; ++ int r; ++ ++ arg = startswith(*s, name); ++ if (!arg || *arg != '=') ++ continue; ++ r = strv_extend(&res, arg + 1); ++ if (r < 0) ++ return r; ++ } ++ ++ *values = res; ++ res = NULL; ++ ++ return !!*values; ++} ++ + int fstab_find_pri(const char *options, int *ret) { + _cleanup_free_ char *opt = NULL; + int r; +diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h +index 9f6b32eaf..387c562a9 100644 +--- a/src/shared/fstab-util.h ++++ b/src/shared/fstab-util.h +@@ -28,6 +28,8 @@ + int fstab_filter_options(const char *opts, const char *names, + const char **namefound, char **value, char **filtered); + ++int fstab_extract_values(const char *opts, const char *name, char ***values); ++ + static inline bool fstab_test_option(const char *opts, const char *names) { + return !!fstab_filter_options(opts, names, NULL, NULL, NULL); + } diff --git a/SOURCES/0179-core-Fix-assertion-with-empty-Exec-paths.patch b/SOURCES/0179-core-Fix-assertion-with-empty-Exec-paths.patch new file mode 100644 index 00000000..472092e9 --- /dev/null +++ b/SOURCES/0179-core-Fix-assertion-with-empty-Exec-paths.patch @@ -0,0 +1,78 @@ +From 9ea44466541480b583032617e6060313f79a6bda Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Thu, 14 May 2015 09:06:40 +0200 +Subject: [PATCH] core: Fix assertion with empty Exec*= paths + +An Exec*= line with whitespace after modifiers, like + + ExecStart=- /bin/true + +is considered to have an empty command path. This is as specified, but causes +systemd to crash with + + Assertion 'skip < l' failed at ../src/core/load-fragment.c:607, function config_parse_exec(). Aborting. + Aborted (core dumped) + +Fix this by logging an error instead and ignoring the invalid line. + +Add corresponding test cases. Also add a test case for a completely empty value +which resets the command list. + +https://launchpad.net/bugs/1454173 + +Cherry-picked from: 35b1078e1c375df244e19961792aeb78ca34bb54 +Resolves: #1222517 +--- + src/core/load-fragment.c | 6 +++++- + src/test/test-unit-file.c | 21 +++++++++++++++++++++ + 2 files changed, 26 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index f17a82fcd..ec4cf4eef 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -604,7 +604,11 @@ int config_parse_exec(const char *unit, + skip = separate_argv0 + ignore; + + /* skip special chars in the beginning */ +- assert(skip < l); ++ if (l <= skip) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Empty path in command line, ignoring: %s", rvalue); ++ r = 0; ++ goto fail; ++ } + + } else if (strneq(word, ";", MAX(l, 1U))) + /* new commandline */ +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 9f3e3a227..550098332 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -318,6 +318,27 @@ static void test_config_parse_exec(void) { + assert_se(r == 0); + assert_se(c1->command_next == NULL); + ++ log_info("/* invalid space between modifiers */"); ++ r = config_parse_exec(NULL, "fake", 4, "section", 1, ++ "LValue", 0, "- /path", ++ &c, NULL); ++ assert_se(r == 0); ++ assert_se(c1->command_next == NULL); ++ ++ log_info("/* only modifiers, no path */"); ++ r = config_parse_exec(NULL, "fake", 4, "section", 1, ++ "LValue", 0, "-", ++ &c, NULL); ++ assert_se(r == 0); ++ assert_se(c1->command_next == NULL); ++ ++ log_info("/* empty argument, reset */"); ++ r = config_parse_exec(NULL, "fake", 4, "section", 1, ++ "LValue", 0, "", ++ &c, NULL); ++ assert_se(r == 0); ++ assert_se(c == NULL); ++ + exec_command_free_list(c); + } + diff --git a/SOURCES/0180-rules-load-sg-module.patch b/SOURCES/0180-rules-load-sg-module.patch new file mode 100644 index 00000000..75f58352 --- /dev/null +++ b/SOURCES/0180-rules-load-sg-module.patch @@ -0,0 +1,24 @@ +From 50a7827f7376d31d2af2dc563fc51d8ad71f48dc Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 20 May 2015 12:34:18 +0200 +Subject: [PATCH] rules: load sg module + +Revert of 09637f743414e2c36d6c5b032d77d76dbeb86b31 +RHEL-only + +Resolves: #1186462 +--- + rules/40-redhat.rules | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 556a3a3a9..305e75228 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -8,3 +8,6 @@ SUBSYSTEM=="memory", ACTION=="add", ATTR{state}=="offline", ATTR{state}="online" + + # reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded + ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge" ++ ++# load SCSI generic (sg) driver ++SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST!="[module/sg]", RUN+="/sbin/modprobe -bv sg" diff --git a/SOURCES/0181-util-add-shell_maybe_quote-call-for-preparing-a-stri.patch b/SOURCES/0181-util-add-shell_maybe_quote-call-for-preparing-a-stri.patch new file mode 100644 index 00000000..6ab4c61c --- /dev/null +++ b/SOURCES/0181-util-add-shell_maybe_quote-call-for-preparing-a-stri.patch @@ -0,0 +1,191 @@ +From 32b4631e74262e02094c6402d39d1e4264442037 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 9 Apr 2015 18:32:21 +0200 +Subject: [PATCH] util: add shell_maybe_quote() call for preparing a string for + shell cmdline inclusion + +If necessary the passed string is enclosed in "", and all special +characters escapes. + +This also ports over usage in bus-util.c and job.c to use this, instead +of a incorrect local implementation that forgets to properly escape. + +Conflicts: + src/shared/util.c + src/shared/util.h + +Cherry-picked from: 019c7fba +Resolves: #1016680 +--- + src/core/job.c | 8 +++---- + src/libsystemd/sd-bus/bus-util.c | 15 +++++++------- + src/shared/util.c | 45 ++++++++++++++++++++++++++++++++++++++-- + src/shared/util.h | 2 ++ + src/test/test-util.c | 19 +++++++++++++++++ + 5 files changed, 74 insertions(+), 15 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 4740ff18c..7416386a1 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -679,15 +679,13 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { + break; + + case JOB_FAILED: { +- bool quotes; ++ _cleanup_free_ char *quoted = NULL; + +- quotes = chars_intersect(u->id, SHELL_NEED_QUOTES); ++ quoted = shell_maybe_quote(u->id); + + manager_flip_auto_status(u->manager, true); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format); +- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, +- "See \"systemctl status %s%s%s\" for details.", +- quotes ? "'" : "", u->id, quotes ? "'" : ""); ++ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted)); + break; + } + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 52d4ebe61..b0a5a7592 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1709,16 +1709,15 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) { + else if (streq(d->result, "unsupported")) + log_error("Operation on or unit type of %s not supported on this system.", strna(d->name)); + else if (!streq(d->result, "done") && !streq(d->result, "skipped")) { +- if (d->name) { +- bool quotes; ++ _cleanup_free_ char *quoted = NULL; + +- quotes = chars_intersect(d->name, SHELL_NEED_QUOTES); ++ if (d->name) ++ quoted = shell_maybe_quote(d->name); + +- log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.", +- d->name, +- quotes ? "'" : "", d->name, quotes ? "'" : ""); +- } else +- log_error("Job failed. See \"journalctl -xe\" for details."); ++ if (quoted) ++ log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xe' for details.", d->name, quoted); ++ else ++ log_error("Job failed. See 'journalctl -xe' for details."); + } + } + +diff --git a/src/shared/util.c b/src/shared/util.c +index 649344d88..778c2b0e0 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -1329,7 +1329,8 @@ char *cescape(const char *s) { + + assert(s); + +- /* Does C style string escaping. */ ++ /* Does C style string escaping. May be be reversed with ++ * cunescape(). */ + + r = new(char, strlen(s)*4 + 1); + if (!r) +@@ -1493,7 +1494,7 @@ char *xescape(const char *s, const char *bad) { + + /* Escapes all chars in bad, in addition to \ and all special + * chars, in \xFF style escaping. May be reversed with +- * cunescape. */ ++ * cunescape(). */ + + r = new(char, strlen(s) * 4 + 1); + if (!r) +@@ -8101,3 +8102,43 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k + + return -1; + } ++ ++char *shell_maybe_quote(const char *s) { ++ const char *p; ++ char *r, *t; ++ ++ assert(s); ++ ++ /* Encloses a string in double quotes if necessary to make it ++ * OK as shell string. */ ++ ++ for (p = s; *p; p++) ++ if (*p <= ' ' || ++ *p >= 127 || ++ strchr(SHELL_NEED_QUOTES, *p)) ++ break; ++ ++ if (!*p) ++ return strdup(s); ++ ++ r = new(char, 1+strlen(s)*2+1+1); ++ if (!r) ++ return NULL; ++ ++ t = r; ++ *(t++) = '"'; ++ t = mempcpy(t, s, p - s); ++ ++ for (; *p; p++) { ++ ++ if (strchr(SHELL_NEED_ESCAPE, *p)) ++ *(t++) = '\\'; ++ ++ *(t++) = *p; ++ } ++ ++ *(t++)= '"'; ++ *t = 0; ++ ++ return r; ++} +diff --git a/src/shared/util.h b/src/shared/util.h +index a83b58822..7ecfd8571 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -1078,3 +1078,5 @@ void sigkill_wait(pid_t *pid); + #define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait) + + int syslog_parse_priority(const char **p, int *priority, bool with_facility); ++ ++char *shell_maybe_quote(const char *s); +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 9515a8cbf..9ae347b43 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -1512,6 +1512,24 @@ static void test_sparse_write(void) { + test_sparse_write_one(fd, test_e, sizeof(test_e)); + } + ++static void test_shell_maybe_quote_one(const char *s, const char *expected) { ++ _cleanup_free_ char *r; ++ ++ assert_se(r = shell_maybe_quote(s)); ++ assert_se(streq(r, expected)); ++} ++ ++static void test_shell_maybe_quote(void) { ++ ++ test_shell_maybe_quote_one("", ""); ++ test_shell_maybe_quote_one("\\", "\"\\\\\""); ++ test_shell_maybe_quote_one("\"", "\"\\\"\""); ++ test_shell_maybe_quote_one("foobar", "foobar"); ++ test_shell_maybe_quote_one("foo bar", "\"foo bar\""); ++ test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\""); ++ test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); ++} ++ + int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); +@@ -1589,6 +1607,7 @@ int main(int argc, char *argv[]) { + test_same_fd(); + test_uid_ptr(); + test_sparse_write(); ++ test_shell_maybe_quote(); + + return 0; + } diff --git a/SOURCES/0182-bus-util-be-more-verbose-if-dbus-job-fails.patch b/SOURCES/0182-bus-util-be-more-verbose-if-dbus-job-fails.patch new file mode 100644 index 00000000..5738cf07 --- /dev/null +++ b/SOURCES/0182-bus-util-be-more-verbose-if-dbus-job-fails.patch @@ -0,0 +1,123 @@ +From 8946c35e525c2a14b12ed425f11af152e37d8583 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 10 Apr 2015 15:56:52 +0200 +Subject: [PATCH] bus-util: be more verbose if dbus job fails + +Users might have hard time figuring out why exactly their systemctl request +failed. If dbus job fails try to figure out more details about failure by +examining Result property of the service. + +https://bugzilla.redhat.com/show_bug.cgi?id=1016680 + +Cherry-picked from: d5cad22109749faffb7563e4b2a3a728486d47b5 +Resolves: #1016680 +--- + src/libsystemd/sd-bus/bus-util.c | 79 ++++++++++++++++++++++++++++++++++++---- + 1 file changed, 72 insertions(+), 7 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index b0a5a7592..2e6d88962 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -30,6 +30,7 @@ + #include "path-util.h" + #include "missing.h" + #include "set.h" ++#include "unit-name.h" + + #include "sd-bus.h" + #include "bus-error.h" +@@ -1690,6 +1691,68 @@ static int bus_process_wait(sd_bus *bus) { + } + } + ++static int bus_job_get_service_result(BusWaitForJobs *d, char **result) { ++ _cleanup_free_ char *dbus_path = NULL; ++ ++ assert(d); ++ assert(d->name); ++ assert(result); ++ ++ dbus_path = unit_dbus_path_from_name(d->name); ++ if (!dbus_path) ++ return -ENOMEM; ++ ++ return sd_bus_get_property_string(d->bus, ++ "org.freedesktop.systemd1", ++ dbus_path, ++ "org.freedesktop.systemd1.Service", ++ "Result", ++ NULL, ++ result); ++} ++ ++static const struct { ++ const char *result, *explanation; ++} explanations [] = { ++ { "resources", "configured resource limit was exceeded" }, ++ { "timeout", "timeout was exceeded" }, ++ { "exit-code", "control process exited with error code" }, ++ { "signal", "fatal signal was delivered to the control process" }, ++ { "core-dump", "fatal signal was delivered to the control process. Core dumped" }, ++ { "watchdog", "service failed to send watchdog ping" }, ++ { "start-limit", "start of the service was attempted too often too quickly" } ++}; ++ ++static void log_job_error_with_service_result(const char* service, const char *result) { ++ unsigned i; ++ _cleanup_free_ char *service_shell_quoted = NULL; ++ ++ assert(service); ++ assert(result); ++ ++ service_shell_quoted = shell_maybe_quote(service); ++ ++ for (i = 0; i < ELEMENTSOF(explanations); ++i) ++ if (streq(result, explanations[i].result)) ++ break; ++ ++ if (i < ELEMENTSOF(explanations)) ++ log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", ++ service, ++ explanations[i].explanation, ++ strna(service_shell_quoted)); ++ else ++ log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", ++ service, ++ strna(service_shell_quoted)); ++ ++ /* For some results maybe additional explanation is required */ ++ if (streq_ptr(result, "start-limit")) ++ log_info("To force a start please invoke \"systemctl reset-failed %s\" followed by \"systemctl start %s\" again.", ++ strna(service_shell_quoted), ++ strna(service_shell_quoted)); ++} ++ + static int check_wait_response(BusWaitForJobs *d, bool quiet) { + int r = 0; + +@@ -1709,15 +1772,17 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) { + else if (streq(d->result, "unsupported")) + log_error("Operation on or unit type of %s not supported on this system.", strna(d->name)); + else if (!streq(d->result, "done") && !streq(d->result, "skipped")) { +- _cleanup_free_ char *quoted = NULL; ++ if (d->name) { ++ int q; ++ _cleanup_free_ char *result = NULL; + +- if (d->name) +- quoted = shell_maybe_quote(d->name); ++ q = bus_job_get_service_result(d, &result); ++ if (q < 0) ++ log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name); + +- if (quoted) +- log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xe' for details.", d->name, quoted); +- else +- log_error("Job failed. See 'journalctl -xe' for details."); ++ log_job_error_with_service_result(d->name, result); ++ } else ++ log_error("Job failed. See \"journalctl -xe\" for details."); + } + } + diff --git a/SOURCES/0183-notify-fix-badly-backported-help-message.patch b/SOURCES/0183-notify-fix-badly-backported-help-message.patch new file mode 100644 index 00000000..cbb7045a --- /dev/null +++ b/SOURCES/0183-notify-fix-badly-backported-help-message.patch @@ -0,0 +1,25 @@ +From 1d23db320710dc4391f6e77ddb32122f83ab8c66 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 29 May 2015 14:12:36 +0200 +Subject: [PATCH] notify: fix badly backported help message + +rhel-only + +Related: #1199644 +--- + src/notify/notify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/notify/notify.c b/src/notify/notify.c +index e4a128b0b..c89a6cc06 100644 +--- a/src/notify/notify.c ++++ b/src/notify/notify.c +@@ -49,7 +49,7 @@ static void help(void) { + " --ready Inform the init system about service start-up completion\n" + " --pid[=PID] Set main pid of daemon\n" + " --status=TEXT Set status text\n" +- " --booted Check if the system was booted up with systemd\n", ++ " --booted Check if the system was booted up with systemd\n" + " --readahead=ACTION Controls read-ahead operations\n", + program_invocation_short_name); + } diff --git a/SOURCES/0184-cryptsetup-craft-a-unique-ID-with-the-source-device.patch b/SOURCES/0184-cryptsetup-craft-a-unique-ID-with-the-source-device.patch new file mode 100644 index 00000000..7a423b1b --- /dev/null +++ b/SOURCES/0184-cryptsetup-craft-a-unique-ID-with-the-source-device.patch @@ -0,0 +1,166 @@ +From 6c45bdd261e027ea78eabb81feaa70f3774bcf2f Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Mon, 1 Jun 2015 17:26:27 +0200 +Subject: [PATCH] cryptsetup: craft a unique ID with the source device + +If cryptsetup is called with a source device as argv[3], then craft the +ID for the password agent with a unique device path. + +If possible "/dev/block/:" is used, otherwise the original +argv[3] is used. + +This enables password agents like petera [1] to provide a password +according to the source device. The original ID did not carry enough +information and was more targeted for a human readable string, which +is specified in the "Message" field anyway. + +With this patch the ID of the ask.XXX ini file looks like this: +ID=cryptsetup:/dev/block/: + +[1] https://github.com/npmccallum/petera + +Cherry-picked from: e51b9486d1b59e72c293028fed1384f4e4ef09aa +Resolves: #1226333 +--- + src/cryptsetup/cryptsetup.c | 90 +++++++++++++++++++++++++++++---------------- + 1 file changed, 58 insertions(+), 32 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index 3f613d9b6..5dedb073e 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -217,6 +217,23 @@ 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[] = +@@ -278,20 +295,55 @@ static char *disk_mount_point(const char *label) { + return NULL; + } + +-static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) { +- int r; ++static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***passwords) { ++ int r = 0; + char **p; + _cleanup_free_ char *text = NULL; + _cleanup_free_ char *escaped_name = NULL; + char *id; ++ const char *name = NULL; ++ _cleanup_free_ char *description = NULL, *name_buffer = NULL, ++ *mount_point = NULL, *maj_min = NULL; + +- assert(name); ++ assert(vol); ++ assert(src); + assert(passwords); + ++ description = disk_description(src); ++ mount_point = disk_mount_point(vol); ++ ++ if (description && streq(vol, description)) { ++ /* If the description string is simply the ++ * volume name, then let's not show this ++ * twice */ ++ free(description); ++ description = NULL; ++ } ++ ++ if (mount_point && description) ++ r = asprintf(&name_buffer, "%s (%s) on %s", description, vol, mount_point); ++ else if (mount_point) ++ r = asprintf(&name_buffer, "%s on %s", vol, mount_point); ++ else if (description) ++ r = asprintf(&name_buffer, "%s (%s)", description, vol); ++ ++ if (r < 0) ++ return log_oom(); ++ ++ name = name_buffer ? name_buffer : vol; ++ + if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) + return log_oom(); + +- escaped_name = cescape(name); ++ if (src) ++ (void) disk_major_minor(src, &maj_min); ++ ++ if (maj_min) { ++ escaped_name = maj_min; ++ maj_min = NULL; ++ } else ++ escaped_name = cescape(name); ++ + if (!escaped_name) + return log_oom(); + +@@ -532,8 +584,7 @@ int main(int argc, char *argv[]) { + unsigned tries; + usec_t until; + crypt_status_info status; +- const char *key_file = NULL, *name = NULL; +- _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL; ++ const char *key_file = NULL; + + /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */ + +@@ -561,31 +612,6 @@ int main(int argc, char *argv[]) { + /* A delicious drop of snake oil */ + mlockall(MCL_FUTURE); + +- description = disk_description(argv[3]); +- mount_point = disk_mount_point(argv[2]); +- +- if (description && streq(argv[2], description)) { +- /* If the description string is simply the +- * volume name, then let's not show this +- * twice */ +- free(description); +- description = NULL; +- } +- +- k = 0; +- if (mount_point && description) +- k = asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point); +- else if (mount_point) +- k = asprintf(&name_buffer, "%s on %s", argv[2], mount_point); +- else if (description) +- k = asprintf(&name_buffer, "%s (%s)", description, argv[2]); +- +- if (k < 0) { +- log_oom(); +- goto finish; +- } +- name = name_buffer ? name_buffer : argv[2]; +- + if (arg_header) { + log_debug("LUKS header: %s", arg_header); + k = crypt_init(&cd, arg_header); +@@ -632,7 +658,7 @@ int main(int argc, char *argv[]) { + _cleanup_strv_free_ char **passwords = NULL; + + if (!key_file) { +- k = get_password(name, until, tries == 0 && !arg_verify, &passwords); ++ k = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords); + if (k == -EAGAIN) + continue; + else if (k < 0) diff --git a/SOURCES/0185-systemctl-introduce-now-for-enable-disable-and-mask.patch b/SOURCES/0185-systemctl-introduce-now-for-enable-disable-and-mask.patch new file mode 100644 index 00000000..a1340c38 --- /dev/null +++ b/SOURCES/0185-systemctl-introduce-now-for-enable-disable-and-mask.patch @@ -0,0 +1,457 @@ +From 65d36d59c936650e141fcbf38b287627fd0ba21a Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 15 May 2015 09:54:10 +0200 +Subject: [PATCH] systemctl: introduce --now for enable, disable and mask + +https://bugs.freedesktop.org/show_bug.cgi?id=42940 + +Conflicts: + src/libsystemd/sd-bus/bus-util.c + src/libsystemd/sd-bus/bus-util.h + src/systemctl/systemctl.c + +Cherry-picked from: 57ab2eabb8f92fad5239c7d4492e9c6e23ee0678 +Resolves: #1233081 +--- + Makefile.am | 1 + + man/systemctl.xml | 33 ++++++++---- + src/libsystemd/sd-bus/bus-util.c | 6 ++- + src/libsystemd/sd-bus/bus-util.h | 3 +- + src/machine/machinectl.c | 2 +- + src/shared/install.c | 112 +++++++++++++++++++-------------------- + src/shared/install.h | 1 + + src/systemctl/systemctl.c | 28 ++++++++-- + 8 files changed, 114 insertions(+), 72 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 604eaf2f1..d3fb398fe 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5253,6 +5253,7 @@ machinectl_LDADD = \ + libsystemd-internal.la \ + libsystemd-logs.la \ + libsystemd-journal-internal.la \ ++ libsystemd-units.la \ + libsystemd-shared.la + + rootbin_PROGRAMS += \ +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 3c4c9cb92..44ec0d7bc 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -455,6 +455,18 @@ + + + ++ ++ ++ ++ ++ When used with enable, the units ++ will also be started. When used with disable or ++ mask, the units will also be stopped. The start ++ or stop operation is only carried out when the respective enable or ++ disable operation has been successful. ++ ++ ++ + + + +@@ -909,11 +921,12 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + the changes are taken into account immediately. Note that + this does not have the effect of also + starting any of the units being enabled. If this +- is desired, a separate start command must +- be invoked for the unit. Also note that in case of instance +- enablement, symlinks named the same as instances are created in +- the install location, however they all point to the same +- template unit file. ++ is desired, either should be used ++ together with this command, or an additional start ++ command must be invoked for the unit. Also note that in case of ++ instance enablement, symlinks named the same as instances ++ are created in the install location, however they all point to the ++ same template unit file. + + This command will print the actions executed. This + output may be suppressed by passing . +@@ -968,9 +981,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + enable. This call implicitly reloads the + systemd daemon configuration after completing the disabling + of the units. Note that this command does not implicitly +- stop the units that are being disabled. If this is desired, +- an additional stop command should be +- executed afterwards. ++ stop the units that are being disabled. If this is desired, either ++ should be used together with this command, or ++ an additional stop command should be executed ++ afterwards. + + This command will print the actions executed. This + output may be suppressed by passing . +@@ -1116,7 +1130,8 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + activation of the unit, including enablement and manual + activation. Use this option with care. This honors the + option to only mask temporarily +- until the next reboot of the system. ++ until the next reboot of the system. The ++ option can be used to ensure that the units are also stopped. + + + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 2e6d88962..fff00d9f9 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1849,7 +1849,7 @@ int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) { + return set_put_strdup(d->jobs, path); + } + +-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) { ++int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) { + const char *type, *path, *source; + int r; + +@@ -1864,6 +1864,10 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) { + else + log_info("Removed symlink %s.", path); + } ++ ++ r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source); ++ if (r < 0) ++ return r; + } + if (r < 0) + return bus_log_parse_error(r); +diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h +index e8a97cef9..21db98228 100644 +--- a/src/libsystemd/sd-bus/bus-util.h ++++ b/src/libsystemd/sd-bus/bus-util.h +@@ -24,6 +24,7 @@ + #include "sd-event.h" + #include "sd-bus.h" + #include "hashmap.h" ++#include "install.h" + #include "time-util.h" + #include "util.h" + +@@ -211,4 +212,4 @@ int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet); + + DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free); + +-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet); ++int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes); +diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c +index 9f8c68b18..f1910709d 100644 +--- a/src/machine/machinectl.c ++++ b/src/machine/machinectl.c +@@ -1709,7 +1709,7 @@ static int enable_machine(int argc, char *argv[], void *userdata) { + return bus_log_parse_error(r); + } + +- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet); ++ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + if (r < 0) + return r; + +diff --git a/src/shared/install.c b/src/shared/install.c +index efd489ec0..b62065be5 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -113,51 +113,6 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d + return 0; + } + +-static int add_file_change( +- UnitFileChange **changes, +- unsigned *n_changes, +- UnitFileChangeType type, +- const char *path, +- const char *source) { +- +- UnitFileChange *c; +- unsigned i; +- +- assert(path); +- assert(!changes == !n_changes); +- +- if (!changes) +- return 0; +- +- c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); +- if (!c) +- return -ENOMEM; +- +- *changes = c; +- i = *n_changes; +- +- c[i].type = type; +- c[i].path = strdup(path); +- if (!c[i].path) +- return -ENOMEM; +- +- path_kill_slashes(c[i].path); +- +- if (source) { +- c[i].source = strdup(source); +- if (!c[i].source) { +- free(c[i].path); +- return -ENOMEM; +- } +- +- path_kill_slashes(c[i].path); +- } else +- c[i].source = NULL; +- +- *n_changes = i+1; +- return 0; +-} +- + static int mark_symlink_for_removal( + Set **remove_symlinks_to, + const char *p) { +@@ -310,7 +265,7 @@ static int remove_marked_symlinks_fd( + + path_kill_slashes(p); + rmdir_parents(p, config_path); +- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); + + if (!set_get(remove_symlinks_to, p)) { + +@@ -597,7 +552,7 @@ int unit_file_mask( + } + + if (symlink("/dev/null", path) >= 0) { +- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); + continue; + } + +@@ -608,8 +563,8 @@ int unit_file_mask( + + if (force) { + if (symlink_atomic("/dev/null", path) >= 0) { +- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); + continue; + } + } +@@ -665,7 +620,7 @@ int unit_file_unmask( + q = -errno; + else { + q = mark_symlink_for_removal(&remove_symlinks_to, path); +- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + } + } + +@@ -747,7 +702,7 @@ int unit_file_link( + return -ENOMEM; + + if (symlink(*i, path) >= 0) { +- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); + continue; + } + +@@ -766,8 +721,8 @@ int unit_file_link( + + if (force) { + if (symlink_atomic(*i, path) >= 0) { +- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); + continue; + } + } +@@ -794,6 +749,51 @@ void unit_file_list_free(Hashmap *h) { + hashmap_free(h); + } + ++int unit_file_changes_add( ++ UnitFileChange **changes, ++ unsigned *n_changes, ++ UnitFileChangeType type, ++ const char *path, ++ const char *source) { ++ ++ UnitFileChange *c; ++ unsigned i; ++ ++ assert(path); ++ assert(!changes == !n_changes); ++ ++ if (!changes) ++ return 0; ++ ++ c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); ++ if (!c) ++ return -ENOMEM; ++ ++ *changes = c; ++ i = *n_changes; ++ ++ c[i].type = type; ++ c[i].path = strdup(path); ++ if (!c[i].path) ++ return -ENOMEM; ++ ++ path_kill_slashes(c[i].path); ++ ++ if (source) { ++ c[i].source = strdup(source); ++ if (!c[i].source) { ++ free(c[i].path); ++ return -ENOMEM; ++ } ++ ++ path_kill_slashes(c[i].path); ++ } else ++ c[i].source = NULL; ++ ++ *n_changes = i+1; ++ return 0; ++} ++ + void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { + unsigned i; + +@@ -1199,7 +1199,7 @@ static int create_symlink( + mkdir_parents_label(new_path, 0755); + + if (symlink(old_path, new_path) >= 0) { +- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); + return 0; + } + +@@ -1220,8 +1220,8 @@ static int create_symlink( + if (r < 0) + return r; + +- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); +- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); + + return 0; + } +diff --git a/src/shared/install.h b/src/shared/install.h +index 3ca39397e..d729e6ed1 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -112,6 +112,7 @@ UnitFileState unit_file_get_state( + int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); + + void unit_file_list_free(Hashmap *h); ++int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source); + void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes); + + int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name); +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 089c25f83..9898694d7 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -138,6 +138,7 @@ static char *arg_host = NULL; + static unsigned arg_lines = 10; + static OutputMode arg_output = OUTPUT_SHORT; + static bool arg_plain = false; ++static bool arg_now = false; + + static bool original_stdout_is_tty; + +@@ -1979,7 +1980,7 @@ static int set_default(sd_bus *bus, char **args) { + return r; + } + +- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet); ++ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + if (r < 0) + return r; + +@@ -5415,7 +5416,7 @@ static int enable_unit(sd_bus *bus, char **args) { + return bus_log_parse_error(r); + } + +- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet); ++ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); + if (r < 0) + return r; + +@@ -5437,6 +5438,18 @@ static int enable_unit(sd_bus *bus, char **args) { + "3) A unit may be started when needed via activation (socket, path, timer,\n" + " D-Bus, udev, scripted systemctl call, ...).\n"); + ++ if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) { ++ char *new_args[n_changes + 2]; ++ unsigned i; ++ ++ new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop"; ++ for (i = 0; i < n_changes; i++) ++ new_args[i + 1] = basename(changes[i].path); ++ new_args[i + 1] = NULL; ++ ++ r = start_unit(bus, new_args); ++ } ++ + finish: + unit_file_changes_free(changes, n_changes); + +@@ -5516,7 +5529,7 @@ static int add_dependency(sd_bus *bus, char **args) { + return r; + } + +- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet); ++ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + if (r < 0) + return r; + +@@ -5582,7 +5595,7 @@ static int preset_all(sd_bus *bus, char **args) { + return r; + } + +- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet); ++ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + if (r < 0) + return r; + +@@ -6058,6 +6071,7 @@ static void systemctl_help(void) { + " When shutting down or sleeping, ignore inhibitors\n" + " --kill-who=WHO Who to send signal to\n" + " -s --signal=SIGNAL Which signal to send\n" ++ " --now Start or stop unit in addition to enabling or disabling it\n" + " -q --quiet Suppress output\n" + " --no-block Do not wait until operation finished\n" + " --no-wall Don't send wall message before halt/power-off/reboot\n" +@@ -6255,6 +6269,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + ARG_STATE, + ARG_JOB_MODE, + ARG_PRESET_MODE, ++ ARG_NOW, + }; + + static const struct option options[] = { +@@ -6297,6 +6312,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + { "state", required_argument, NULL, ARG_STATE }, + { "recursive", no_argument, NULL, 'r' }, + { "preset-mode", required_argument, NULL, ARG_PRESET_MODE }, ++ { "now", no_argument, NULL, ARG_NOW }, + {} + }; + +@@ -6573,6 +6589,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + + break; + ++ case ARG_NOW: ++ arg_now = true; ++ break; ++ + case '?': + return -EINVAL; + diff --git a/SOURCES/0186-udev-also-create-old-sas-paths.patch b/SOURCES/0186-udev-also-create-old-sas-paths.patch new file mode 100644 index 00000000..45ce1f46 --- /dev/null +++ b/SOURCES/0186-udev-also-create-old-sas-paths.patch @@ -0,0 +1,135 @@ +From 956212c9a226d9192e4b3c085e917fe59f6d5cb9 Mon Sep 17 00:00:00 2001 +From: Maurizio Lombardi +Date: Tue, 2 Jun 2015 17:26:25 +0200 +Subject: [PATCH] udev: also create old sas paths + +RHEL-only + +Resolves: #957112 +--- + rules/60-persistent-storage.rules | 2 ++ + src/udev/udev-builtin-path_id.c | 33 ++++++++++++++++++++++++++------- + 2 files changed, 28 insertions(+), 7 deletions(-) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 25b44a55c..71ab97484 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -54,7 +54,9 @@ KERNEL=="mspblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+= + # by-path (parent device path) + ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id" + ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}" ++ENV{DEVTYPE}=="disk", ENV{ID_SAS_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_SAS_PATH}" + ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n" ++ENV{DEVTYPE}=="partition", ENV{ID_SAS_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_SAS_PATH}-part%n" + + # 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" +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index bb0a6242a..025392df5 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -154,7 +154,7 @@ out: + return parent; + } + +-static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path) ++static struct udev_device *handle_scsi_sas(struct udev_device *parent, bool enable_new_sas_path, char **path, bool *new_sas_path) + { + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; +@@ -169,6 +169,8 @@ static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **pa + const char *phy_count; + char *lun = NULL; + ++ *new_sas_path = false; ++ + targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target"); + if (targetdev == NULL) + return NULL; +@@ -201,7 +203,7 @@ static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **pa + } + + /* Check if we are simple disk */ +- if (strncmp(phy_count, "1", 2) != 0) { ++ if (strncmp(phy_count, "1", 2) != 0 || !enable_new_sas_path) { + parent = handle_scsi_sas_wide_port(parent, path); + goto out; + } +@@ -241,6 +243,8 @@ static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **pa + + if (lun) + free(lun); ++ ++ *new_sas_path = true; + out: + udev_device_unref(target_sasdev); + udev_device_unref(expander_sasdev); +@@ -466,7 +470,7 @@ out: + return hostdev; + } + +-static struct udev_device *handle_scsi(struct udev_device *parent, char **path, bool *supported_parent) { ++static struct udev_device *handle_scsi(struct udev_device *parent, bool enable_new_sas_path, char **path, bool *supported_parent, bool *new_sas_path) { + const char *devtype; + const char *name; + const char *id; +@@ -494,7 +498,7 @@ static struct udev_device *handle_scsi(struct udev_device *parent, char **path, + } + + if (strstr(name, "/end_device-") != NULL) { +- parent = handle_scsi_sas(parent, path); ++ parent = handle_scsi_sas(parent, enable_new_sas_path, path, new_sas_path); + *supported_parent = true; + goto out; + } +@@ -610,6 +614,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool + char *path = NULL; + bool supported_transport = false; + bool supported_parent = false; ++ bool new_sas_path = false; ++ bool enable_new_sas_path = true; + + /* S390 ccw bus */ + parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL); +@@ -618,6 +624,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool + goto out; + } + ++restart: ++ ; + /* walk up the chain of devices and compose path */ + parent = dev; + while (parent != NULL) { +@@ -629,7 +637,7 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool + } else if (streq(subsys, "scsi_tape")) { + handle_scsi_tape(parent, &path); + } else if (streq(subsys, "scsi")) { +- parent = handle_scsi(parent, &path, &supported_parent); ++ parent = handle_scsi(parent, enable_new_sas_path, &path, &supported_parent, &new_sas_path); + supported_transport = true; + } else if (streq(subsys, "cciss")) { + parent = handle_cciss(parent, &path); +@@ -721,9 +729,20 @@ out: + i--; + tag[i] = '\0'; + +- udev_builtin_add_property(dev, test, "ID_PATH", path); +- udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag); ++ if (new_sas_path) { ++ udev_builtin_add_property(dev, test, "ID_SAS_PATH", path); ++ } else { ++ udev_builtin_add_property(dev, test, "ID_PATH", path); ++ udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag); ++ } ++ + free(path); ++ ++ if (new_sas_path) { ++ enable_new_sas_path = false; ++ goto restart; ++ } ++ + return EXIT_SUCCESS; + } + return EXIT_FAILURE; diff --git a/SOURCES/0187-journald-do-not-strip-leading-whitespace-from-messag.patch b/SOURCES/0187-journald-do-not-strip-leading-whitespace-from-messag.patch new file mode 100644 index 00000000..b6a12b9c --- /dev/null +++ b/SOURCES/0187-journald-do-not-strip-leading-whitespace-from-messag.patch @@ -0,0 +1,34 @@ +From fa74ba131041161f1ae9fbc0a3b11f9a005b9d8f Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Wed, 10 Jun 2015 22:33:44 -0700 +Subject: [PATCH] journald: do not strip leading whitespace from messages + +Keep leading whitespace for compatibility with older syslog +implementations. Also useful when piping formatted output to the +`logger` command. Keep removing trailing whitespace. + +Tested with `pstree | logger` and checking that the output of +`journalctl | tail` included aligned and formatted output. + +Confirmed that all test cases still pass as expected. + +Cherry-picked from: ec5ff444 +Resolves: #1227396 +--- + src/journal/journald-syslog.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index 7d545ca31..ba80941d7 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -232,7 +232,8 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) + if (t) + *identifier = t; + +- e += strspn(p + e, WHITESPACE); ++ if (strchr(WHITESPACE, p[e])) ++ e++; + *buf = p + e; + return e; + } diff --git a/SOURCES/0188-Revert-core-one-step-back-again-for-nspawn-we-actual.patch b/SOURCES/0188-Revert-core-one-step-back-again-for-nspawn-we-actual.patch new file mode 100644 index 00000000..d5584933 --- /dev/null +++ b/SOURCES/0188-Revert-core-one-step-back-again-for-nspawn-we-actual.patch @@ -0,0 +1,39 @@ +From 647a7761e2fa423c6e1bd6785b043dbe7b525e3c Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 25 Jun 2015 09:20:59 +0200 +Subject: [PATCH] Revert "core: one step back again, for nspawn we actually + can't wait for cgroups running empty since systemd will get exactly zero + notifications about it" + +This reverts commit 743970d2ea6d08aa7c7bff8220f6b7702f2b1db7. + +RHEL-only +https://bugzilla.redhat.com/show_bug.cgi?id=1141137 +https://github.com/systemd/systemd/pull/350 + +Resolves: #1199644 +--- + src/core/unit.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index b9e1f13ea..fa17567dd 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3546,15 +3546,7 @@ int unit_kill_context( + log_unit_warning_errno(u->id, r, "Failed to kill control group: %m"); + } else if (r > 0) { + +- /* FIXME: For now, we will not wait for the +- * cgroup members to die, simply because +- * cgroup notification is unreliable. It +- * doesn't work at all in containers, and +- * outside of containers it can be confused +- * easily by leaving directories in the +- * cgroup. */ +- +- /* wait_for_exit = true; */ ++ wait_for_exit = true; + + if (c->send_sighup && k != KILL_KILL) { + set_free(pid_set); diff --git a/SOURCES/0189-bus-creds-always-set-SD_BUS_CREDS_PID-when-we-set-pi.patch b/SOURCES/0189-bus-creds-always-set-SD_BUS_CREDS_PID-when-we-set-pi.patch new file mode 100644 index 00000000..57550ea9 --- /dev/null +++ b/SOURCES/0189-bus-creds-always-set-SD_BUS_CREDS_PID-when-we-set-pi.patch @@ -0,0 +1,61 @@ +From 0ca06b7178ac205855238941eef7fe981447822a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 24 May 2015 20:20:06 -0400 +Subject: [PATCH] bus-creds: always set SD_BUS_CREDS_PID when we set pid in the + mask + +Also reorder the code a bit to be easier to parse. + +Cherry-picked from: 236f83a +Related: #1230190 +--- + src/core/selinux-access.c | 2 +- + src/libsystemd/sd-bus/bus-creds.c | 17 +++++++---------- + 2 files changed, 8 insertions(+), 11 deletions(-) + +diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c +index 18888747f..ce4f39459 100644 +--- a/src/core/selinux-access.c ++++ b/src/core/selinux-access.c +@@ -240,7 +240,7 @@ int mac_selinux_generic_access_check( + audit_info.path = path; + audit_info.cmdline = cl; + +- r = selinux_check_access((security_context_t) scon, fcon, tclass, permission, &audit_info); ++ r = selinux_check_access(scon, fcon, tclass, permission, &audit_info); + if (r < 0) + r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); + +diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c +index ea8a619c5..5b87fa950 100644 +--- a/src/libsystemd/sd-bus/bus-creds.c ++++ b/src/libsystemd/sd-bus/bus-creds.c +@@ -698,21 +698,18 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { + return 0; + + /* Try to retrieve PID from creds if it wasn't passed to us */ +- if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID)) ++ if (pid > 0) { ++ c->pid = pid; ++ c->mask |= SD_BUS_CREDS_PID; ++ } else if (c->mask & SD_BUS_CREDS_PID) + pid = c->pid; ++ else ++ /* Without pid we cannot do much... */ ++ return 0; + + if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID)) + tid = c->pid; + +- /* Without pid we cannot do much... */ +- if (pid <= 0) +- return 0; +- +- if (pid > 0) { +- c->pid = pid; +- c->mask |= SD_BUS_CREDS_PID; +- } +- + if (tid > 0) { + c->tid = tid; + c->mask |= SD_BUS_CREDS_TID; diff --git a/SOURCES/0190-sd-bus-do-not-use-per-datagram-auxiliary-information.patch b/SOURCES/0190-sd-bus-do-not-use-per-datagram-auxiliary-information.patch new file mode 100644 index 00000000..08e44528 --- /dev/null +++ b/SOURCES/0190-sd-bus-do-not-use-per-datagram-auxiliary-information.patch @@ -0,0 +1,137 @@ +From d0986e46b74de3b131fccbf79bd00de5ff054f71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 6 Jun 2015 18:59:27 -0400 +Subject: [PATCH] sd-bus: do not use per-datagram auxiliary information + +SELinux information cannot be retrieved this way, since we are +using stream unix sockets and SCM_SECURITY does not work for +them. + +SCM_CREDENTIALS use dropped to be consistent. We also should +get this information at connection time. + +https://bugzilla.redhat.com/show_bug.cgi?id=1224211 +"SCM_SECURITY was only added for datagram sockets." + +Cherry-picked from: d868f2a +Related: #1230190 +--- + src/libsystemd/sd-bus/bus-socket.c | 70 +++++++------------------------------- + 1 file changed, 12 insertions(+), 58 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c +index 52883fa8c..abd9ece01 100644 +--- a/src/libsystemd/sd-bus/bus-socket.c ++++ b/src/libsystemd/sd-bus/bus-socket.c +@@ -501,9 +501,7 @@ static int bus_socket_read_auth(sd_bus *b) { + void *p; + union { + struct cmsghdr cmsghdr; +- uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) + +- CMSG_SPACE(sizeof(struct ucred)) + +- CMSG_SPACE(NAME_MAX)]; /*selinux label */ ++ uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)]; + } control; + struct cmsghdr *cmsg; + bool handle_cmsg = false; +@@ -556,8 +554,8 @@ static int bus_socket_read_auth(sd_bus *b) { + + b->rbuffer_size += k; + +- if (handle_cmsg) { +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ if (handle_cmsg) ++ for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int j; +@@ -568,31 +566,9 @@ static int bus_socket_read_auth(sd_bus *b) { + j = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + close_many((int*) CMSG_DATA(cmsg), j); + return -EIO; +- +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_CREDENTIALS && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { +- +- /* Ignore bogus data, which we might +- * get on socketpair() sockets */ +- if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) { +- memcpy(&b->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); +- b->ucred_valid = true; +- } +- +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_SECURITY) { +- +- size_t l; +- +- l = cmsg->cmsg_len - CMSG_LEN(0); +- if (l > 0) { +- memcpy(&b->label, CMSG_DATA(cmsg), l); +- b->label[l] = 0; +- } +- } +- } +- } ++ } else ++ log_debug("Got unexpected auxiliary data with level=%d and type=%d", ++ cmsg->cmsg_level, cmsg->cmsg_type); + + r = bus_socket_auth_verify(b); + if (r != 0) +@@ -945,9 +921,7 @@ int bus_socket_read_message(sd_bus *bus) { + void *b; + union { + struct cmsghdr cmsghdr; +- uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) + +- CMSG_SPACE(sizeof(struct ucred)) + +- CMSG_SPACE(NAME_MAX)]; /*selinux label */ ++ uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)]; + } control; + struct cmsghdr *cmsg; + bool handle_cmsg = false; +@@ -995,8 +969,8 @@ int bus_socket_read_message(sd_bus *bus) { + + bus->rbuffer_size += k; + +- if (handle_cmsg) { +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ if (handle_cmsg) ++ for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int n, *f; +@@ -1021,29 +995,9 @@ int bus_socket_read_message(sd_bus *bus) { + memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + bus->fds = f; + bus->n_fds += n; +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_CREDENTIALS && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { +- +- /* Ignore bogus data, which we might +- * get on socketpair() sockets */ +- if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) { +- memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); +- bus->ucred_valid = true; +- } +- +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_SECURITY) { +- +- size_t l; +- l = cmsg->cmsg_len - CMSG_LEN(0); +- if (l > 0) { +- memcpy(&bus->label, CMSG_DATA(cmsg), l); +- bus->label[l] = 0; +- } +- } +- } +- } ++ } else ++ log_debug("Got unexpected auxiliary data with level=%d and type=%d", ++ cmsg->cmsg_level, cmsg->cmsg_type); + + r = bus_socket_read_message_need(bus, &need); + if (r < 0) diff --git a/SOURCES/0191-sd-bus-store-selinux-context-at-connection-time.patch b/SOURCES/0191-sd-bus-store-selinux-context-at-connection-time.patch new file mode 100644 index 00000000..0574bce7 --- /dev/null +++ b/SOURCES/0191-sd-bus-store-selinux-context-at-connection-time.patch @@ -0,0 +1,94 @@ +From d491fd1068446f74992e76154e5e9d57bd67e7ac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 6 Jun 2015 21:24:45 -0400 +Subject: [PATCH] sd-bus: store selinux context at connection time + +This appears to be the right time to do it for SOCK_STREAM +unix sockets. + +Also: condition bus_get_owner_creds_dbus1 was reversed. Split +it out to a separate variable for clarity and fix. + +https://bugzilla.redhat.com/show_bug.cgi?id=1224211 + +Cherry-picked from: c4e6556 +Related: #1230190 +--- + src/libsystemd/sd-bus/bus-control.c | 6 ++++-- + src/libsystemd/sd-bus/bus-internal.h | 2 +- + src/libsystemd/sd-bus/bus-socket.c | 7 +++++++ + src/libsystemd/sd-bus/sd-bus.c | 1 + + 4 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c +index 06e5b4fd9..8b84b9496 100644 +--- a/src/libsystemd/sd-bus/bus-control.c ++++ b/src/libsystemd/sd-bus/bus-control.c +@@ -945,8 +945,10 @@ static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds ** + _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + pid_t pid = 0; + int r; ++ bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); + +- if (!bus->ucred_valid && !isempty(bus->label)) ++ /* Avoid allocating anything if we have no chance of returning useful data */ ++ if (!bus->ucred_valid && !do_label) + return -ENODATA; + + c = bus_creds_new(); +@@ -970,7 +972,7 @@ static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds ** + } + } + +- if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) { ++ if (do_label) { + c->label = strdup(bus->label); + if (!c->label) + return -ENOMEM; +diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h +index e9f1a816a..071b3da79 100644 +--- a/src/libsystemd/sd-bus/bus-internal.h ++++ b/src/libsystemd/sd-bus/bus-internal.h +@@ -262,7 +262,7 @@ struct sd_bus { + usec_t auth_timeout; + + struct ucred ucred; +- char label[NAME_MAX]; ++ char *label; + + uint64_t creds_mask; + +diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c +index abd9ece01..d00cd014e 100644 +--- a/src/libsystemd/sd-bus/bus-socket.c ++++ b/src/libsystemd/sd-bus/bus-socket.c +@@ -600,10 +600,17 @@ void bus_socket_setup(sd_bus *b) { + } + + static void bus_get_peercred(sd_bus *b) { ++ int r; ++ + assert(b); + + /* Get the peer for socketpair() sockets */ + b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; ++ ++ /* Get the SELinux context of the peer */ ++ r = getpeersec(b->input_fd, &b->label); ++ if (r < 0 && r != -EOPNOTSUPP) ++ log_debug_errno(r, "Failed to determine peer security context: %m"); + } + + static int bus_socket_start_auth_client(sd_bus *b) { +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index cac9b6560..b0a323792 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -121,6 +121,7 @@ static void bus_free(sd_bus *b) { + if (b->kdbus_buffer) + munmap(b->kdbus_buffer, KDBUS_POOL_SIZE); + ++ free(b->label); + free(b->rbuffer); + free(b->unique_name); + free(b->auth_buffer); diff --git a/SOURCES/0192-journald-simplify-context-handling.patch b/SOURCES/0192-journald-simplify-context-handling.patch new file mode 100644 index 00000000..79adcd35 --- /dev/null +++ b/SOURCES/0192-journald-simplify-context-handling.patch @@ -0,0 +1,81 @@ +From da4f4b5c330ad648c9ca9c33e1f0e65148042c12 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 6 Jun 2015 21:36:52 -0400 +Subject: [PATCH] journald: simplify context handling + +By using our homegrown function we can dispense with all the iffdefery. + +Cherry-picked from: 2de56f7 +Related: #1230190 +--- + src/journal/journald-stream.c | 29 ++++++++--------------------- + 1 file changed, 8 insertions(+), 21 deletions(-) + +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 11b852d39..15a554c34 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -57,10 +57,7 @@ struct StdoutStream { + int fd; + + struct ucred ucred; +-#ifdef HAVE_SELINUX +- security_context_t security_context; +-#endif +- ++ char *label; + char *identifier; + char *unit_id; + int priority; +@@ -84,8 +81,7 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { + char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1]; + _cleanup_free_ char *message = NULL, *syslog_identifier = NULL; + unsigned n = 0; +- char *label = NULL; +- size_t label_len = 0; ++ size_t label_len; + + assert(s); + assert(p); +@@ -130,14 +126,8 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { + if (message) + IOVEC_SET_STRING(iovec[n++], message); + +-#ifdef HAVE_SELINUX +- if (s->security_context) { +- label = (char*) s->security_context; +- label_len = strlen((char*) s->security_context); +- } +-#endif +- +- server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0); ++ label_len = s->label ? strlen(s->label) : 0; ++ server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, s->label, label_len, s->unit_id, priority, 0); + return 0; + } + +@@ -343,11 +333,7 @@ void stdout_stream_free(StdoutStream *s) { + + safe_close(s->fd); + +-#ifdef HAVE_SELINUX +- if (s->security_context) +- freecon(s->security_context); +-#endif +- ++ free(s->label); + free(s->identifier); + free(s->unit_id); + free(s); +@@ -396,8 +382,9 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent + + #ifdef HAVE_SELINUX + if (mac_selinux_use()) { +- if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT) +- log_error_errno(errno, "Failed to determine peer security context: %m"); ++ r = getpeersec(fd, &stream->label); ++ if (r < 0 && r != -EOPNOTSUPP) ++ (void) log_warning_errno(r, "Failed to determine peer security context: %m"); + } + #endif + diff --git a/SOURCES/0193-bash-completion-add-verb-set-property.patch b/SOURCES/0193-bash-completion-add-verb-set-property.patch new file mode 100644 index 00000000..a65df944 --- /dev/null +++ b/SOURCES/0193-bash-completion-add-verb-set-property.patch @@ -0,0 +1,51 @@ +From 19c1015ce732c387cae8d0a2b116eb2022087ca2 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 23 Sep 2014 14:59:11 +0200 +Subject: [PATCH] bash-completion: add verb set-property + +not in upstream yet + +Resolves: #1235635 +--- + shell-completion/bash/systemctl.in | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in +index 3d787cdb7..496c756a4 100644 +--- a/shell-completion/bash/systemctl.in ++++ b/shell-completion/bash/systemctl.in +@@ -96,6 +96,12 @@ _systemctl () { + [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --root' + ) + ++ local -A PROPS='CPUQuota= CPUAccounting= MemoryAccounting= BlockIOAccounting= SendSIGHUP= SendSIGKILL= WakeSystem= ++ DefaultDependencies= MemoryLimit= CPUShares= BlockIOWeight= User= Group= DevicePolicy= KillMode= DeviceAllow= ++ BlockIOReadBandwidth= BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= KillSignal= AccuracySec= ++ LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= LimitMEMLOCK= ++ LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= LimitNICE= LimitRTPRIO= LimitRTTIME=' ++ + if __contains_word "--user" ${COMP_WORDS[*]}; then + mode=--user + else +@@ -153,6 +159,7 @@ _systemctl () { + [MASKED_UNITS]='unmask' + [JOBS]='cancel' + [SNAPSHOTS]='delete' ++ [PROPERTIES]='set-property' + [ENVS]='set-environment unset-environment' + [STANDALONE]='daemon-reexec daemon-reload default + emergency exit halt hibernate hybrid-sleep kexec list-jobs +@@ -258,6 +265,13 @@ _systemctl () { + elif __contains_word "$verb" ${VERBS[TARGETS]}; then + comps=$( __systemctl $mode list-unit-files --type target --full --all \ + | { while read -r a b; do echo " $a"; done; } ) ++ elif __contains_word "$verb" ${VERBS[PROPERTIES]}; then ++ if __contains_word "$prev" ${VERBS[PROPERTIES]}; then ++ comps=$( __get_active_units $mode ) ++ else ++ comps=$PROPS ++ compopt -o nospace ++ fi + fi + + COMPREPLY=( $(compgen -o filenames -W '$comps' -- "$cur") ) diff --git a/SOURCES/0194-sd-bus-don-t-inherit-connection-creds-into-message-c.patch b/SOURCES/0194-sd-bus-don-t-inherit-connection-creds-into-message-c.patch new file mode 100644 index 00000000..a111ab0c --- /dev/null +++ b/SOURCES/0194-sd-bus-don-t-inherit-connection-creds-into-message-c.patch @@ -0,0 +1,33 @@ +From 61a6ce79defd59fee00cd2bc28d58f7c3e637ae2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 23 Apr 2015 13:37:03 +0200 +Subject: [PATCH] sd-bus: don't inherit connection creds into message creds + when we have a direct connection + +It's never a good idea, let's just not do it, not even on dierct +connections. + +Conflicts: + src/libsystemd/sd-bus/bus-socket.c + +Cherry-picked from: 038f9863 +Related: #1230190 +--- + src/libsystemd/sd-bus/bus-socket.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c +index d00cd014e..a3c3a45b4 100644 +--- a/src/libsystemd/sd-bus/bus-socket.c ++++ b/src/libsystemd/sd-bus/bus-socket.c +@@ -900,8 +900,8 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) { + r = bus_message_from_malloc(bus, + bus->rbuffer, size, + bus->fds, bus->n_fds, +- !bus->bus_client && bus->ucred_valid ? &bus->ucred : NULL, +- !bus->bus_client && bus->label[0] ? bus->label : NULL, ++ NULL, ++ NULL, + &t); + if (r < 0) { + free(b); diff --git a/SOURCES/0195-udev-fix-crash-in-path_id-builtin.patch b/SOURCES/0195-udev-fix-crash-in-path_id-builtin.patch new file mode 100644 index 00000000..d69b3552 --- /dev/null +++ b/SOURCES/0195-udev-fix-crash-in-path_id-builtin.patch @@ -0,0 +1,27 @@ +From a571e5420b188913e4986f65c33294c2b39e3f7d Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 14 Jul 2015 17:24:09 +0200 +Subject: [PATCH] udev: fix crash in path_id builtin + +RHEL-only + +Resolves: #957112 +--- + src/udev/udev-builtin-path_id.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 025392df5..9ca608468 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -737,6 +737,10 @@ out: + } + + free(path); ++ path = NULL; ++ supported_transport = false; ++ supported_parent = false; ++ + + if (new_sas_path) { + enable_new_sas_path = false; diff --git a/SOURCES/0196-sysv-generator-test-Fix-assertion.patch b/SOURCES/0196-sysv-generator-test-Fix-assertion.patch new file mode 100644 index 00000000..a5bc4cf7 --- /dev/null +++ b/SOURCES/0196-sysv-generator-test-Fix-assertion.patch @@ -0,0 +1,35 @@ +From 20f5864e8f41957f6ed4b94a0199253a821b8c40 Mon Sep 17 00:00:00 2001 +From: Alberto Fanjul Alonso +Date: Tue, 28 Apr 2015 15:44:23 +0200 +Subject: [PATCH] sysv-generator test: Fix assertion + +(cherry picked from commit 230f04856647fcfb07d5658f4b8c1cb3557fa0d8) + +Cherry-picked from: 230f048 +Resolves: #1222517 +--- + test/sysv-generator-test.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py +index 09f5c0176..509899e0a 100644 +--- a/test/sysv-generator-test.py ++++ b/test/sysv-generator-test.py +@@ -323,7 +323,7 @@ class SysvGeneratorTest(unittest.TestCase): + self.add_sysv('foo.sh', {'Provides': 'foo bar'}) + err, results = self.run_generator() + # ensure we don't try to create a symlink to itself +- self.assertNotIn(err, 'itself') ++ self.assertNotIn('itself', err) + self.assertEqual(list(results), ['foo.service']) + self.assertEqual(results['foo.service'].get('Unit', 'Description'), + 'LSB: test foo service') +@@ -361,7 +361,7 @@ class SysvGeneratorTest(unittest.TestCase): + ['foo.bak.service', 'foo.old.service', 'foo.service']) + + # ensure we don't try to create a symlink to itself +- self.assertNotIn(err, 'itself') ++ self.assertNotIn('itself', err) + + self.assert_enabled('foo.service', [2, 3, 4, 5]) + self.assert_enabled('foo.bak.service', []) diff --git a/SOURCES/0197-man-avoid-line-break-in-url.patch b/SOURCES/0197-man-avoid-line-break-in-url.patch new file mode 100644 index 00000000..16fc3a11 --- /dev/null +++ b/SOURCES/0197-man-avoid-line-break-in-url.patch @@ -0,0 +1,27 @@ +From ab0d796698509ca5da4ac4c926ab123925b25b4e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 29 Apr 2015 12:04:16 +0200 +Subject: [PATCH] man: avoid line break in url + +(cherry picked from commit b53c3c2d24ed1398ee427139cd880b07bc35fa24) + +Cherry-picked from: b53c3c2 +Resolves: #1222517 +--- + man/os-release.xml | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/man/os-release.xml b/man/os-release.xml +index 8f4ab10fe..4f57323d4 100644 +--- a/man/os-release.xml ++++ b/man/os-release.xml +@@ -104,8 +104,7 @@ + + For a longer rationale for os-release + please refer to the Announcement of +- /etc/os-release. ++ url="http://0pointer.de/blog/projects/os-release">Announcement of /etc/os-release. + + + diff --git a/SOURCES/0198-Add-VARIANT-as-a-standard-value-for-etc-os-release.patch b/SOURCES/0198-Add-VARIANT-as-a-standard-value-for-etc-os-release.patch new file mode 100644 index 00000000..01cd5f1a --- /dev/null +++ b/SOURCES/0198-Add-VARIANT-as-a-standard-value-for-etc-os-release.patch @@ -0,0 +1,75 @@ +From e31c6804ca177ab911f6212b34930969b83f2d30 Mon Sep 17 00:00:00 2001 +From: Stephen Gallagher +Date: Wed, 29 Apr 2015 08:19:05 -0400 +Subject: [PATCH] Add VARIANT as a standard value for /etc/os-release + +Some distributions (such as Fedora) are using the VARIANT field to +indicate to select packages which of several default configurations +they should be using. For example, VARIANT=Server provides a +different default firewall configuration (blocking basically +everything but SSH and the management console) whereas +VARIANT=Workstation opens many other ports for application +compatibility. + +By adding this patch to the manual pages, we can standardize on a +cross-distribution mechanism for accomplishing this. + +Fedora implementation details are available at +https://fedoraproject.org/wiki/Packaging:Per-Product_Configuration + +(David: drop double paranthesis) + +(cherry picked from commit be7d0048ddda1e994f651e2825f96266d537d10d) + +Cherry-picked from: be7d004 +Resolves: #1222517 +--- + man/os-release.xml | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/man/os-release.xml b/man/os-release.xml +index 4f57323d4..4ca2e5970 100644 +--- a/man/os-release.xml ++++ b/man/os-release.xml +@@ -273,6 +273,41 @@ + + + ++ ++ VARIANT= ++ ++ ++ A string identifying a specific variant or edition of the ++ operating system suitable for presentation to the user. This ++ field may be used to inform the user that the configuration of ++ this system is subject to a specific divergent set of rules or ++ default configuration settings. This field is optional and may ++ not be implemented on all systems. ++ Examples: ++ VARIANT="Server Edition", ++ VARIANT="Smart Refrigerator Edition" ++ Note: this field is for display purposes only. The ++ VARIANT_ID field should be used for making ++ programmatic decisions. ++ ++ ++ ++ ++ VARIANT_ID= ++ ++ ++ A lower-case string (no spaces or other characters outside of ++ 0-9, a-z, ".", "_" and "-"), identifying a specific variant or ++ edition of the operating system. This may be interpreted by ++ other packages in order to determine a divergent default ++ configuration. This field is optional and may not be ++ implemented on all systems. ++ Examples: ++ VARIANT_ID=server, ++ VARIANT_ID=embedded ++ ++ ++ + + + If you are reading this file from C code or a shell script diff --git a/SOURCES/0199-Fix-permissions-on-run-systemd-nspawn-locks.patch b/SOURCES/0199-Fix-permissions-on-run-systemd-nspawn-locks.patch new file mode 100644 index 00000000..4539e64e --- /dev/null +++ b/SOURCES/0199-Fix-permissions-on-run-systemd-nspawn-locks.patch @@ -0,0 +1,44 @@ +From b0a6aa4de054e69213d0902094a1ae85fe2c5e58 Mon Sep 17 00:00:00 2001 +From: Seth Jennings +Date: Tue, 5 May 2015 13:31:01 -0500 +Subject: [PATCH] Fix permissions on /run/systemd/nspawn/locks + +machined is getting an EACCES when trying to create the lock file for +images because the mode on /run/systemd/nspawn/locks is 0600. + +mkdir("/run/systemd/nspawn/locks", 0600) = -1 EEXIST (File exists) +stat("/run/systemd/nspawn/locks", {st_mode=S_IFDIR|0600, st_size=40, ...}) = 0 +open("/run/systemd/nspawn/locks/inode-41:256", O_RDWR|O_CREAT|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC, 0600) = -1 EACCES (Permission denied) + +This commit adjusts the mode to 0700 to correct the issue. + +(cherry picked from commit 7e7cddb22493642dad826ec42ac00979f40b2d17) + +Cherry-picked from: 7e7cddb +Resolves: #1222517 +--- + src/shared/machine-image.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c +index 8d61507e8..c02ee814c 100644 +--- a/src/shared/machine-image.c ++++ b/src/shared/machine-image.c +@@ -601,7 +601,7 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile + return r; + + if (p) { +- mkdir_p("/run/systemd/nspawn/locks", 0600); ++ mkdir_p("/run/systemd/nspawn/locks", 0700); + + r = make_lock_file(p, operation, global); + if (r < 0) { +@@ -628,7 +628,7 @@ int image_name_lock(const char *name, int operation, LockFile *ret) { + if (streq(name, ".host")) + return -EBUSY; + +- mkdir_p("/run/systemd/nspawn/locks", 0600); ++ mkdir_p("/run/systemd/nspawn/locks", 0700); + p = strjoina("/run/systemd/nspawn/locks/name-", name); + + return make_lock_file(p, operation, ret); diff --git a/SOURCES/0200-generators-rename-add_-root-usr-_mount-to-add_-sysro.patch b/SOURCES/0200-generators-rename-add_-root-usr-_mount-to-add_-sysro.patch new file mode 100644 index 00000000..9d0b7486 --- /dev/null +++ b/SOURCES/0200-generators-rename-add_-root-usr-_mount-to-add_-sysro.patch @@ -0,0 +1,163 @@ +From 3282d24f8f9f7561312779710f250396f2ecc29b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 2 May 2015 12:01:29 -0500 +Subject: [PATCH] generators: rename add_{root,usr}_mount to + add_{sysroot,sysroot_usr}_mount + +This makes it obvious that those functions are only usable in the +initramfs. + +Also, add a warning when noauto, nofail, or automount is used for the +root fs, instead of silently ignoring. Using those options would be a +sign of significant misconfiguration, and if we bother to check for +them, than let's go all the way and complain. + +Other various small cleanups and reformattings elsewhere. + +(cherry picked from commit 2e8522767e27d5686206794c69e0aa95da6e798b) + +Cherry-picked from: 2e85227 +Resolves: #1222517 +--- + src/fstab-generator/fstab-generator.c | 20 ++++++++++++-------- + src/shared/generator.c | 21 ++++++++++++--------- + src/shared/generator.h | 17 +++++++++++++---- + 3 files changed, 37 insertions(+), 21 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 65ed20579..029eb1638 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -250,10 +250,14 @@ static int add_mount( + return 0; + + if (path_equal(where, "/")) { +- /* The root disk is not an option */ +- automount = false; +- noauto = false; +- nofail = false; ++ if (noauto) ++ log_warning("Ignoring \"noauto\" for root device"); ++ if (nofail) ++ log_warning("Ignoring \"nofail\" for root device"); ++ if (automount) ++ log_warning("Ignoring automount option for root device"); ++ ++ noauto = nofail = automount = false; + } + + name = unit_name_from_path(where, ".mount"); +@@ -470,7 +474,7 @@ static int parse_fstab(bool initrd) { + return r; + } + +-static int add_root_mount(void) { ++static int add_sysroot_mount(void) { + _cleanup_free_ char *what = NULL; + const char *opts; + +@@ -506,7 +510,7 @@ static int add_root_mount(void) { + "/proc/cmdline"); + } + +-static int add_usr_mount(void) { ++static int add_sysroot_usr_mount(void) { + _cleanup_free_ char *what = NULL; + const char *opts; + +@@ -653,9 +657,9 @@ int main(int argc, char *argv[]) { + + /* Always honour root= and usr= in the kernel command line if we are in an initrd */ + if (in_initrd()) { +- r = add_root_mount(); ++ r = add_sysroot_mount(); + if (r == 0) +- r = add_usr_mount(); ++ r = add_sysroot_usr_mount(); + } + + /* Honour /etc/fstab only when that's enabled */ +diff --git a/src/shared/generator.c b/src/shared/generator.c +index 7f16d5cbe..cd37812f8 100644 +--- a/src/shared/generator.c ++++ b/src/shared/generator.c +@@ -33,13 +33,13 @@ + + int generator_write_fsck_deps( + FILE *f, +- const char *dest, ++ const char *dir, + const char *what, + const char *where, + const char *fstype) { + + assert(f); +- assert(dest); ++ assert(dir); + assert(what); + assert(where); + +@@ -59,10 +59,10 @@ int generator_write_fsck_deps( + return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype); + } + +- if (streq(where, "/")) { ++ if (path_equal(where, "/")) { + char *lnk; + +- lnk = strjoina(dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service"); ++ lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service"); + + mkdir_parents(lnk, 0755); + if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0) +@@ -76,17 +76,20 @@ int generator_write_fsck_deps( + return log_oom(); + + fprintf(f, +- "RequiresOverridable=%s\n" +- "After=%s\n", +- fsck, ++ "RequiresOverridable=%1$s\n" ++ "After=%1$s\n", + fsck); + } + + return 0; + } + +-int generator_write_timeouts(const char *dir, const char *what, const char *where, +- const char *opts, char **filtered) { ++int generator_write_timeouts( ++ const char *dir, ++ const char *what, ++ const char *where, ++ const char *opts, ++ char **filtered) { + + /* Allow configuration how long we wait for a device that + * backs a mount point to show up. This is useful to support +diff --git a/src/shared/generator.h b/src/shared/generator.h +index 64bd28f59..6c3f38abb 100644 +--- a/src/shared/generator.h ++++ b/src/shared/generator.h +@@ -23,7 +23,16 @@ + + #include + +-int generator_write_fsck_deps(FILE *f, const char *dest, const char *what, const char *where, const char *type); +- +-int generator_write_timeouts(const char *dir, const char *what, const char *where, +- const char *opts, char **filtered); ++int generator_write_fsck_deps( ++ FILE *f, ++ const char *dir, ++ const char *what, ++ const char *where, ++ const char *type); ++ ++int generator_write_timeouts( ++ const char *dir, ++ const char *what, ++ const char *where, ++ const char *opts, ++ char **filtered); diff --git a/SOURCES/0201-Generate-systemd-fsck-root.service-in-the-initramfs.patch b/SOURCES/0201-Generate-systemd-fsck-root.service-in-the-initramfs.patch new file mode 100644 index 00000000..76c6014d --- /dev/null +++ b/SOURCES/0201-Generate-systemd-fsck-root.service-in-the-initramfs.patch @@ -0,0 +1,109 @@ +From 306dfc00aefbd35197ca30469f4b40bb120caf91 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 6 May 2015 01:09:53 -0400 +Subject: [PATCH] Generate systemd-fsck-root.service in the initramfs + +In the initrafms, generate a systemd-fsck-root.service to replace +systemd-fsck@.service. This way, after we transition +to the real root, systemd-fsck-root.service is marked as already done. + +This introduces an unnecessary synchronization point, because +systemd-fsck@* is ordered after systemd-fsck-root also in the +initramfs. In practice this shouldn't be a problem. + +https://bugzilla.redhat.com/show_bug.cgi?id=1201979 + +C.f. 956eaf2b8d6c9999024705ddadc7393bc707de02. + +(cherry picked from commit 4dda4e637e4c17a14db6cd265f36f5e8a5050367) + +Cherry-picked from: 4dda4e6 +Resolves: #1222517 +--- + src/shared/generator.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 59 insertions(+), 4 deletions(-) + +diff --git a/src/shared/generator.c b/src/shared/generator.c +index cd37812f8..148a0b077 100644 +--- a/src/shared/generator.c ++++ b/src/shared/generator.c +@@ -29,8 +29,51 @@ + #include "generator.h" + #include "path-util.h" + #include "fstab-util.h" ++#include "fileio.h" + #include "dropin.h" + ++static int write_fsck_sysroot_service(const char *dir, const char *what) { ++ const char *unit; ++ _cleanup_free_ char *device = NULL; ++ _cleanup_fclose_ FILE *f = NULL; ++ ++ unit = strjoina(dir, "/systemd-fsck-root.service"); ++ log_debug("Creating %s", unit); ++ ++ device = unit_name_from_path(what, ".device"); ++ if (!device) ++ return log_oom(); ++ ++ f = fopen(unit, "wxe"); ++ if (!f) ++ return log_error_errno(errno, "Failed to create unit file %s: %m", unit); ++ ++ fprintf(f, ++ "# Automatically generated by %1$s\n\n" ++ "[Unit]\n" ++ "Documentation=man:systemd-fsck-root.service(8)\n" ++ "Description=File System Check on %2$s\n" ++ "DefaultDependencies=no\n" ++ "BindsTo=%3$s\n" ++ "After=%3$s\n" ++ "Before=shutdown.target\n" ++ "\n" ++ "[Service]\n" ++ "Type=oneshot\n" ++ "RemainAfterExit=yes\n" ++ "ExecStart=/usr/lib/systemd/systemd-fsck %2$s\n" ++ "TimeoutSec=0\n", ++ program_invocation_short_name, ++ what, ++ device); ++ ++ fflush(f); ++ if (ferror(f)) ++ return log_error_errno(errno, "Failed to write unit file %s: %m", unit); ++ ++ return 0; ++} ++ + int generator_write_fsck_deps( + FILE *f, + const char *dir, +@@ -69,11 +112,23 @@ int generator_write_fsck_deps( + return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); + + } else { +- _cleanup_free_ char *fsck = NULL; ++ _cleanup_free_ char *_fsck = NULL; ++ const char *fsck; ++ int r; ++ ++ if (in_initrd() && path_equal(where, "/sysroot")) { ++ r = write_fsck_sysroot_service(dir, what); ++ if (r < 0) ++ return r; ++ ++ fsck = "systemd-fsck-root.service"; ++ } else { ++ _fsck = unit_name_from_path_instance("systemd-fsck", what, ".service"); ++ if (!_fsck) ++ return log_oom(); + +- fsck = unit_name_from_path_instance("systemd-fsck", what, ".service"); +- if (!fsck) +- return log_oom(); ++ fsck = _fsck; ++ } + + fprintf(f, + "RequiresOverridable=%1$s\n" diff --git a/SOURCES/0202-units-fix-typo-in-systemd-resolved.service.patch b/SOURCES/0202-units-fix-typo-in-systemd-resolved.service.patch new file mode 100644 index 00000000..5682d39a --- /dev/null +++ b/SOURCES/0202-units-fix-typo-in-systemd-resolved.service.patch @@ -0,0 +1,33 @@ +From 9e7315f4149a97fa8d5b826770610cd59316db2d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 14 May 2015 22:32:35 +0200 +Subject: [PATCH] units: fix typo in systemd-resolved.service +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There's no network.service unit, we actually mean network.target here. + +Reported by Fco. Eduardo Ramírez. + +(cherry picked from commit 1dff3202941786dd00060f078f6b031efe52d3c3) + +Cherry-picked from: 1dff320 +Resolves: #1222517 +--- + units/systemd-resolved.service.m4.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/systemd-resolved.service.m4.in b/units/systemd-resolved.service.m4.in +index d133847d5..98ae564af 100644 +--- a/units/systemd-resolved.service.m4.in ++++ b/units/systemd-resolved.service.m4.in +@@ -8,7 +8,7 @@ + [Unit] + Description=Network Name Resolution + Documentation=man:systemd-resolved.service(8) +-After=systemd-networkd.service network.service ++After=systemd-networkd.service network.target + + m4_ifdef(`ENABLE_KDBUS', + # On kdbus systems we pull in the busname explicitly, because it diff --git a/SOURCES/0203-core-don-t-consider-umask-for-SocketMode.patch b/SOURCES/0203-core-don-t-consider-umask-for-SocketMode.patch new file mode 100644 index 00000000..23ac116a --- /dev/null +++ b/SOURCES/0203-core-don-t-consider-umask-for-SocketMode.patch @@ -0,0 +1,28 @@ +From a8ad87112c0992579fcf4fc91234490ec82ce939 Mon Sep 17 00:00:00 2001 +From: Davide Bettio +Date: Fri, 15 May 2015 16:36:28 +0200 +Subject: [PATCH] core: don't consider umask for SocketMode= + +https://bugs.freedesktop.org/show_bug.cgi?id=89248 +(cherry picked from commit a2c7f25aec23b6d74ff5cf169e38159754e6dfe8) + +Cherry-picked from: a2c7f25 +Resolves: #1222517 +--- + src/shared/socket-label.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c +index 6806c5115..a6289eb50 100644 +--- a/src/shared/socket-label.c ++++ b/src/shared/socket-label.c +@@ -117,9 +117,6 @@ int socket_address_listen( + /* Enforce the right access mode for the socket */ + old_mask = umask(~ socket_mode); + +- /* Include the original umask in our mask */ +- umask(~socket_mode | old_mask); +- + r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); + + if (r < 0 && errno == EADDRINUSE) { diff --git a/SOURCES/0204-timedate-fix-memory-leak-in-timedated.patch b/SOURCES/0204-timedate-fix-memory-leak-in-timedated.patch new file mode 100644 index 00000000..d1f88ab9 --- /dev/null +++ b/SOURCES/0204-timedate-fix-memory-leak-in-timedated.patch @@ -0,0 +1,71 @@ +From 266eacb3e5a46caba3a56485a9ba54ad8027ff61 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Fri, 15 May 2015 13:26:18 -0300 +Subject: [PATCH] timedate: fix memory leak in timedated + +$ /usr/lib/systemd/systemd-timedated (wait until auto-exit) + +================================================================= +==396==ERROR: LeakSanitizer: detected memory leaks + +Direct leak of 928 byte(s) in 1 object(s) allocated from: + #0 0x7f782f788db1 in __interceptor_calloc (/usr/lib64/libasan.so.2+0x96db1) + #1 0x562a83ae60cf in bus_message_from_header src/libsystemd/sd-bus/bus-message.c:480 + #2 0x562a83ae6f5a in bus_message_from_malloc src/libsystemd/sd-bus/bus-message.c:576 + #3 0x562a83ad3cad in bus_socket_make_message src/libsystemd/sd-bus/bus-socket.c:915 + #4 0x562a83ad4cfc in bus_socket_read_message src/libsystemd/sd-bus/bus-socket.c:1051 + #5 0x562a83ab733f in bus_read_message src/libsystemd/sd-bus/sd-bus.c:1647 + #6 0x562a83ab98ea in sd_bus_call src/libsystemd/sd-bus/sd-bus.c:2038 + #7 0x562a83b1f46d in sd_bus_call_method src/libsystemd/sd-bus/bus-convenience.c:94 + #8 0x562a83aab3e1 in context_read_ntp src/timedate/timedated.c:192 + #9 0x562a83aae1af in main src/timedate/timedated.c:730 + #10 0x7f782eb238c4 in __libc_start_main (/lib64/libc.so.6+0x208c4) + +Indirect leak of 77 byte(s) in 1 object(s) allocated from: + #0 0x7f782f788f6a in realloc (/usr/lib64/libasan.so.2+0x96f6a) + #1 0x562a83ad418a in bus_socket_read_message src/libsystemd/sd-bus/bus-socket.c:963 + #2 0x562a83ab733f in bus_read_message src/libsystemd/sd-bus/sd-bus.c:1647 + #3 0x562a83ab98ea in sd_bus_call src/libsystemd/sd-bus/sd-bus.c:2038 + #4 0x562a83b1f46d in sd_bus_call_method src/libsystemd/sd-bus/bus-convenience.c:94 + #5 0x562a83aab3e1 in context_read_ntp src/timedate/timedated.c:192 + #6 0x562a83aae1af in main src/timedate/timedated.c:730 + #7 0x7f782eb238c4 in __libc_start_main (/lib64/libc.so.6+0x208c4) + +Indirect leak of 2 byte(s) in 1 object(s) allocated from: + #0 0x7f782f75493f in strdup (/usr/lib64/libasan.so.2+0x6293f) + #1 0x562a83b0229b in bus_message_parse_fields src/libsystemd/sd-bus/bus-message.c:5382 + #2 0x562a83ae7290 in bus_message_from_malloc src/libsystemd/sd-bus/bus-message.c:601 + #3 0x562a83ad3cad in bus_socket_make_message src/libsystemd/sd-bus/bus-socket.c:915 + #4 0x562a83ad4cfc in bus_socket_read_message src/libsystemd/sd-bus/bus-socket.c:1051 + #5 0x562a83ab733f in bus_read_message src/libsystemd/sd-bus/sd-bus.c:1647 + #6 0x562a83ab98ea in sd_bus_call src/libsystemd/sd-bus/sd-bus.c:2038 + #7 0x562a83b1f46d in sd_bus_call_method src/libsystemd/sd-bus/bus-convenience.c:94 + #8 0x562a83aab3e1 in context_read_ntp src/timedate/timedated.c:192 + #9 0x562a83aae1af in main src/timedate/timedated.c:730 + #10 0x7f782eb238c4 in __libc_start_main (/lib64/libc.so.6+0x208c4) + +SUMMARY: AddressSanitizer: 1007 byte(s) leaked in 3 allocation(s). + +This is due to missing _cleanup_bus_message_unref_ in context_read_ntp() + +(cherry picked from commit 6b71bab08dc6c92156263daba0e969313eed1323) + +Cherry-picked from: 6b71bab +Resolves: #1222517 +--- + src/timedate/timedated.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index f87514936..09d0dbabc 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -245,7 +245,7 @@ static int context_read_ntp(Context *c, sd_bus *bus) { + l = get_ntp_services(); + STRV_FOREACH(i, l) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- sd_bus_message *reply = NULL; ++ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *s; + + r = sd_bus_call_method( diff --git a/SOURCES/0205-coredump-make-sure-we-vacuum-by-default.patch b/SOURCES/0205-coredump-make-sure-we-vacuum-by-default.patch new file mode 100644 index 00000000..fc13b3b2 --- /dev/null +++ b/SOURCES/0205-coredump-make-sure-we-vacuum-by-default.patch @@ -0,0 +1,57 @@ +From c730efd5335cf49ef78008b7d49fc5d5215089eb Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 15 May 2015 20:56:55 +0200 +Subject: [PATCH] coredump: make sure we vacuum by default + +Only if both keep_free and max_use are actually 0 we can shortcut things +and avoid vacuuming. If either are positive or -1 we need to execute the +vacuuming. + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/031382.html +(cherry picked from commit 5470c03b37d8421a903564c2c8028c8b8d67d403) + +Cherry-picked from: 5470c03 +Resolves: #1222517 +--- + man/coredump.conf.xml | 4 +++- + src/journal/coredump-vacuum.c | 5 ++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml +index 0b7329bf5..fd54c59e6 100644 +--- a/man/coredump.conf.xml ++++ b/man/coredump.conf.xml +@@ -134,7 +134,9 @@ + by coredumps might temporarily exceed these limits while + coredumps are processed. Note that old coredumps are also + removed based on time via +- systemd-tmpfiles8. ++ systemd-tmpfiles8. Set ++ either value to 0 to turn off size based ++ clean-up. + + + +diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c +index 9b73795e5..c0347ef56 100644 +--- a/src/journal/coredump-vacuum.c ++++ b/src/journal/coredump-vacuum.c +@@ -103,8 +103,7 @@ static bool vacuum_necessary(int fd, off_t sum, off_t keep_free, off_t max_use) + + if (max_use < DEFAULT_MAX_USE_LOWER) + max_use = DEFAULT_MAX_USE_LOWER; +- } +- else ++ } else + max_use = DEFAULT_MAX_USE_LOWER; + } else + max_use = PAGE_ALIGN(max_use); +@@ -135,7 +134,7 @@ int coredump_vacuum(int exclude_fd, off_t keep_free, off_t max_use) { + struct stat exclude_st; + int r; + +- if (keep_free <= 0 && max_use <= 0) ++ if (keep_free == 0 && max_use == 0) + return 0; + + if (exclude_fd >= 0) { diff --git a/SOURCES/0206-tmpfiles-don-t-fail-if-we-cannot-create-a-subvolume-.patch b/SOURCES/0206-tmpfiles-don-t-fail-if-we-cannot-create-a-subvolume-.patch new file mode 100644 index 00000000..a8fd11a8 --- /dev/null +++ b/SOURCES/0206-tmpfiles-don-t-fail-if-we-cannot-create-a-subvolume-.patch @@ -0,0 +1,51 @@ +From e2550d725cf94c01dee40f5f02ad242ee8e02072 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 15 May 2015 21:47:22 +0200 +Subject: [PATCH] tmpfiles: don't fail if we cannot create a subvolume because + a file system is read-only but a dir already exists anyway + +https://bugs.freedesktop.org/show_bug.cgi?id=90281 +(cherry picked from commit 7b135a73999b6911ebb85c053b6f7701fdac1883) + +Cherry-picked from: 7b135a7 +Resolves: #1222517 +--- + src/tmpfiles/tmpfiles.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 73a9c9d5b..d0e6567d8 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1002,20 +1002,25 @@ static int create_item(Item *i) { + r = mkdir_label(i->path, i->mode); + + if (r < 0) { +- if (r != -EEXIST) +- return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path); ++ int k; + +- if (stat(i->path, &st) < 0) +- return log_error_errno(errno, "stat(%s) failed: %m", i->path); ++ if (r != -EEXIST && r != -EROFS) ++ return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path); + +- if (!S_ISDIR(st.st_mode)) { +- log_debug("\"%s\" already exists and is not a directory.", i->path); ++ k = is_dir(i->path, false); ++ if (k == -ENOENT && r == -EROFS) ++ return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", i->path); ++ if (k < 0) ++ return log_error_errno(k, "Failed to check if %s exists: %m", i->path); ++ if (!k) { ++ log_warning("\"%s\" already exists and is not a directory.", i->path); + return 0; + } + + creation = CREATION_EXISTING; + } else + creation = CREATION_NORMAL; ++ + log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path); + + r = path_set_perms(i, i->path); diff --git a/SOURCES/0207-resolved-fix-crash-when-shutting-down.patch b/SOURCES/0207-resolved-fix-crash-when-shutting-down.patch new file mode 100644 index 00000000..0a28c9b3 --- /dev/null +++ b/SOURCES/0207-resolved-fix-crash-when-shutting-down.patch @@ -0,0 +1,148 @@ +From c724e008771aaaed70f909cb28fdcab1c9244d22 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 18 May 2015 23:23:17 +0200 +Subject: [PATCH] resolved: fix crash when shutting down +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reported by Cristian Rodríguez + +http://lists.freedesktop.org/archives/systemd-devel/2015-May/031626.html +(cherry picked from commit cab5b05903096e1c9cf5575ccc73f89d15c8db69) + +Cherry-picked from: cab5b05 +Resolves: #1222517 +--- + src/resolve/resolved-dns-cache.c | 4 +--- + src/resolve/resolved-dns-server.c | 15 ++++++++------- + src/resolve/resolved-link.c | 6 +++--- + src/resolve/resolved-manager.c | 4 ++-- + src/shared/prioq.c | 6 ++++-- + src/shared/prioq.h | 2 +- + 6 files changed, 19 insertions(+), 18 deletions(-) + +diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c +index 33ca4d1a4..874207cfb 100644 +--- a/src/resolve/resolved-dns-cache.c ++++ b/src/resolve/resolved-dns-cache.c +@@ -93,9 +93,7 @@ void dns_cache_flush(DnsCache *c) { + + hashmap_free(c->by_key); + c->by_key = NULL; +- +- prioq_free(c->by_expiry); +- c->by_expiry = NULL; ++ c->by_expiry = prioq_free(c->by_expiry); + } + + static void dns_cache_remove(DnsCache *c, DnsResourceKey *key) { +diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c +index caf06fe45..9a62a6325 100644 +--- a/src/resolve/resolved-dns-server.c ++++ b/src/resolve/resolved-dns-server.c +@@ -78,23 +78,24 @@ DnsServer* dns_server_free(DnsServer *s) { + if (!s) + return NULL; + +- if (s->manager) { ++ if (s->link) { + if (s->type == DNS_SERVER_LINK) + LIST_REMOVE(servers, s->link->dns_servers, s); +- else if (s->type == DNS_SERVER_SYSTEM) ++ ++ if (s->link->current_dns_server == s) ++ link_set_dns_server(s->link, NULL); ++ } ++ ++ if (s->manager) { ++ if (s->type == DNS_SERVER_SYSTEM) + LIST_REMOVE(servers, s->manager->dns_servers, s); + else if (s->type == DNS_SERVER_FALLBACK) + LIST_REMOVE(servers, s->manager->fallback_dns_servers, s); +- else +- assert_not_reached("Unknown server type"); + + if (s->manager->current_dns_server == s) + manager_set_dns_server(s->manager, NULL); + } + +- if (s->link && s->link->current_dns_server == s) +- link_set_dns_server(s->link, NULL); +- + free(s); + + return NULL; +diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c +index f94e4bb6f..27d9129e0 100644 +--- a/src/resolve/resolved-link.c ++++ b/src/resolve/resolved-link.c +@@ -68,13 +68,13 @@ Link *link_free(Link *l) { + if (l->manager) + hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex)); + ++ while (l->dns_servers) ++ dns_server_free(l->dns_servers); ++ + dns_scope_free(l->unicast_scope); + dns_scope_free(l->llmnr_ipv4_scope); + dns_scope_free(l->llmnr_ipv6_scope); + +- while (l->dns_servers) +- dns_server_free(l->dns_servers); +- + free(l); + return NULL; + } +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index b5ad70161..7c253aa13 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -536,11 +536,11 @@ Manager *manager_free(Manager *m) { + while (m->dns_queries) + dns_query_free(m->dns_queries); + +- dns_scope_free(m->unicast_scope); +- + manager_flush_dns_servers(m, DNS_SERVER_SYSTEM); + manager_flush_dns_servers(m, DNS_SERVER_FALLBACK); + ++ dns_scope_free(m->unicast_scope); ++ + hashmap_free(m->links); + hashmap_free(m->dns_transactions); + +diff --git a/src/shared/prioq.c b/src/shared/prioq.c +index 8af4c51c2..b89888be0 100644 +--- a/src/shared/prioq.c ++++ b/src/shared/prioq.c +@@ -45,12 +45,14 @@ Prioq *prioq_new(compare_func_t compare_func) { + return q; + } + +-void prioq_free(Prioq *q) { ++Prioq* prioq_free(Prioq *q) { + if (!q) +- return; ++ return NULL; + + free(q->items); + free(q); ++ ++ return NULL; + } + + int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) { +diff --git a/src/shared/prioq.h b/src/shared/prioq.h +index d836b36cd..1c044b135 100644 +--- a/src/shared/prioq.h ++++ b/src/shared/prioq.h +@@ -28,7 +28,7 @@ typedef struct Prioq Prioq; + #define PRIOQ_IDX_NULL ((unsigned) -1) + + Prioq *prioq_new(compare_func_t compare); +-void prioq_free(Prioq *q); ++Prioq *prioq_free(Prioq *q); + int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func); + + int prioq_put(Prioq *q, void *data, unsigned *idx); diff --git a/SOURCES/0208-resolved-allow-DnsAnswer-objects-with-no-space-for-R.patch b/SOURCES/0208-resolved-allow-DnsAnswer-objects-with-no-space-for-R.patch new file mode 100644 index 00000000..0603cc1d --- /dev/null +++ b/SOURCES/0208-resolved-allow-DnsAnswer-objects-with-no-space-for-R.patch @@ -0,0 +1,30 @@ +From d5b06145261637bcb69c1a213874cce10918a189 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 18 May 2015 23:38:47 +0200 +Subject: [PATCH] resolved: allow DnsAnswer objects with no space for RRs + +They might be created as result of merged answer sets, hence accept +them. + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/030834.html +(cherry picked from commit 084cea6cee1471d81e078bea4e7ee5f50a5dc009) + +Cherry-picked from: 084cea6 +Resolves: #1222517 +--- + src/resolve/resolved-dns-answer.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c +index 7c4ab18b5..e08eb667c 100644 +--- a/src/resolve/resolved-dns-answer.c ++++ b/src/resolve/resolved-dns-answer.c +@@ -25,8 +25,6 @@ + DnsAnswer *dns_answer_new(unsigned n) { + DnsAnswer *a; + +- assert(n > 0); +- + a = malloc0(offsetof(DnsAnswer, rrs) + sizeof(DnsResourceRecord*) * n); + if (!a) + return NULL; diff --git a/SOURCES/0209-id128-add-new-sd_id128_is_null-call.patch b/SOURCES/0209-id128-add-new-sd_id128_is_null-call.patch new file mode 100644 index 00000000..25f0d076 --- /dev/null +++ b/SOURCES/0209-id128-add-new-sd_id128_is_null-call.patch @@ -0,0 +1,28 @@ +From 69c2ae8ed9bb861a0bc47ce553b1749390009036 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 24 Feb 2015 00:10:35 +0100 +Subject: [PATCH] id128: add new sd_id128_is_null() call + +(cherry picked from commit 15e80c7b75c3a3188bfaaa0baddccf31ae661a7a) + +Cherry-picked from: 15e80c7 +Resolves: #1222517 +--- + src/systemd/sd-id128.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h +index 48fd87671..9f445278b 100644 +--- a/src/systemd/sd-id128.h ++++ b/src/systemd/sd-id128.h +@@ -106,6 +106,10 @@ _sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) { + return memcmp(&a, &b, 16) == 0; + } + ++_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) { ++ return a.qwords[0] == 0 && a.qwords[1] == 0; ++} ++ + #define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }}) + + _SD_END_DECLARATIONS; diff --git a/SOURCES/0210-journalctl-Improve-boot-ID-lookup.patch b/SOURCES/0210-journalctl-Improve-boot-ID-lookup.patch new file mode 100644 index 00000000..1916e7e8 --- /dev/null +++ b/SOURCES/0210-journalctl-Improve-boot-ID-lookup.patch @@ -0,0 +1,403 @@ +From 99ea430346f3f8ffba504cd3de1a269ab4eac8e6 Mon Sep 17 00:00:00 2001 +From: Jan Janssen +Date: Fri, 1 May 2015 15:15:16 +0200 +Subject: [PATCH] journalctl: Improve boot ID lookup + +This method should greatly improve offset based lookup, by simply jumping +from one boot to the next boot. It starts at the journal head to get the +a boot ID, makes a _BOOT_ID match and then comes from the opposite +journal direction (tail) to get to the end that boot. After flushing the matches +and advancing the journal from that exact position, we arrive at the start +of next boot. Rinse and repeat. + +This is faster than the old method of aggregating the full boot listing just +so we can jump to a specific boot, which can be a real pain on big journals +just for a mere "-b -1" case. + +As an additional benefit --list-boots should improve slightly too, because +it does less seeking. + +Note that there can be a change in boot order with this lookup method +because it will use the order of boots in the journal, not the realtime stamp +stored in them. That's arguably better, though. +Another deficiency is that it will get confused with boots interleaving in the +journal, therefore, it will refuse operation in --merge, --file and --directory mode. + +https://bugs.freedesktop.org/show_bug.cgi?id=72601 +(cherry picked from commit 596a23293d28f93843aef86721b90043e74d3081) + +Cherry-picked from: 596a232 +Resolves: #1222517 +--- + src/journal/journalctl.c | 275 ++++++++++++++++++++++++++++++----------------- + 1 file changed, 174 insertions(+), 101 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 12c869f5a..c26cc00f5 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -131,6 +131,7 @@ typedef struct boot_id_t { + sd_id128_t id; + uint64_t first; + uint64_t last; ++ LIST_FIELDS(struct boot_id_t, boot_list); + } boot_id_t; + + static void pager_open_if_enabled(void) { +@@ -735,6 +736,11 @@ static int parse_argv(int argc, char *argv[]) { + return -EINVAL; + } + ++ if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && (arg_file || arg_directory || arg_merge)) { ++ log_error("Using --boot or --list-boots with --file, --directory or --merge is not supported."); ++ return -EINVAL; ++ } ++ + return 1; + } + +@@ -854,111 +860,203 @@ static int add_matches(sd_journal *j, char **args) { + return 0; + } + +-static int boot_id_cmp(const void *a, const void *b) { +- uint64_t _a, _b; ++static int discover_next_boot(sd_journal *j, ++ boot_id_t **boot, ++ bool advance_older, ++ bool read_realtime) { ++ int r; ++ char match[9+32+1] = "_BOOT_ID="; ++ _cleanup_free_ boot_id_t *next_boot = NULL; + +- _a = ((const boot_id_t *)a)->first; +- _b = ((const boot_id_t *)b)->first; ++ assert(j); ++ assert(boot); + +- return _a < _b ? -1 : (_a > _b ? 1 : 0); +-} ++ /* We expect the journal to be on the last position of a boot ++ * (in relation to the direction we are going), so that the next ++ * invocation of sd_journal_next/previous will be from a different ++ * boot. We then collect any information we desire and then jump ++ * to the last location of the new boot by using a _BOOT_ID match ++ * coming from the other journal direction. */ + +-static int get_boots(sd_journal *j, +- boot_id_t **boots, +- unsigned int *count, +- boot_id_t *query_ref_boot) { +- int r; +- const void *data; +- size_t length, allocated = 0; ++ /* Make sure we aren't restricted by any _BOOT_ID matches, so that ++ * we can actually advance to a *different* boot. */ ++ sd_journal_flush_matches(j); + +- assert(j); +- assert(boots); +- assert(count); ++ if (advance_older) ++ r = sd_journal_previous(j); ++ else ++ r = sd_journal_next(j); ++ if (r < 0) ++ return r; ++ else if (r == 0) ++ return 0; /* End of journal, yay. */ ++ ++ next_boot = new0(boot_id_t, 1); ++ if (!next_boot) ++ return log_oom(); + +- r = sd_journal_query_unique(j, "_BOOT_ID"); ++ r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id); + if (r < 0) + return r; + +- *count = 0; +- SD_JOURNAL_FOREACH_UNIQUE(j, data, length) { +- boot_id_t *id; ++ if (read_realtime) { ++ r = sd_journal_get_realtime_usec(j, &next_boot->first); ++ if (r < 0) ++ return r; ++ } + +- assert(startswith(data, "_BOOT_ID=")); ++ /* Now seek to the last occurrence of this boot ID. */ ++ sd_id128_to_string(next_boot->id, match + 9); ++ r = sd_journal_add_match(j, match, sizeof(match) - 1); ++ if (r < 0) ++ return r; + +- if (!GREEDY_REALLOC(*boots, allocated, *count + 1)) +- return log_oom(); ++ if (advance_older) ++ r = sd_journal_seek_head(j); ++ else ++ r = sd_journal_seek_tail(j); ++ if (r < 0) ++ return r; + +- id = *boots + *count; ++ if (advance_older) ++ r = sd_journal_next(j); ++ else ++ r = sd_journal_previous(j); ++ if (r < 0) ++ return r; ++ else if (r == 0) ++ return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */ + +- r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id); ++ if (read_realtime) { ++ r = sd_journal_get_realtime_usec(j, &next_boot->last); + if (r < 0) +- continue; ++ return r; ++ } ++ ++ *boot = next_boot; ++ next_boot = NULL; ++ return 0; ++} ++ ++static int get_boots(sd_journal *j, ++ boot_id_t **boots, ++ boot_id_t *query_ref_boot, ++ int ref_boot_offset) { ++ bool skip_once; ++ int r, count = 0; ++ boot_id_t *head = NULL, *tail = NULL; ++ const bool advance_older = query_ref_boot && ref_boot_offset <= 0; ++ ++ assert(j); ++ ++ /* Adjust for the asymmetry that offset 0 is ++ * the last (and current) boot, while 1 is considered the ++ * (chronological) first boot in the journal. */ ++ skip_once = query_ref_boot && sd_id128_is_null(query_ref_boot->id) && ref_boot_offset < 0; ++ ++ /* Advance to the earliest/latest occurrence of our reference ++ * boot ID (taking our lookup direction into account), so that ++ * discover_next_boot() can do its job. ++ * If no reference is given, the journal head/tail will do, ++ * they're "virtual" boots after all. */ ++ if (query_ref_boot && !sd_id128_is_null(query_ref_boot->id)) { ++ char match[9+32+1] = "_BOOT_ID="; ++ ++ sd_journal_flush_matches(j); + +- r = sd_journal_add_match(j, data, length); ++ sd_id128_to_string(query_ref_boot->id, match + 9); ++ r = sd_journal_add_match(j, match, sizeof(match) - 1); + if (r < 0) + return r; + +- r = sd_journal_seek_head(j); ++ if (advance_older) ++ r = sd_journal_seek_head(j); ++ else ++ r = sd_journal_seek_tail(j); + if (r < 0) + return r; + +- r = sd_journal_next(j); ++ if (advance_older) ++ r = sd_journal_next(j); ++ else ++ r = sd_journal_previous(j); + if (r < 0) + return r; + else if (r == 0) +- goto flush; +- +- r = sd_journal_get_realtime_usec(j, &id->first); ++ goto finish; ++ else if (ref_boot_offset == 0) { ++ count = 1; ++ goto finish; ++ } ++ } else { ++ if (advance_older) ++ r = sd_journal_seek_tail(j); ++ else ++ r = sd_journal_seek_head(j); + if (r < 0) + return r; + +- if (query_ref_boot) { +- id->last = 0; +- if (sd_id128_equal(id->id, query_ref_boot->id)) +- *query_ref_boot = *id; +- } else { +- r = sd_journal_seek_tail(j); +- if (r < 0) +- return r; ++ /* No sd_journal_next/previous here. */ ++ } + +- r = sd_journal_previous(j); +- if (r < 0) +- return r; +- else if (r == 0) +- goto flush; ++ while (true) { ++ _cleanup_free_ boot_id_t *current = NULL; + +- r = sd_journal_get_realtime_usec(j, &id->last); +- if (r < 0) +- return r; ++ r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); ++ if (r < 0) { ++ boot_id_t *id, *id_next; ++ LIST_FOREACH_SAFE(boot_list, id, id_next, head) ++ free(id); ++ return r; + } + +- (*count)++; +- flush: +- sd_journal_flush_matches(j); ++ if (!current) ++ break; ++ ++ if (query_ref_boot) { ++ if (!skip_once) ++ ref_boot_offset += advance_older ? 1 : -1; ++ skip_once = false; ++ ++ if (ref_boot_offset == 0) { ++ count = 1; ++ query_ref_boot->id = current->id; ++ break; ++ } ++ } else { ++ LIST_INSERT_AFTER(boot_list, head, tail, current); ++ tail = current; ++ current = NULL; ++ count++; ++ } + } + +- qsort_safe(*boots, *count, sizeof(boot_id_t), boot_id_cmp); +- return 0; ++finish: ++ if (boots) ++ *boots = head; ++ ++ sd_journal_flush_matches(j); ++ ++ return count; + } + + static int list_boots(sd_journal *j) { +- int r, w, i; +- unsigned int count; +- boot_id_t *id; +- _cleanup_free_ boot_id_t *all_ids = NULL; ++ int w, i, count; ++ boot_id_t *id, *id_next, *all_ids; + + assert(j); + +- r = get_boots(j, &all_ids, &count, NULL); +- if (r < 0) +- return r; ++ count = get_boots(j, &all_ids, NULL, 0); ++ if (count <= 0) ++ return count; + + pager_open_if_enabled(); + + /* numbers are one less, but we need an extra char for the sign */ + w = DECIMAL_STR_WIDTH(count - 1) + 1; + +- for (id = all_ids, i = 0; id < all_ids + count; id++, i++) { ++ i = 0; ++ LIST_FOREACH_SAFE(boot_list, id, id_next, all_ids) { + char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX]; + + printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n", +@@ -966,39 +1064,8 @@ static int list_boots(sd_journal *j) { + SD_ID128_FORMAT_VAL(id->id), + format_timestamp_maybe_utc(a, sizeof(a), id->first), + format_timestamp_maybe_utc(b, sizeof(b), id->last)); +- } +- +- return 0; +-} +- +-static int get_boot_id_by_offset(sd_journal *j, sd_id128_t *boot_id, int offset) { +- int r; +- unsigned int count; +- boot_id_t ref_boot_id = {}, *id; +- _cleanup_free_ boot_id_t *all_ids = NULL; +- +- assert(j); +- assert(boot_id); +- +- ref_boot_id.id = *boot_id; +- r = get_boots(j, &all_ids, &count, &ref_boot_id); +- if (r < 0) +- return r; +- +- if (sd_id128_equal(*boot_id, SD_ID128_NULL)) { +- if (offset > (int) count || offset <= -(int)count) +- return -EADDRNOTAVAIL; +- +- *boot_id = all_ids[(offset <= 0)*count + offset - 1].id; +- } else { +- id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp); +- +- if (!id || +- offset <= 0 ? (id - all_ids) + offset < 0 : +- (id - all_ids) + offset >= (int) count) +- return -EADDRNOTAVAIL; +- +- *boot_id = (id + offset)->id; ++ i++; ++ free(id); + } + + return 0; +@@ -1007,6 +1074,7 @@ static int get_boot_id_by_offset(sd_journal *j, sd_id128_t *boot_id, int offset) + static int add_boot(sd_journal *j) { + char match[9+32+1] = "_BOOT_ID="; + int r; ++ boot_id_t ref_boot_id = {}; + + assert(j); + +@@ -1016,17 +1084,22 @@ static int add_boot(sd_journal *j) { + if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL)) + return add_match_this_boot(j, arg_machine); + +- r = get_boot_id_by_offset(j, &arg_boot_id, arg_boot_offset); +- if (r < 0) { +- if (sd_id128_equal(arg_boot_id, SD_ID128_NULL)) +- log_error_errno(r, "Failed to look up boot %+i: %m", arg_boot_offset); ++ ref_boot_id.id = arg_boot_id; ++ r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset); ++ assert(r <= 1); ++ if (r <= 0) { ++ const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); ++ ++ if (sd_id128_is_null(arg_boot_id)) ++ log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason); + else + log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s", +- SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r)); +- return r; ++ SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason); ++ ++ return r == 0 ? -ENODATA : r; + } + +- sd_id128_to_string(arg_boot_id, match + 9); ++ sd_id128_to_string(ref_boot_id.id, match + 9); + + r = sd_journal_add_match(j, match, sizeof(match) - 1); + if (r < 0) diff --git a/SOURCES/0211-test-hashmap-fix-an-assert.patch b/SOURCES/0211-test-hashmap-fix-an-assert.patch new file mode 100644 index 00000000..13170b6b --- /dev/null +++ b/SOURCES/0211-test-hashmap-fix-an-assert.patch @@ -0,0 +1,28 @@ +From 2c52141dcf9c1bc2445dde5265036abca7e5c2c7 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 19 May 2015 06:33:54 +0200 +Subject: [PATCH] test-hashmap: fix an assert + +CID#1299016 + +(cherry picked from commit b669934fae49c9158c35e612e54e1765edca8584) + +Cherry-picked from: b669934 +Resolves: #1222517 +--- + src/test/test-hashmap-plain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c +index 84b508f87..c1a5ccf1f 100644 +--- a/src/test/test-hashmap-plain.c ++++ b/src/test/test-hashmap-plain.c +@@ -682,7 +682,7 @@ static void test_hashmap_get2(void) { + r = hashmap_get2(m, key_orig, &key_copy); + assert_se(streq(r, val)); + assert_se(key_orig != key_copy); +- assert_se(streq(key_orig, key_orig)); ++ assert_se(streq(key_orig, key_copy)); + + r = hashmap_get2(m, "no such key", NULL); + assert_se(r == NULL); diff --git a/SOURCES/0212-units-make-sure-systemd-nspawn-.slice-instances-are-.patch b/SOURCES/0212-units-make-sure-systemd-nspawn-.slice-instances-are-.patch new file mode 100644 index 00000000..b8574b66 --- /dev/null +++ b/SOURCES/0212-units-make-sure-systemd-nspawn-.slice-instances-are-.patch @@ -0,0 +1,27 @@ +From 68932296f01cd3eee3ee47f3e8f339f33c18b95d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 19:47:52 +0200 +Subject: [PATCH] units: make sure systemd-nspawn@.slice instances are actually + located in machine.slice + +https://plus.google.com/112206451048767236518/posts/SYAueyXHeEX +(cherry picked from commit 45d383a3b888195b01b58dbd2c46a11027ff5022) + +Cherry-picked from: 45d383a +Resolves: #1222517 +--- + units/systemd-nspawn@.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in +index 3e26b53fd..5e8612113 100644 +--- a/units/systemd-nspawn@.service.in ++++ b/units/systemd-nspawn@.service.in +@@ -17,6 +17,7 @@ KillMode=mixed + Type=notify + RestartForceExitStatus=133 + SuccessExitStatus=133 ++Slice=machine.slice + Delegate=yes + + [Install] diff --git a/SOURCES/0213-Revert-journald-audit-exit-gracefully-in-the-case-we.patch b/SOURCES/0213-Revert-journald-audit-exit-gracefully-in-the-case-we.patch new file mode 100644 index 00000000..59b2d072 --- /dev/null +++ b/SOURCES/0213-Revert-journald-audit-exit-gracefully-in-the-case-we.patch @@ -0,0 +1,31 @@ +From d5e8f58887c572e3d9317b68999ca5d6320f2815 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 15 Jul 2015 14:52:04 +0200 +Subject: [PATCH] Revert "journald-audit: exit gracefully in the case we can't + join audit multicast group" + +This reverts commit 9b5e05005e534fc7fb6dc56c94e3296bb17fe122. + +Cherry-picked from: +Resolves: #1222517 +--- + src/journal/journald-audit.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c +index 77abe2e63..46eb82fa3 100644 +--- a/src/journal/journald-audit.c ++++ b/src/journal/journald-audit.c +@@ -533,10 +533,8 @@ int server_open_audit(Server *s) { + } + + r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl)); +- if (r < 0) { +- log_warning_errno(errno, "Failed to join audit multicast group, ignoring: %m"); +- return 0; +- } ++ if (r < 0) ++ return log_error_errno(errno, "Failed to join audit multicast group: %m"); + } else + fd_nonblock(s->audit_fd, 1); + diff --git a/SOURCES/0214-journald-handle-more-gracefully-when-bind-fails-on-a.patch b/SOURCES/0214-journald-handle-more-gracefully-when-bind-fails-on-a.patch new file mode 100644 index 00000000..575c51c1 --- /dev/null +++ b/SOURCES/0214-journald-handle-more-gracefully-when-bind-fails-on-a.patch @@ -0,0 +1,36 @@ +From a81ba5e1bfabf643e11fec41c1ce646874ae0df1 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 20 May 2015 14:37:21 +0200 +Subject: [PATCH] journald: handle more gracefully when bind() fails on audit + sockets + +(cherry picked from commit 417a7fdc418ec76cc4c321c9a07ec15c72b3ac7d) + +Cherry-picked from: 417a7fd +Resolves: #1222517 +--- + src/journal/journald-audit.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c +index 46eb82fa3..0e739a23a 100644 +--- a/src/journal/journald-audit.c ++++ b/src/journal/journald-audit.c +@@ -532,9 +532,14 @@ int server_open_audit(Server *s) { + return 0; + } + +- r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl)); +- if (r < 0) +- return log_error_errno(errno, "Failed to join audit multicast group: %m"); ++ if (bind(s->audit_fd, &sa.sa, sizeof(sa.nl)) < 0) { ++ log_warning_errno(errno, ++ "Failed to join audit multicast group. " ++ "The kernel is probably too old or multicast reading is not supported. " ++ "Ignoring: %m"); ++ s->audit_fd = safe_close(s->audit_fd); ++ return 0; ++ } + } else + fd_nonblock(s->audit_fd, 1); + diff --git a/SOURCES/0215-udev-link-config-fix-corruption.patch b/SOURCES/0215-udev-link-config-fix-corruption.patch new file mode 100644 index 00000000..4d667989 --- /dev/null +++ b/SOURCES/0215-udev-link-config-fix-corruption.patch @@ -0,0 +1,72 @@ +From f50fbeaf7c2ce57027f774d02d9e2b09f810ec2a Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 21 May 2015 15:22:07 +0200 +Subject: [PATCH] udev: link-config - fix corruption + +The parser used for MTU and Speed expects them to be size_t, not unsigned int. + +This caused a corruption in the rest of the structure. + +Reported by David O Neill . + +(cherry picked from commit dab495dc23bf9a5ba0487a057bb594355555a0e9) + +Cherry-picked from: dab495d +Resolves: #1222517 +--- + src/udev/net/link-config.c | 11 ++++++----- + src/udev/net/link-config.h | 4 ++-- + 2 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index 8b3dc45d4..489593f4f 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -177,6 +177,9 @@ static int load_link(link_config_ctx *ctx, const char *filename) { + else + log_debug("Parsed configuration file %s", filename); + ++ if (link->mtu > UINT_MAX || link->speed > UINT_MAX) ++ return -ERANGE; ++ + link->filename = strdup(filename); + + LIST_PREPEND(links, ctx->links, link); +@@ -379,10 +382,9 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, + if (!old_name) + return -EINVAL; + +- r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024, +- config->duplex); ++ r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex); + if (r < 0) +- log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m", ++ log_warning_errno(r, "Could not set speed or duplex of %s to %zu Mbps (%s): %m", + old_name, config->speed / 1024, + duplex_to_string(config->duplex)); + +@@ -461,8 +463,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, + mac = config->mac; + } + +- r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, +- config->mtu); ++ r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu); + if (r < 0) + return log_warning_errno(r, "Could not set Alias, MACAddress or MTU on %s: %m", old_name); + +diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h +index cb434d1ae..f2e917488 100644 +--- a/src/udev/net/link-config.h ++++ b/src/udev/net/link-config.h +@@ -67,8 +67,8 @@ struct link_config { + NamePolicy *name_policy; + char *name; + char *alias; +- unsigned int mtu; +- unsigned int speed; ++ size_t mtu; ++ size_t speed; + Duplex duplex; + WakeOnLan wol; + diff --git a/SOURCES/0216-udev-net_id-Only-read-the-first-64-bytes-of-PCI-conf.patch b/SOURCES/0216-udev-net_id-Only-read-the-first-64-bytes-of-PCI-conf.patch new file mode 100644 index 00000000..2c73bd6e --- /dev/null +++ b/SOURCES/0216-udev-net_id-Only-read-the-first-64-bytes-of-PCI-conf.patch @@ -0,0 +1,59 @@ +From 210ec6353d3cab2029e1eb160671fea918c97814 Mon Sep 17 00:00:00 2001 +From: "Jason S. McMullan" +Date: Fri, 22 May 2015 20:30:01 +0200 +Subject: [PATCH] udev/net_id: Only read the first 64 bytes of PCI config space + +The original code used fread(), which on some libc implementions +(ie glibc 2.17) would pre-read a full 4K (PAGE_SIZE) of the +PCI config space, when only 64 bytes were requested. + +I have recently come across PCIe hardware which responds with +Completion Timeouts when accesses above 256 bytes are attempted. + +This can cause server systems with GHES/AEPI support to cause +and immediate kernel panic due to the failed PCI transaction. + +This change replaces the buffered fread() with an explict +unbuffered read() of 64 bytes, which corrects this issue by +only reading the guaranteed first 64 bytes of PCIe config space. + +(cherry picked from commit 0454229c100a2113ba82df55703436d6cb2c492b) + +Cherry-picked from: 0454229 +Resolves: #1222517 +--- + src/udev/udev-builtin-net_id.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 66474f772..dd2886caf 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -91,6 +91,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -166,15 +167,15 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + + /* read the 256 bytes PCI configuration space to check the multi-function bit */ + static bool is_pci_multifunction(struct udev_device *dev) { +- _cleanup_fclose_ FILE *f = NULL; ++ _cleanup_close_ int fd = -1; + const char *filename; + uint8_t config[64]; + + filename = strjoina(udev_device_get_syspath(dev), "/config"); +- f = fopen(filename, "re"); +- if (!f) ++ fd = open(filename, O_RDONLY | O_CLOEXEC); ++ if (fd < 0) + return false; +- if (fread(&config, sizeof(config), 1, f) != 1) ++ if (read(fd, &config, sizeof(config)) != sizeof(config)) + return false; + + /* bit 0-6 header type, bit 7 multi/single function device */ diff --git a/SOURCES/0217-shared-generator-correct-path-to-systemd-fsck.patch b/SOURCES/0217-shared-generator-correct-path-to-systemd-fsck.patch new file mode 100644 index 00000000..717005a4 --- /dev/null +++ b/SOURCES/0217-shared-generator-correct-path-to-systemd-fsck.patch @@ -0,0 +1,44 @@ +From 36bc4ca74d03fcff5808a7efb107886749472819 Mon Sep 17 00:00:00 2001 +From: Mike Gilbert +Date: Sun, 24 May 2015 16:33:35 -0400 +Subject: [PATCH] shared: generator - correct path to systemd-fsck + +In generated systemd-fsck-root.service. This would break if rootprefix +is not /usr/lib/systemd. + +[tomegun: flesh out commit message] + +(cherry picked from commit 77eb82f9f0f60535ab5f585834ed6e66cf39b184) + +Cherry-picked from: 77eb82f +Resolves: #1222517 +--- + Makefile.am | 1 + + src/shared/generator.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index d3fb398fe..a81d3c131 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -177,6 +177,7 @@ AM_CPPFLAGS = \ + -DCATALOG_DATABASE=\"$(catalogstatedir)/database\" \ + -DSYSTEMD_CGROUP_AGENT_PATH=\"$(rootlibexecdir)/systemd-cgroups-agent\" \ + -DSYSTEMD_BINARY_PATH=\"$(rootlibexecdir)/systemd\" \ ++ -DSYSTEMD_FSCK_PATH=\"$(rootlibexecdir)/systemd-fsck\" \ + -DSYSTEMD_SHUTDOWN_BINARY_PATH=\"$(rootlibexecdir)/systemd-shutdown\" \ + -DSYSTEMD_SLEEP_BINARY_PATH=\"$(rootlibexecdir)/systemd-sleep\" \ + -DSYSTEMCTL_BINARY_PATH=\"$(rootbindir)/systemctl\" \ +diff --git a/src/shared/generator.c b/src/shared/generator.c +index 148a0b077..3af84a325 100644 +--- a/src/shared/generator.c ++++ b/src/shared/generator.c +@@ -61,7 +61,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" +- "ExecStart=/usr/lib/systemd/systemd-fsck %2$s\n" ++ "ExecStart=" SYSTEMD_FSCK_PATH " %2$s\n" + "TimeoutSec=0\n", + program_invocation_short_name, + what, diff --git a/SOURCES/0218-logind-Save-the-user-s-state-when-a-session-enters-S.patch b/SOURCES/0218-logind-Save-the-user-s-state-when-a-session-enters-S.patch new file mode 100644 index 00000000..7934dff3 --- /dev/null +++ b/SOURCES/0218-logind-Save-the-user-s-state-when-a-session-enters-S.patch @@ -0,0 +1,47 @@ +From a01e2476f0421026d12384292b34f303fc01c43c Mon Sep 17 00:00:00 2001 +From: Philip Withnall +Date: Tue, 2 Jun 2015 14:17:10 +0100 +Subject: [PATCH] =?UTF-8?q?logind:=20Save=20the=20user=E2=80=99s=20state?= + =?UTF-8?q?=20when=20a=20session=20enters=20SESSION=5FACTIVE?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When (for example) switching from X11 to a new VT and logging in there, +creating a new session, the user state file (/run/systemd/users/$uid) is +not updated after the session becomes active. The latest time it is +saved is when the session is in SESSION_OPENING. + +This results in a /run/systemd/users/$uid file which contains +STATE=online for the current user on the current active VT, which is +obviously wrong. + +As functions like sd_uid_get_state() use this file to get the user’s +state, this could result in things like PolicyKit making incorrect +decisions about the user’s state. (See +https://bugs.freedesktop.org/show_bug.cgi?id=76358.) + +Fix this by re-saving the state for a session’s user after completing +the state_job for that session. + +https://bugs.freedesktop.org/show_bug.cgi?id=90818 +(cherry picked from commit 41dfeaa194c18de49706b5cecf4e53accd12b7f6) + +Cherry-picked from: 41dfeaa +Resolves: #1222517 +--- + src/login/logind-dbus.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 8b0bafd49..fb84e92e5 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -2124,6 +2124,7 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b + session_jobs_reply(session, unit, result); + + session_save(session); ++ user_save(session->user); + session_add_to_gc_queue(session); + } + diff --git a/SOURCES/0219-small-fix-ru-translation.patch b/SOURCES/0219-small-fix-ru-translation.patch new file mode 100644 index 00000000..fc3c0af9 --- /dev/null +++ b/SOURCES/0219-small-fix-ru-translation.patch @@ -0,0 +1,44 @@ +From 376e273fd9efb41fbeefc1e273fb4bd69135d041 Mon Sep 17 00:00:00 2001 +From: kloun +Date: Thu, 4 Jun 2015 17:56:59 +0300 +Subject: [PATCH] small fix ru translation + +(cherry picked from commit fcf3f5958e0441c9cc00f035ef6c86c278442366) + +Cherry-picked from: fcf3f59 +Resolves: #1222517 +--- + catalog/systemd.ru.catalog | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/catalog/systemd.ru.catalog b/catalog/systemd.ru.catalog +index f99532469..03eea04c9 100644 +--- a/catalog/systemd.ru.catalog ++++ b/catalog/systemd.ru.catalog +@@ -81,7 +81,7 @@ Documentation: man:core(5) + Записан дамп памяти. + + Вероятно, это произошло из-за ошибки, допущенной в коде программы. +-Рекомендуется сообщить ее разработчикам о возникшей проблеме. ++Рекомендуется сообщить её разработчикам о возникшей проблеме. + + # Subject: A new session @SESSION_ID@ has been created for user @USER_ID@ + -- 8d45620c1a4348dbb17410da57c60c66 +@@ -146,7 +146,7 @@ Defined-By: systemd + Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + + Все системные службы, запуск которых предписан настройками, были запущены. +-Впрочем, это еще не означает, что система в данный момент ничем не занята, ++Впрочем, это ещё не означает, что система в данный момент ничем не занята, + так как некоторые службы могут продолжать инициализацию даже после того, как + отчитались о своем запуске. + +@@ -274,7 +274,7 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + столбце файла /etc/fstab, либо в параметре Where= файла конфигурации юнита), + не является пустым. Это никак не мешает монтированию, однако ранее находившиеся + в нем файлы будут недоступны. Чтобы получить к ним доступ, вы можете вручную +-перемонтировать нижележащую файловую систему в другую точку. ++перемонтировать эту файловую систему в другую точку. + + # Subject: A virtual machine or container has been started + -- 24d8d4452573402496068381a6312df2 diff --git a/SOURCES/0220-kmod-setup-don-t-warn-when-ipv6-can-t-be-loaded.patch b/SOURCES/0220-kmod-setup-don-t-warn-when-ipv6-can-t-be-loaded.patch new file mode 100644 index 00000000..50a966e1 --- /dev/null +++ b/SOURCES/0220-kmod-setup-don-t-warn-when-ipv6-can-t-be-loaded.patch @@ -0,0 +1,33 @@ +From 7076491959d3e67f339a520dcdfb824a46ff5ccb Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 5 Jun 2015 14:59:36 +0200 +Subject: [PATCH] kmod-setup: don't warn when ipv6 can't be loaded + +Not having IPv6 is a valid setup. Let's not print a warning in that +case. + +Addresses: + + https://bugs.freedesktop.org/show_bug.cgi?id=87475 + +(cherry picked from commit b4aa82f168913b7bff42017023b43933b3aa0d24) + +Cherry-picked from: b4aa82f +Resolves: #1222517 +--- + src/core/kmod-setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c +index 97f3b9b34..6b2f29585 100644 +--- a/src/core/kmod-setup.c ++++ b/src/core/kmod-setup.c +@@ -66,7 +66,7 @@ int kmod_setup(void) { + { "autofs4", "/sys/class/misc/autofs", true, NULL }, + + /* early configure of ::1 on the loopback device */ +- { "ipv6", "/sys/module/ipv6", true, NULL }, ++ { "ipv6", "/sys/module/ipv6", false, NULL }, + + /* this should never be a module */ + { "unix", "/proc/net/unix", true, NULL }, diff --git a/SOURCES/0221-Partially-revert-ma-setup-simplify.patch b/SOURCES/0221-Partially-revert-ma-setup-simplify.patch new file mode 100644 index 00000000..7adc24d7 --- /dev/null +++ b/SOURCES/0221-Partially-revert-ma-setup-simplify.patch @@ -0,0 +1,67 @@ +From 21559c09b39155d44f8997703a35211623a38689 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 1 Jun 2015 10:33:48 -0400 +Subject: [PATCH] Partially revert "ma-setup: simplify" + +copy_bytes() tries to do the write in chunks, but ima kernel code +needs every rule to be written in one write. Writing the whole file +at once avoids the issue. + +http://lists.freedesktop.org/archives/systemd-devel/2015-June/032623.html +http://sourceforge.net/p/linux-ima/mailman/message/34145236/ +https://bugzilla.redhat.com/show_bug.cgi?id=1226948 +(cherry picked from commit 116b6c8687e1da25fcecf80ba6ac16866e308d50) + +Cherry-picked from: 116b6c8 +Resolves: #1222517 +--- + src/core/ima-setup.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c +index 0e0d16a7c..1d4acfa3b 100644 +--- a/src/core/ima-setup.c ++++ b/src/core/ima-setup.c +@@ -27,9 +27,10 @@ + #include + #include + #include ++#include ++#include + + #include "ima-setup.h" +-#include "copy.h" + #include "util.h" + #include "log.h" + +@@ -42,6 +43,8 @@ int ima_setup(void) { + + #ifdef HAVE_IMA + _cleanup_close_ int policyfd = -1, imafd = -1; ++ struct stat st; ++ char *policy; + + if (access(IMA_SECFS_DIR, F_OK) < 0) { + log_debug("IMA support is disabled in the kernel, ignoring."); +@@ -66,12 +69,20 @@ int ima_setup(void) { + return 0; + } + +- r = copy_bytes(policyfd, imafd, (off_t) -1, false); ++ if (fstat(policyfd, &st) < 0) ++ return log_error_errno(errno, "Failed to fstat "IMA_POLICY_PATH": %m"); ++ ++ policy = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, policyfd, 0); ++ if (policy == MAP_FAILED) ++ return log_error_errno(errno, "Failed to mmap "IMA_POLICY_PATH": %m"); ++ ++ r = loop_write(imafd, policy, (size_t) st.st_size, false); + if (r < 0) + log_error_errno(r, "Failed to load the IMA custom policy file "IMA_POLICY_PATH": %m"); + else + log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH"."); + ++ munmap(policy, st.st_size); + #endif /* HAVE_IMA */ + return r; + } diff --git a/SOURCES/0222-ima-setup-write-policy-one-line-at-a-time.patch b/SOURCES/0222-ima-setup-write-policy-one-line-at-a-time.patch new file mode 100644 index 00000000..ba92b4da --- /dev/null +++ b/SOURCES/0222-ima-setup-write-policy-one-line-at-a-time.patch @@ -0,0 +1,94 @@ +From 877774af9162dde25e314ff99a427dd28435c26a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 10 Jun 2015 15:19:03 -0400 +Subject: [PATCH] ima-setup: write policy one line at a time + +ima_write_policy() expects data to be written as one or more +rules, no more than PAGE_SIZE at a time. Easiest way to ensure +that we are not splitting rules is to read and write one line at +a time. + +https://bugzilla.redhat.com/show_bug.cgi?id=1226948 +(cherry picked from commit 92994160afa888255a7ede525dd16e3f1e2ed10d) + +Cherry-picked from: 9299416 +Resolves: #1222517 +--- + src/core/ima-setup.c | 41 +++++++++++++++++------------------------ + 1 file changed, 17 insertions(+), 24 deletions(-) + +diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c +index 1d4acfa3b..81ce2cda9 100644 +--- a/src/core/ima-setup.c ++++ b/src/core/ima-setup.c +@@ -24,11 +24,6 @@ + #include + #include + #include +-#include +-#include +-#include +-#include +-#include + + #include "ima-setup.h" + #include "util.h" +@@ -39,20 +34,19 @@ + #define IMA_POLICY_PATH "/etc/ima/ima-policy" + + int ima_setup(void) { +- int r = 0; +- + #ifdef HAVE_IMA +- _cleanup_close_ int policyfd = -1, imafd = -1; +- struct stat st; +- char *policy; ++ _cleanup_fclose_ FILE *input = NULL; ++ _cleanup_close_ int imafd = -1; ++ unsigned lineno = 0; ++ char line[page_size()]; + + if (access(IMA_SECFS_DIR, F_OK) < 0) { + log_debug("IMA support is disabled in the kernel, ignoring."); + return 0; + } + +- policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC); +- if (policyfd < 0) { ++ input = fopen(IMA_POLICY_PATH, "re"); ++ if (!input) { + log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, + "Failed to open the IMA custom policy file "IMA_POLICY_PATH", ignoring: %m"); + return 0; +@@ -69,20 +63,19 @@ int ima_setup(void) { + return 0; + } + +- if (fstat(policyfd, &st) < 0) +- return log_error_errno(errno, "Failed to fstat "IMA_POLICY_PATH": %m"); ++ FOREACH_LINE(line, input, ++ return log_error_errno(errno, "Failed to read the IMA custom policy file "IMA_POLICY_PATH": %m")) { ++ size_t len; + +- policy = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, policyfd, 0); +- if (policy == MAP_FAILED) +- return log_error_errno(errno, "Failed to mmap "IMA_POLICY_PATH": %m"); ++ len = strlen(line); ++ lineno++; + +- r = loop_write(imafd, policy, (size_t) st.st_size, false); +- if (r < 0) +- log_error_errno(r, "Failed to load the IMA custom policy file "IMA_POLICY_PATH": %m"); +- else +- log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH"."); ++ if (len > 0 && write(imafd, line, len) < 0) ++ return log_error_errno(errno, "Failed to load the IMA custom policy file "IMA_POLICY_PATH"%u: %m", ++ lineno); ++ } + +- munmap(policy, st.st_size); ++ log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH"."); + #endif /* HAVE_IMA */ +- return r; ++ return 0; + } diff --git a/SOURCES/0223-ata_id-unbotch-format-specifier.patch b/SOURCES/0223-ata_id-unbotch-format-specifier.patch new file mode 100644 index 00000000..902564c6 --- /dev/null +++ b/SOURCES/0223-ata_id-unbotch-format-specifier.patch @@ -0,0 +1,34 @@ +From b2aa96a5e92762adaff127227338fe5034175fcd Mon Sep 17 00:00:00 2001 +From: Jan Engelhardt +Date: Wed, 24 Jun 2015 01:48:18 +0200 +Subject: [PATCH] ata_id: unbotch format specifier + +Commit v218-247-g11c6f69 broke the output of the utility. "%1$" PRIu64 +"x" expands to "%1$lux", essentially "%lux", which shows the problem. +u and x cannot be combined, u wins as the type character, and x gets +emitted verbatim to stdout. + +References: https://bugzilla.redhat.com/show_bug.cgi?id=1227503 +(cherry picked from commit ec62e858734a66130f68d036c55c2050bde1e52e) + +Cherry-picked from: ec62e85 +Resolves: #1222517 +--- + src/udev/ata_id/ata_id.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c +index 9e4f674a9..b6f28c6f5 100644 +--- a/src/udev/ata_id/ata_id.c ++++ b/src/udev/ata_id/ata_id.c +@@ -639,8 +639,8 @@ int main(int argc, char *argv[]) + */ + word = identify.wyde[108]; + if ((word & 0xf000) == 0x5000) +- printf("ID_WWN=0x%1$"PRIu64"x\n" +- "ID_WWN_WITH_EXTENSION=0x%1$"PRIu64"x\n", ++ printf("ID_WWN=0x%1$" PRIx64 "\n" ++ "ID_WWN_WITH_EXTENSION=0x%1$" PRIx64 "\n", + identify.octa[108/4]); + + /* from Linux's include/linux/ata.h */ diff --git a/SOURCES/0224-install-explicitly-return-0-on-success.patch b/SOURCES/0224-install-explicitly-return-0-on-success.patch new file mode 100644 index 00000000..8fb15c18 --- /dev/null +++ b/SOURCES/0224-install-explicitly-return-0-on-success.patch @@ -0,0 +1,35 @@ +From c086e8c91b0dc455bfa5fa09f3f5aa20c582b2a0 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 25 Jun 2015 16:06:40 +0200 +Subject: [PATCH] install: explicitly return 0 on success + +Maybe there is some left-over value stored in r from previous function +call. Let's make sure we always return consistent error code when we reach end of +the function body. + +Fixes following crash of test-install, + +Assertion 'r == 0' failed at src/test/test-install.c:52, function main(). Aborting. +[1] 11703 abort (core dumped) ./test-install + +(cherry picked from commit 77cd2c87a47c49aa9063fbaa4d9077f4a381cab1) + +Cherry-picked from: 77cd2c8 +Resolves: #1222517 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index b62065be5..aa197e91b 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2265,7 +2265,7 @@ int unit_file_get_list( + } + } + +- return r; ++ return 0; + } + + static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { diff --git a/SOURCES/0225-systemd.service.xml-document-that-systemd-removes-th.patch b/SOURCES/0225-systemd.service.xml-document-that-systemd-removes-th.patch new file mode 100644 index 00000000..a1a653e9 --- /dev/null +++ b/SOURCES/0225-systemd.service.xml-document-that-systemd-removes-th.patch @@ -0,0 +1,30 @@ +From 7dbfc725ccbdcdf33aa46f97a68275fbd5f936c5 Mon Sep 17 00:00:00 2001 +From: Felipe Sateler +Date: Sat, 27 Jun 2015 17:25:06 -0300 +Subject: [PATCH] systemd.service.xml: document that systemd removes the + PIDFile + +(cherry picked from commit 341db20b7e98199003b4ce6aa52b339757828204) + +Cherry-picked from: 341db20 +Resolves: #1222517 +--- + man/systemd.service.xml | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index f59870563..a274db480 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -226,7 +226,10 @@ + services where Type= is set to + . systemd will read the PID of the + main process of the daemon after start-up of the service. +- systemd will not write to the file configured here. ++ systemd will not write to the file configured here, although ++ it will remove the file after the service has shut down if it ++ still exists. ++ + + + diff --git a/SOURCES/0226-core-handle-log-target-null-when-calling-systemd-shu.patch b/SOURCES/0226-core-handle-log-target-null-when-calling-systemd-shu.patch new file mode 100644 index 00000000..95faaa2c --- /dev/null +++ b/SOURCES/0226-core-handle-log-target-null-when-calling-systemd-shu.patch @@ -0,0 +1,31 @@ +From ce82f7886b2326a507d523dcf459be4ab7fd8eb1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Iago=20L=C3=B3pez=20Galeiras?= +Date: Tue, 30 Jun 2015 15:08:49 +0200 +Subject: [PATCH] core: handle --log-target=null when calling systemd-shutdown + +When shutting down, if systemd was started with --log-target=null, +systemd-shutdown was being called with --log-target=console. + +(cherry picked from commit 10f00ff17b9c9b55dc77c99797d27cb819fa5fdf) + +Cherry-picked from: 10f00ff +Resolves: #1222517 +--- + src/core/main.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/core/main.c b/src/core/main.c +index fd527d4d6..1c8d67dac 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -2001,6 +2001,10 @@ finish: + command_line[pos++] = "kmsg"; + break; + ++ case LOG_TARGET_NULL: ++ command_line[pos++] = "null"; ++ break; ++ + case LOG_TARGET_CONSOLE: + default: + command_line[pos++] = "console"; diff --git a/SOURCES/0227-man-ProtectHome-protects-root-as-well.patch b/SOURCES/0227-man-ProtectHome-protects-root-as-well.patch new file mode 100644 index 00000000..9ca73719 --- /dev/null +++ b/SOURCES/0227-man-ProtectHome-protects-root-as-well.patch @@ -0,0 +1,30 @@ +From 421fa6e97928bca5a55414ad38bd9659d0e99a15 Mon Sep 17 00:00:00 2001 +From: Christian Hesse +Date: Tue, 30 Jun 2015 19:12:20 +0200 +Subject: [PATCH] man: ProtectHome= protects /root as well + +(cherry picked from commit 5833143708733a3fc9e6935922bf11d7d27cb768) + +Cherry-picked from: 5833143 +Resolves: #1222517 +--- + man/systemd.exec.xml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 56b53e601..5b93aa71e 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -858,9 +858,10 @@ + + Takes a boolean argument or + read-only. If true, the directories +- /home and /run/user ++ /home, /root and ++ /run/user + are made inaccessible and empty for processes invoked by this +- unit. If set to read-only, the two ++ unit. If set to read-only, the three + directories are made read-only instead. It is recommended to + enable this setting for all long-running services (in + particular network-facing ones), to ensure they cannot get diff --git a/SOURCES/0228-timedatectl-trim-non-local-RTC-warning-to-80-chars-w.patch b/SOURCES/0228-timedatectl-trim-non-local-RTC-warning-to-80-chars-w.patch new file mode 100644 index 00000000..4ba38fec --- /dev/null +++ b/SOURCES/0228-timedatectl-trim-non-local-RTC-warning-to-80-chars-w.patch @@ -0,0 +1,35 @@ +From 205750e2144e942bb6c04bb901684cc1aea82a26 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Vedran=20Mileti=C4=87?= +Date: Thu, 2 Jul 2015 00:13:31 +0200 +Subject: [PATCH] timedatectl: trim non-local RTC warning to 80 chars wide + +(cherry picked from commit ab59f4123a6f9c32953e522cc9afc5fc610d59ca) + +Cherry-picked from: ab59f41 +Resolves: #1222517 +--- + src/timedate/timedatectl.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c +index 4d8988673..1accccb68 100644 +--- a/src/timedate/timedatectl.c ++++ b/src/timedate/timedatectl.c +@@ -190,11 +190,12 @@ static void print_status_info(const StatusInfo *i) { + + if (i->rtc_local) + fputs("\n" ANSI_HIGHLIGHT_ON +- "Warning: The system is configured to read the RTC time in the local time zone. This\n" +- " mode can not be fully supported. It will create various problems with time\n" +- " zone changes and daylight saving time adjustments. The RTC time is never updated,\n" +- " it relies on external facilities to maintain it. If at all possible, use\n" +- " RTC in UTC by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout); ++ "Warning: The system is configured to read the RTC time in the local time zone.\n" ++ " This mode can not be fully supported. It will create various problems\n" ++ " with time zone changes and daylight saving time adjustments. The RTC\n" ++ " time is never updated, it relies on external facilities to maintain it.\n" ++ " If at all possible, use RTC in UTC by calling\n" ++ " 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout); + } + + static int show_status(sd_bus *bus, char **args, unsigned n) { diff --git a/SOURCES/0229-escape-fix-exit-code.patch b/SOURCES/0229-escape-fix-exit-code.patch new file mode 100644 index 00000000..da366673 --- /dev/null +++ b/SOURCES/0229-escape-fix-exit-code.patch @@ -0,0 +1,26 @@ +From 3eb63550d4222d9edd6ed2d257b8b03eff65fd24 Mon Sep 17 00:00:00 2001 +From: Michael Marineau +Date: Wed, 1 Jul 2015 23:46:42 -0700 +Subject: [PATCH] escape: fix exit code + +r == 0 indicates success, not failure + +(cherry picked from commit ff9c82cc399c37dd3d3fad4ec116b33c9efe70ea) + +Cherry-picked from: ff9c82c +Resolves: #1222517 +--- + src/escape/escape.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/escape/escape.c b/src/escape/escape.c +index f2a072186..766a2c2c6 100644 +--- a/src/escape/escape.c ++++ b/src/escape/escape.c +@@ -232,5 +232,5 @@ int main(int argc, char *argv[]) { + fputc('\n', stdout); + + finish: +- return r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + } diff --git a/SOURCES/0230-man-information-about-available-properties.patch b/SOURCES/0230-man-information-about-available-properties.patch new file mode 100644 index 00000000..2987ae79 --- /dev/null +++ b/SOURCES/0230-man-information-about-available-properties.patch @@ -0,0 +1,54 @@ +From 285bd714e050c189f6e5e9aa6b59173997ae550e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 29 Jun 2015 20:19:56 -0400 +Subject: [PATCH] man: information about available properties + +https://bugzilla.redhat.com/show_bug.cgi?id=1144496 +(cherry picked from commit ea539eb65950bea7a9734424e660ef84f6f30e6c) + +Cherry-picked from: ea539eb +Resolves: #1222517 +--- + man/systemctl.xml | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 44ec0d7bc..6b29b8cd0 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -111,12 +111,30 @@ + + + When showing unit/job/manager properties with the +- show command, limit display to certain +- properties as specified as argument. If not specified, all +- set properties are shown. The argument should be a ++ show command, limit display to properties ++ specified in the argument. The argument should be a + comma-separated list of property names, such as +- MainPID. If specified more than once, all +- properties with the specified names are shown. ++ MainPID. Unless specified, all known ++ properties are shown. If specified more than once, all ++ properties with the specified names are shown. Shell ++ completion is implemented for property names. ++ ++ For the manager itself, ++ systemctl show will show all available ++ properties. Those properties are documented in ++ systemd-system.conf5. ++ ++ ++ Properties for units vary by unit type, so showing any ++ unit (even a non-existent one) is a way to list properties ++ pertaining to this type. Similarly showing any job will list ++ properties pertaining to all jobs. Properties for units are ++ documented in ++ systemd.unit5, ++ and the pages for individual unit types ++ systemd.service5, ++ systemd.socket5, ++ etc. + + + diff --git a/SOURCES/0231-journal-in-persistent-mode-create-var-log-journal-wi.patch b/SOURCES/0231-journal-in-persistent-mode-create-var-log-journal-wi.patch new file mode 100644 index 00000000..45a5e2a5 --- /dev/null +++ b/SOURCES/0231-journal-in-persistent-mode-create-var-log-journal-wi.patch @@ -0,0 +1,36 @@ +From c9c9111ad96ab8827a8866f80adbacf4f58e055e Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 3 Jul 2015 11:34:12 +0100 +Subject: [PATCH] journal: in persistent mode create /var/log/journal, with all + parents. + +systemd-journald races with systemd-tmpfiles-setup, and hence both are +started at about the same time. On a bare-bones system (e.g. with +empty /var, or even non-existent /var), systemd-tmpfiles will create +/var/log. But it can happen too late, that is systemd-journald already +attempted to mkdir /var/log/journal, ignoring the error. Thus failing +to create /var/log/journal. One option, without modifiying the +dependency graph is to create /var/log/journal directory with parents, +when persistent storage has been requested. + +(cherry picked from commit ac892057c2ddd8f06323c73ebd80423cc3ec7190) + +Cherry-picked from: ac89205 +Resolves: #1222517 +--- + 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 04839c950..d692c06ef 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -942,7 +942,7 @@ static int system_journal_open(Server *s, bool flush_requested) { + * the machine path */ + + if (s->storage == STORAGE_PERSISTENT) +- (void) mkdir("/var/log/journal/", 0755); ++ (void) mkdir_p("/var/log/journal/", 0755); + + fn = strjoina("/var/log/journal/", ids); + (void) mkdir(fn, 0755); diff --git a/SOURCES/0232-sysv-generator-fix-wrong-Overwriting-existing-symlin.patch b/SOURCES/0232-sysv-generator-fix-wrong-Overwriting-existing-symlin.patch new file mode 100644 index 00000000..84b2206f --- /dev/null +++ b/SOURCES/0232-sysv-generator-fix-wrong-Overwriting-existing-symlin.patch @@ -0,0 +1,75 @@ +From c59c376b2623330a70ab692844ca00eb58f67576 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Thu, 19 Feb 2015 11:06:24 +0100 +Subject: [PATCH] sysv-generator: fix wrong "Overwriting existing symlink" + warnings + +Fix result testing of is_symlink() to ignore negative results, which happen if +the file name does not exist at all. In this case we do not want a warning and +unlink the non-existing link. + +https://bugs.debian.org/778700 +(cherry picked from commit 4e5589836c9e143796c3f3d81e67ab7a9209e2b0) + +Apparently this was missed for some reason and did not end up in +stable previously. + +Cherry-picked from: 4e55898 +Resolves: #1222517 +--- + src/sysv-generator/sysv-generator.c | 2 +- + test/sysv-generator-test.py | 7 +++++++ + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index cfc4a99e4..3c6cb8f10 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -166,7 +166,7 @@ static int generate_unit_file(SysvStub *s) { + /* We might already have a symlink with the same name from a Provides:, + * or from backup files like /etc/init.d/foo.bak. Real scripts always win, + * so remove an existing link */ +- if (is_symlink(unit)) { ++ if (is_symlink(unit) > 0) { + log_warning("Overwriting existing symlink %s with real service", unit); + (void) unlink(unit); + } +diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py +index 509899e0a..e716d705c 100644 +--- a/test/sysv-generator-test.py ++++ b/test/sysv-generator-test.py +@@ -178,6 +178,8 @@ class SysvGeneratorTest(unittest.TestCase): + self.assertEqual(s.get('Service', 'ExecStop'), + '%s stop' % init_script) + ++ self.assertNotIn('Overwriting', err) ++ + def test_simple_enabled_all(self): + '''simple service without dependencies, enabled in all runlevels''' + +@@ -185,6 +187,7 @@ class SysvGeneratorTest(unittest.TestCase): + err, results = self.run_generator() + self.assertEqual(list(results), ['foo.service']) + self.assert_enabled('foo.service', [2, 3, 4, 5]) ++ self.assertNotIn('Overwriting', err) + + def test_simple_enabled_some(self): + '''simple service without dependencies, enabled in some runlevels''' +@@ -270,6 +273,7 @@ class SysvGeneratorTest(unittest.TestCase): + for f in ['bar.service', 'baz.service']: + self.assertEqual(os.readlink(os.path.join(self.out_dir, f)), + 'foo.service') ++ self.assertNotIn('Overwriting', err) + + def test_same_provides_in_multiple_scripts(self): + '''multiple init.d scripts provide the same name''' +@@ -289,6 +293,9 @@ class SysvGeneratorTest(unittest.TestCase): + self.add_sysv('bar', {'Provides': 'bar'}, enable=True) + err, results = self.run_generator() + self.assertEqual(sorted(results), ['bar.service', 'foo.service']) ++ # we do expect an overwrite here, bar.service should overwrite the ++ # alias link from foo.service ++ self.assertIn('Overwriting', err) + + def test_nonexecutable_script(self): + '''ignores non-executable init.d script''' diff --git a/SOURCES/0233-mount-don-t-claim-a-device-is-gone-from-proc-self-mo.patch b/SOURCES/0233-mount-don-t-claim-a-device-is-gone-from-proc-self-mo.patch new file mode 100644 index 00000000..7378faaa --- /dev/null +++ b/SOURCES/0233-mount-don-t-claim-a-device-is-gone-from-proc-self-mo.patch @@ -0,0 +1,92 @@ +From 6b8fedd82c23f1d8c334c3081a1befebedc40f1f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 13:50:36 +0200 +Subject: [PATCH] mount: don't claim a device is gone from /proc/self/mountinfo + before it is gone from *all* lines + +Devices might be referenced by multiple mount points in +/proc/self/mountinfo, hence we should consider them unmounted only after +they disappeared from all lines, not just from one. + +http://lists.freedesktop.org/archives/systemd-devel/2015-May/032026.html +(cherry picked from commit fcd8b266edf0df2b85079fcf7b099cd4028740e6) + +Cherry-picked from: +Resolves: #1222517 +--- + src/core/mount.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index fd4fb6f1b..fa63f2426 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1698,7 +1698,10 @@ fail: + } + + static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++ _cleanup_set_free_ Set *around = NULL, *gone = NULL; + Manager *m = userdata; ++ const char *what; ++ Iterator i; + Unit *u; + int r; + +@@ -1765,6 +1768,8 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + + if (!mount->is_mounted) { + ++ /* A mount point is gone */ ++ + mount->from_proc_self_mountinfo = false; + + switch (mount->state) { +@@ -1780,13 +1785,17 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + break; + } + +- if (mount->parameters_proc_self_mountinfo.what) +- (void) device_found_node(m, mount->parameters_proc_self_mountinfo.what, false, DEVICE_FOUND_MOUNT, true); ++ /* Remember that this device might just have disappeared */ ++ if (mount->parameters_proc_self_mountinfo.what) { + ++ if (set_ensure_allocated(&gone, &string_hash_ops) < 0 || ++ set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0) ++ log_oom(); /* we don't care too much about OOM here... */ ++ } + + } else if (mount->just_mounted || mount->just_changed) { + +- /* New or changed mount entry */ ++ /* A mount point was added or changed */ + + switch (mount->state) { + +@@ -1811,12 +1820,27 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + mount_set_state(mount, mount->state); + break; + } ++ ++ if (mount->parameters_proc_self_mountinfo.what) { ++ ++ if (set_ensure_allocated(&around, &string_hash_ops) < 0 || ++ set_put(around, mount->parameters_proc_self_mountinfo.what) < 0) ++ log_oom(); ++ } + } + + /* Reset the flags for later calls */ + mount->is_mounted = mount->just_mounted = mount->just_changed = false; + } + ++ SET_FOREACH(what, gone, i) { ++ if (set_contains(around, what)) ++ continue; ++ ++ /* Let the device units know that the device is no longer mounted */ ++ (void) device_found_node(m, what, false, DEVICE_FOUND_MOUNT, true); ++ } ++ + return 0; + } + diff --git a/SOURCES/0234-mount-properly-check-for-mounts-currently-in-proc-se.patch b/SOURCES/0234-mount-properly-check-for-mounts-currently-in-proc-se.patch new file mode 100644 index 00000000..a7d8fe5f --- /dev/null +++ b/SOURCES/0234-mount-properly-check-for-mounts-currently-in-proc-se.patch @@ -0,0 +1,75 @@ +From 602786c9171d189e859796fd61873835fe858a06 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 17:19:27 +0200 +Subject: [PATCH] mount: properly check for mounts currently in + /proc/self/mountinfo + +http://lists.freedesktop.org/archives/systemd-devel/2015-May/032059.html +(cherry picked from commit 394763f63c1941cafd9d3bf81e8151a2206474a7) + +Cherry-picked from: 394763f +Resolves: #1222517 +--- + src/core/mount.c | 33 +++++++++++++++++++-------------- + 1 file changed, 19 insertions(+), 14 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index fa63f2426..1f1a41ab6 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1768,7 +1768,18 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + + if (!mount->is_mounted) { + +- /* A mount point is gone */ ++ /* A mount point is not around right now. It ++ * might be gone, or might never have ++ * existed. */ ++ ++ if (mount->from_proc_self_mountinfo && ++ mount->parameters_proc_self_mountinfo.what) { ++ ++ /* Remember that this device might just have disappeared */ ++ if (set_ensure_allocated(&gone, &string_hash_ops) < 0 || ++ set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0) ++ log_oom(); /* we don't care too much about OOM here... */ ++ } + + mount->from_proc_self_mountinfo = false; + +@@ -1785,14 +1796,6 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + break; + } + +- /* Remember that this device might just have disappeared */ +- if (mount->parameters_proc_self_mountinfo.what) { +- +- if (set_ensure_allocated(&gone, &string_hash_ops) < 0 || +- set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0) +- log_oom(); /* we don't care too much about OOM here... */ +- } +- + } else if (mount->just_mounted || mount->just_changed) { + + /* A mount point was added or changed */ +@@ -1820,13 +1823,15 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, + mount_set_state(mount, mount->state); + break; + } ++ } + +- if (mount->parameters_proc_self_mountinfo.what) { ++ if (mount->is_mounted && ++ mount->from_proc_self_mountinfo && ++ mount->parameters_proc_self_mountinfo.what) { + +- if (set_ensure_allocated(&around, &string_hash_ops) < 0 || +- set_put(around, mount->parameters_proc_self_mountinfo.what) < 0) +- log_oom(); +- } ++ if (set_ensure_allocated(&around, &string_hash_ops) < 0 || ++ set_put(around, mount->parameters_proc_self_mountinfo.what) < 0) ++ log_oom(); + } + + /* Reset the flags for later calls */ diff --git a/SOURCES/0235-units-add-Install-section-to-tmp.mount.patch b/SOURCES/0235-units-add-Install-section-to-tmp.mount.patch new file mode 100644 index 00000000..79ac5ab5 --- /dev/null +++ b/SOURCES/0235-units-add-Install-section-to-tmp.mount.patch @@ -0,0 +1,26 @@ +From 6e9187c22c22872e8b0ade7a0e5603895797ede2 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Fri, 15 Feb 2013 09:07:57 +0100 +Subject: [PATCH] units: add [Install] section to tmp.mount + +Change-Id: I2e6d129de00a9afaf7558006c886866f64394c29 +Related: #908253 + +Cherry-picked from: b4aeab33 +Resolves: #1199644 +--- + units/tmp.mount | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/units/tmp.mount b/units/tmp.mount +index 00a0d2872..af0cf4a55 100644 +--- a/units/tmp.mount ++++ b/units/tmp.mount +@@ -19,3 +19,7 @@ What=tmpfs + Where=/tmp + Type=tmpfs + Options=mode=1777,strictatime ++ ++# Make 'systemctl enable tmp.mount' work: ++[Install] ++WantedBy=local-fs.target diff --git a/SOURCES/0236-bus-util-add-articles-to-explanation-messages.patch b/SOURCES/0236-bus-util-add-articles-to-explanation-messages.patch new file mode 100644 index 00000000..d802365c --- /dev/null +++ b/SOURCES/0236-bus-util-add-articles-to-explanation-messages.patch @@ -0,0 +1,52 @@ +From 18b5e1630c73438a262fea9dd76bc3e67b250335 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 11 Apr 2015 19:39:30 -0400 +Subject: [PATCH] bus-util: add articles to explanation messages + +We are talking about one member of a group of things (resource limits, signals, +timeouts), without specifying which one. An indenfinite article is in order. + +When we are talking about the control process, it's a specific one, so the +definite article is used. + +Cherry-picked from: a61cc46 +Related: #1016680 +--- + src/libsystemd/sd-bus/bus-util.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index fff00d9f9..017fbaf2a 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1714,13 +1714,13 @@ static int bus_job_get_service_result(BusWaitForJobs *d, char **result) { + static const struct { + const char *result, *explanation; + } explanations [] = { +- { "resources", "configured resource limit was exceeded" }, +- { "timeout", "timeout was exceeded" }, +- { "exit-code", "control process exited with error code" }, +- { "signal", "fatal signal was delivered to the control process" }, +- { "core-dump", "fatal signal was delivered to the control process. Core dumped" }, +- { "watchdog", "service failed to send watchdog ping" }, +- { "start-limit", "start of the service was attempted too often too quickly" } ++ { "resources", "a configured resource limit was exceeded" }, ++ { "timeout", "a timeout was exceeded" }, ++ { "exit-code", "the control process exited with error code" }, ++ { "signal", "a fatal signal was delivered to the control process" }, ++ { "core-dump", "a fatal signal was delivered causing the control process to dump core" }, ++ { "watchdog", "the service failed to send watchdog ping" }, ++ { "start-limit", "start of the service was attempted too often" } + }; + + static void log_job_error_with_service_result(const char* service, const char *result) { +@@ -1748,8 +1748,7 @@ static void log_job_error_with_service_result(const char* service, const char *r + + /* For some results maybe additional explanation is required */ + if (streq_ptr(result, "start-limit")) +- log_info("To force a start please invoke \"systemctl reset-failed %s\" followed by \"systemctl start %s\" again.", +- strna(service_shell_quoted), ++ log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.", + strna(service_shell_quoted)); + } + diff --git a/SOURCES/0237-bus-util-print-correct-warnings-for-units-that-fail-.patch b/SOURCES/0237-bus-util-print-correct-warnings-for-units-that-fail-.patch new file mode 100644 index 00000000..781ef431 --- /dev/null +++ b/SOURCES/0237-bus-util-print-correct-warnings-for-units-that-fail-.patch @@ -0,0 +1,65 @@ +From caff38650c2c1ae9244a30b87275db3d3a5e3b5d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 28 Apr 2015 12:12:29 +0200 +Subject: [PATCH] bus-util: print correct warnings for units that fail but for + which we have a NULL result only + +Cherry-picked from: 373a99e +Related: #1016680 +--- + src/libsystemd/sd-bus/bus-util.c | 34 ++++++++++++++++++++-------------- + 1 file changed, 20 insertions(+), 14 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 017fbaf2a..e48abf55a 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1724,28 +1724,34 @@ static const struct { + }; + + static void log_job_error_with_service_result(const char* service, const char *result) { +- unsigned i; + _cleanup_free_ char *service_shell_quoted = NULL; + + assert(service); +- assert(result); + + service_shell_quoted = shell_maybe_quote(service); + +- for (i = 0; i < ELEMENTSOF(explanations); ++i) +- if (streq(result, explanations[i].result)) +- break; ++ if (!isempty(result)) { ++ unsigned i; + +- if (i < ELEMENTSOF(explanations)) +- log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", +- service, +- explanations[i].explanation, +- strna(service_shell_quoted)); +- else +- log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", +- service, +- strna(service_shell_quoted)); ++ for (i = 0; i < ELEMENTSOF(explanations); ++i) ++ if (streq(result, explanations[i].result)) ++ break; ++ ++ if (i < ELEMENTSOF(explanations)) { ++ log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", ++ service, ++ explanations[i].explanation, ++ strna(service_shell_quoted)); + ++ goto finish; ++ } ++ } ++ ++ log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", ++ service, ++ strna(service_shell_quoted)); ++ ++finish: + /* For some results maybe additional explanation is required */ + if (streq_ptr(result, "start-limit")) + log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.", diff --git a/SOURCES/0238-Revert-journald-move-dev-log-socket-to-run.patch b/SOURCES/0238-Revert-journald-move-dev-log-socket-to-run.patch new file mode 100644 index 00000000..2d566a11 --- /dev/null +++ b/SOURCES/0238-Revert-journald-move-dev-log-socket-to-run.patch @@ -0,0 +1,210 @@ +From 4a1723115afea68db4cbe4f7f2d97c4f5663403d Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 6 Aug 2015 11:30:19 +0200 +Subject: [PATCH] Revert "journald: move /dev/log socket to /run" + +This reverts commit 03ee5c38cb0da193dd08733fb4c0c2809cee6a99. + +rhel-only + +Resolves: #1249968 +--- + Makefile-man.am | 5 ----- + Makefile.am | 7 ++----- + man/systemd-journald.service.xml | 2 -- + src/core/namespace.c | 3 ++- + src/journal/journald-server.c | 3 +-- + src/journal/journald-syslog.c | 2 +- + units/systemd-journald-dev-log.socket | 32 -------------------------------- + units/systemd-journald.service.in | 4 ++-- + units/systemd-journald.socket | 2 +- + 9 files changed, 9 insertions(+), 51 deletions(-) + delete mode 100644 units/systemd-journald-dev-log.socket + +diff --git a/Makefile-man.am b/Makefile-man.am +index 084df754a..497be6612 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -214,7 +214,6 @@ MANPAGES_ALIAS += \ + man/systemd-hybrid-sleep.service.8 \ + man/systemd-initctl.8 \ + man/systemd-initctl.socket.8 \ +- man/systemd-journald-dev-log.socket.8 \ + man/systemd-journald.8 \ + man/systemd-journald.socket.8 \ + man/systemd-kexec.service.8 \ +@@ -326,7 +325,6 @@ man/systemd-hibernate.service.8: man/systemd-suspend.service.8 + man/systemd-hybrid-sleep.service.8: man/systemd-suspend.service.8 + man/systemd-initctl.8: man/systemd-initctl.service.8 + man/systemd-initctl.socket.8: man/systemd-initctl.service.8 +-man/systemd-journald-dev-log.socket.8: man/systemd-journald.service.8 + man/systemd-journald.8: man/systemd-journald.service.8 + man/systemd-journald.socket.8: man/systemd-journald.service.8 + man/systemd-kexec.service.8: man/systemd-halt.service.8 +@@ -616,9 +614,6 @@ man/systemd-initctl.html: man/systemd-initctl.service.html + man/systemd-initctl.socket.html: man/systemd-initctl.service.html + $(html-alias) + +-man/systemd-journald-dev-log.socket.html: man/systemd-journald.service.html +- $(html-alias) +- + man/systemd-journald.html: man/systemd-journald.service.html + $(html-alias) + +diff --git a/Makefile.am b/Makefile.am +index a81d3c131..58bcc2c42 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4518,8 +4518,7 @@ bin_PROGRAMS += \ + systemd-cat + + dist_systemunit_DATA += \ +- units/systemd-journald.socket \ +- units/systemd-journald-dev-log.socket ++ units/systemd-journald.socket + + nodist_systemunit_DATA += \ + units/systemd-journald.service \ +@@ -4538,9 +4537,7 @@ dist_catalog_DATA = \ + catalog/systemd.catalog + + SOCKETS_TARGET_WANTS += \ +- systemd-journald.socket \ +- systemd-journald-dev-log.socket +- ++ systemd-journald.socket + SYSINIT_TARGET_WANTS += \ + systemd-journald.service \ + systemd-journal-flush.service \ +diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml +index 8280d6c87..fe99ce9bc 100644 +--- a/man/systemd-journald.service.xml ++++ b/man/systemd-journald.service.xml +@@ -45,7 +45,6 @@ + + systemd-journald.service + systemd-journald.socket +- systemd-journald-dev-log.socket + systemd-journald + Journal service + +@@ -53,7 +52,6 @@ + + systemd-journald.service + systemd-journald.socket +- systemd-journald-dev-log.socket + /usr/lib/systemd/systemd-journald + + +diff --git a/src/core/namespace.c b/src/core/namespace.c +index d4f1c8621..ebd5fb334 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -187,7 +187,8 @@ static int mount_dev(BindMount *m) { + mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL); + + devlog = strjoina(temporary_mount, "/dev/log"); +- symlink("/run/systemd/journal/dev-log", devlog); ++ (void)touch(devlog); ++ mount("/dev/log", devlog, NULL, MS_BIND, NULL); + + NULSTR_FOREACH(d, devnodes) { + _cleanup_free_ char *dn = NULL; +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index d692c06ef..fb7aae309 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1531,8 +1531,7 @@ int server_init(Server *s) { + + s->stdout_fd = fd; + +- } else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/dev/log", 0) > 0 || +- sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/run/systemd/journal/dev-log", 0) > 0) { ++ } else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/dev/log", 0) > 0) { + + if (s->syslog_fd >= 0) { + log_error("Too many /dev/log sockets passed."); +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index ba80941d7..4e118aabc 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -384,7 +384,7 @@ int server_open_syslog_socket(Server *s) { + if (s->syslog_fd < 0) { + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, +- .un.sun_path = "/run/systemd/journal/dev-log", ++ .un.sun_path = "/dev/log", + }; + + s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); +diff --git a/units/systemd-journald-dev-log.socket b/units/systemd-journald-dev-log.socket +deleted file mode 100644 +index ffd44bb50..000000000 +--- a/units/systemd-journald-dev-log.socket ++++ /dev/null +@@ -1,32 +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=Journal Socket (/dev/log) +-Documentation=man:systemd-journald.service(8) man:journald.conf(5) +-DefaultDependencies=no +-Before=sockets.target +- +-# Mount and swap units need this. If this socket unit is removed by an +-# isolate request the mount and swap units would be removed too, +-# hence let's exclude this from isolate requests. +-IgnoreOnIsolate=yes +- +-[Socket] +-Service=systemd-journald.service +-ListenDatagram=/run/systemd/journal/dev-log +-Symlinks=/dev/log +-SocketMode=0666 +-PassCredentials=yes +-PassSecurity=yes +- +-# Increase both the send and receive buffer, so that things don't +-# block early. Note that journald internally uses the this socket both +-# for receiving syslog messages, and for forwarding them to any other +-# syslog, hence we bump both values. +-ReceiveBuffer=8M +-SendBuffer=8M +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index 1bcc290ec..9d4462283 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -10,12 +10,12 @@ Description=Journal Service + Documentation=man:systemd-journald.service(8) man:journald.conf(5) + DefaultDependencies=no + Requires=systemd-journald.socket +-After=systemd-journald.socket systemd-journald-dev-log.socket syslog.socket ++After=systemd-journald.socket syslog.socket + Before=sysinit.target + + [Service] + Type=notify +-Sockets=systemd-journald.socket systemd-journald-dev-log.socket ++Sockets=systemd-journald.socket + ExecStart=@rootlibexecdir@/systemd-journald + Restart=always + RestartSec=0 +diff --git a/units/systemd-journald.socket b/units/systemd-journald.socket +index 71737014c..fbeb10baa 100644 +--- a/units/systemd-journald.socket ++++ b/units/systemd-journald.socket +@@ -19,8 +19,8 @@ IgnoreOnIsolate=yes + [Socket] + ListenStream=/run/systemd/journal/stdout + ListenDatagram=/run/systemd/journal/socket ++ListenDatagram=/dev/log + SocketMode=0666 + PassCredentials=yes + PassSecurity=yes + ReceiveBuffer=8M +-Service=systemd-journald.service diff --git a/SOURCES/0239-journald-server-don-t-read-audit-events.patch b/SOURCES/0239-journald-server-don-t-read-audit-events.patch new file mode 100644 index 00000000..ee0deb1d --- /dev/null +++ b/SOURCES/0239-journald-server-don-t-read-audit-events.patch @@ -0,0 +1,25 @@ +From 5dee07f71ccaf8eacd115e01e665c645f7c3a75d Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 10 Aug 2015 14:24:18 +0200 +Subject: [PATCH] journald-server: don't read audit events + +Resolves: #1252409 +--- + src/journal/journald-server.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index fb7aae309..f13147f65 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1577,10 +1577,6 @@ int server_init(Server *s) { + if (r < 0) + return r; + +- r = server_open_audit(s); +- if (r < 0) +- return r; +- + r = server_open_kernel_seqnum(s); + if (r < 0) + return r; diff --git a/SOURCES/0240-everything-remove-traces-of-user.patch b/SOURCES/0240-everything-remove-traces-of-user.patch new file mode 100644 index 00000000..b9e15b48 --- /dev/null +++ b/SOURCES/0240-everything-remove-traces-of-user.patch @@ -0,0 +1,833 @@ +From d550b42ed66ea7e3de9d04b3d472c6c1721a2978 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 11 Aug 2015 13:53:47 +0200 +Subject: [PATCH] everything: remove traces of --user + +Resolves: #1071363 +--- + man/busctl.xml | 6 ++-- + man/journalctl.xml | 14 -------- + man/pam_systemd.xml | 7 ++-- + man/systemctl.xml | 55 +++++------------------------ + man/systemd-analyze.xml | 6 ---- + man/systemd-run.xml | 1 - + man/systemd-system.conf.xml | 5 +-- + man/systemd.device.xml | 4 +-- + man/systemd.exec.xml | 17 ++------- + man/systemd.special.xml | 46 ++---------------------- + man/systemd.unit.xml | 66 +---------------------------------- + man/systemd.xml | 63 +++++---------------------------- + man/user-system-options.xml | 9 ----- + shell-completion/bash/busctl | 2 +- + shell-completion/bash/journalctl | 5 +-- + shell-completion/bash/systemctl.in | 2 +- + shell-completion/bash/systemd-analyze | 12 +++---- + shell-completion/bash/systemd-run | 4 +-- + src/analyze/analyze.c | 1 - + src/core/main.c | 1 - + src/journal/journalctl.c | 1 - + src/libsystemd/sd-bus/busctl.c | 1 - + src/run/run.c | 1 - + src/systemctl/systemctl.c | 1 - + 24 files changed, 40 insertions(+), 290 deletions(-) + +diff --git a/man/busctl.xml b/man/busctl.xml +index 807fc78e8..0635280ea 100644 +--- a/man/busctl.xml ++++ b/man/busctl.xml +@@ -75,9 +75,8 @@ + + Connect to the bus specified by + ADDRESS instead of using suitable +- defaults for either the system or user bus (see +- and +- options). ++ defaults for the system bus (see ++ option). + + + +@@ -236,7 +235,6 @@ + + + +- + + + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index 08de0ff06..2764f66ed 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -469,20 +469,6 @@ + + + +- +- +- +- Show messages for the specified user session +- unit. This will add a match for messages from the unit +- (_SYSTEMD_USER_UNIT= and +- _UID=) and additional matches for messages +- from session systemd and messages about coredumps for the +- specified unit. +- +- This parameter can be specified multiple times. +- +- +- + + + +diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml +index b4a3f502b..a448aed02 100644 +--- a/man/pam_systemd.xml ++++ b/man/pam_systemd.xml +@@ -78,9 +78,7 @@ + A new systemd scope unit is created for the + session. If this is the first concurrent session of the user, an + implicit slice below user.slice is +- automatically created and the scope placed into it. An instance +- of the system service user@.service, which +- runs the systemd user manager instance, is started. ++ automatically created and the scope placed into it. + + + +@@ -91,8 +89,7 @@ + logind.conf + 5, all processes of the + session are terminated. If the last concurrent session of a user +- ends, the user's systemd instance will be terminated too, and so +- will the user's slice unit. ++ ends, the user's slice unit will be terminated too. + + If the last concurrent session of a user ends, + the $XDG_RUNTIME_DIR directory and all its +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 6b29b8cd0..c6f584278 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -339,7 +339,6 @@ + + + +- + + + ++ ++ ++ ++ ++ ++ ++ ++ sd_journal_has_runtime_files ++ systemd ++ ++ ++ ++ Developer ++ Jan ++ Synáček ++ jan.synacek@gmail.com ++ ++ ++ ++ ++ ++ sd_journal_has_runtime_files ++ 3 ++ ++ ++ ++ sd_journal_has_runtime_files ++ sd_journal_has_persistent_files ++ Query availability of runtime or persistent journal files. ++ ++ ++ ++ ++ #include <systemd/sd-journal.h> ++ ++ ++ int sd_journal_has_runtime_files ++ sd_journal *j ++ ++ ++ ++ int sd_journal_has_persistent_files ++ sd_journal *j ++ ++ ++ ++ ++ ++ ++ Description ++ ++ sd_journal_has_runtime_files() returns a positive value ++ if runtime journal files (present in /run/systemd/journal/) have been found. ++ Otherwise returns 0. ++ ++ sd_journal_has_persistent_files() returns a positive value ++ if persistent journal files (present in /var/log/journal/) have been found. ++ Otherwise returns 0. ++ ++ ++ ++ Return value ++ Both sd_journal_has_runtime_files() ++ and sd_journal_has_persistent_files() return -EINVAL ++ if their argument is NULL. ++ ++ ++ ++ ++ See Also ++ ++ sd-journal3 ++ ++ ++ ++ +diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h +index b51ecdb60..115d7776d 100644 +--- a/src/journal/journal-internal.h ++++ b/src/journal/journal-internal.h +@@ -115,6 +115,8 @@ struct sd_journal { + removed, and there were no more + files, so sd_j_enumerate_unique + will return a value equal to 0. */ ++ bool has_runtime_files:1; ++ bool has_persistent_files:1; + + size_t data_threshold; + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 9b9e8ac85..20456c3a1 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -1230,8 +1230,7 @@ static int add_any_file(sd_journal *j, const char *path) { + } + + static int add_file(sd_journal *j, const char *prefix, const char *filename) { +- _cleanup_free_ char *path = NULL; +- int r; ++ char *path = NULL; + + assert(j); + assert(prefix); +@@ -1241,14 +1240,14 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { + !file_type_wanted(j->flags, filename)) + return 0; + +- path = strjoin(prefix, "/", filename, NULL); +- if (!path) +- return -ENOMEM; ++ path = strjoina(prefix, "/", filename); + +- r = add_any_file(j, path); +- if (r == -ENOENT) +- return 0; +- return r; ++ if (!j->has_runtime_files && path_startswith(path, "/run/log/journal")) ++ j->has_runtime_files = true; ++ else if (!j->has_persistent_files && path_startswith(path, "/var/log/journal")) ++ j->has_persistent_files = true; ++ ++ return add_any_file(j, path); + } + + static int remove_file(sd_journal *j, const char *prefix, const char *filename) { +@@ -2616,3 +2615,15 @@ _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) { + *sz = j->data_threshold; + return 0; + } ++ ++_public_ int sd_journal_has_runtime_files(sd_journal *j) { ++ assert_return(j, -EINVAL); ++ ++ return j->has_runtime_files; ++} ++ ++_public_ int sd_journal_has_persistent_files(sd_journal *j) { ++ assert_return(j, -EINVAL); ++ ++ return j->has_persistent_files; ++} +diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h +index 00237a215..d5fd46eea 100644 +--- a/src/systemd/sd-journal.h ++++ b/src/systemd/sd-journal.h +@@ -138,6 +138,9 @@ int sd_journal_reliable_fd(sd_journal *j); + int sd_journal_get_catalog(sd_journal *j, char **text); + int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **text); + ++int sd_journal_has_runtime_files(sd_journal *j); ++int sd_journal_has_persistent_files(sd_journal *j); ++ + /* the inverse condition avoids ambiguity of danling 'else' after the macro */ + #define SD_JOURNAL_FOREACH(j) \ + if (sd_journal_seek_head(j) < 0) { } \ diff --git a/SOURCES/0279-journalctl-improve-error-messages-when-the-specified.patch b/SOURCES/0279-journalctl-improve-error-messages-when-the-specified.patch new file mode 100644 index 00000000..f6355dd4 --- /dev/null +++ b/SOURCES/0279-journalctl-improve-error-messages-when-the-specified.patch @@ -0,0 +1,31 @@ +From 046d996001c0b3fe34d34683e55f62481a5af932 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 1 Feb 2016 09:29:02 +0100 +Subject: [PATCH] journalctl: improve error messages when the specified boot is + not found + +Cherry-picked from: c34e939909710bf124e7741c3648592a30418ffd +Resolves: #1082179 +--- + src/journal/journalctl.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 7058788ef..964f849ee 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1090,10 +1090,11 @@ static int add_boot(sd_journal *j) { + const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); + + if (sd_id128_is_null(arg_boot_id)) +- log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason); ++ log_error("Data from the specified boot (%+i) is not available: %s", ++ arg_boot_offset, reason); + else +- log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s", +- SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason); ++ log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s", ++ SD_ID128_FORMAT_VAL(arg_boot_id), reason); + + return r == 0 ? -ENODATA : r; + } diff --git a/SOURCES/0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch b/SOURCES/0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch new file mode 100644 index 00000000..3275d865 --- /dev/null +++ b/SOURCES/0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch @@ -0,0 +1,33 @@ +From a932c70a76846aa7dbb4b783291b44bfc8cbd76c Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 1 Feb 2016 09:25:22 +0100 +Subject: [PATCH] journalctl: show friendly info when using -b on runtime + journal only + +Make it clear that specifing boot when there is actually only one has no +effect. This cosmetic patch improves user experience a bit. + +Cherry-picked from: 0f1a9a830c87d8accdc3a44d0a93ad343e52a7bd +Resolves: #1082179 +--- + src/journal/journalctl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 964f849ee..836d7d214 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1905,6 +1905,13 @@ int main(int argc, char *argv[]) { + goto finish; + } + ++ if (arg_boot_offset != 0 && ++ sd_journal_has_runtime_files(j) > 0 && ++ sd_journal_has_persistent_files(j) == 0) { ++ log_info("Specifying boot ID has no effect, no persistent journal was found"); ++ r = 0; ++ goto finish; ++ } + /* add_boot() must be called first! + * It may need to seek the journal to find parent boot IDs. */ + r = add_boot(j); diff --git a/SOURCES/0281-journalctl-make-journalctl-dev-sda-work.patch b/SOURCES/0281-journalctl-make-journalctl-dev-sda-work.patch new file mode 100644 index 00000000..1ae56c8a --- /dev/null +++ b/SOURCES/0281-journalctl-make-journalctl-dev-sda-work.patch @@ -0,0 +1,206 @@ +From 1c33de9e1370bc56e10f3b5306e27c8aa6a18873 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 1 Feb 2016 10:44:58 +0100 +Subject: [PATCH] journalctl: make "journalctl /dev/sda" work + +Currently when journalctl is called with path to block device node we +add following match _KERNEL_DEVICE=b$MAJOR:$MINOR. + +That is not sufficient to actually obtain logs about the disk because +dev_printk() kernel helper puts to /dev/kmsg information about the +device in following format, +$SUBSYSTEM:$ADDRESS, +e.g. "+pci:pci:0000:00:14.0". + +Now we will walk upward the syspath and add match for every device in +format produced by dev_printk() as well as match for its device node if +it exists. + +Cherry-picked from: 795ab08f783e78e85f1493879f13ac44cb113b00 +Resolves: #947636 +--- + Makefile.am | 3 +- + src/journal/journalctl.c | 118 ++++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 97 insertions(+), 24 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 2645f66bc..255937643 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4245,7 +4245,8 @@ journalctl_LDADD = \ + libsystemd-journal-internal.la \ + libsystemd-internal.la \ + libsystemd-logs.la \ +- libsystemd-shared.la ++ libsystemd-shared.la \ ++ libudev-core.la + + if HAVE_ACL + journalctl_LDADD += \ +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 836d7d214..3db1cd24e 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -63,6 +63,8 @@ + #include "mkdir.h" + #include "bus-util.h" + #include "bus-error.h" ++#include "udev.h" ++#include "udev-util.h" + + #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) + +@@ -134,6 +136,80 @@ typedef struct boot_id_t { + LIST_FIELDS(struct boot_id_t, boot_list); + } boot_id_t; + ++static int add_matches_for_device(sd_journal *j, const char *devpath) { ++ int r; ++ _cleanup_udev_unref_ struct udev *udev = NULL; ++ _cleanup_udev_device_unref_ struct udev_device *device = NULL; ++ struct udev_device *d = NULL; ++ struct stat st; ++ ++ assert(j); ++ assert(devpath); ++ ++ if (!path_startswith(devpath, "/dev/")) { ++ log_error("Devpath does not start with /dev/"); ++ return -EINVAL; ++ } ++ ++ udev = udev_new(); ++ if (!udev) ++ return log_oom(); ++ ++ r = stat(devpath, &st); ++ if (r < 0) ++ log_error_errno(errno, "Couldn't stat file: %m"); ++ ++ d = device = udev_device_new_from_devnum(udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev); ++ if (!device) ++ return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev)); ++ ++ while (d) { ++ _cleanup_free_ char *match = NULL; ++ const char *subsys, *sysname, *devnode; ++ ++ subsys = udev_device_get_subsystem(d); ++ if (!subsys) { ++ d = udev_device_get_parent(d); ++ continue; ++ } ++ ++ sysname = udev_device_get_sysname(d); ++ if (!sysname) { ++ d = udev_device_get_parent(d); ++ continue; ++ } ++ ++ match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname, NULL); ++ if (!match) ++ return log_oom(); ++ ++ r = sd_journal_add_match(j, match, 0); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add match: %m"); ++ ++ devnode = udev_device_get_devnode(d); ++ if (devnode) { ++ _cleanup_free_ char *match1 = NULL; ++ ++ r = stat(devnode, &st); ++ if (r < 0) ++ return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode); ++ ++ r = asprintf(&match1, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st.st_mode) ? 'b' : 'c', major(st.st_rdev), minor(st.st_rdev)); ++ if (r < 0) ++ return log_oom(); ++ ++ r = sd_journal_add_match(j, match1, 0); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add match: %m"); ++ } ++ ++ d = udev_device_get_parent(d); ++ } ++ ++ return 0; ++} ++ + static void pager_open_if_enabled(void) { + + if (arg_no_pager) +@@ -788,13 +864,12 @@ static int add_matches(sd_journal *j, char **args) { + have_term = false; + + } else if (path_is_absolute(*i)) { +- _cleanup_free_ char *p, *t = NULL, *t2 = NULL; ++ _cleanup_free_ char *p, *t = NULL, *t2 = NULL, *interpreter = NULL; + const char *path; +- _cleanup_free_ char *interpreter = NULL; + struct stat st; + + p = canonicalize_file_name(*i); +- path = p ? p : *i; ++ path = p ?: *i; + + if (stat(path, &st) < 0) + return log_error_errno(errno, "Couldn't stat file: %m"); +@@ -808,40 +883,37 @@ static int add_matches(sd_journal *j, char **args) { + return log_oom(); + + t = strappend("_COMM=", comm); ++ if (!t) ++ return log_oom(); + + /* Append _EXE only if the interpreter is not a link. + Otherwise, it might be outdated often. */ +- if (lstat(interpreter, &st) == 0 && +- !S_ISLNK(st.st_mode)) { ++ if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) { + t2 = strappend("_EXE=", interpreter); + if (!t2) + return log_oom(); + } +- } else ++ } else { + t = strappend("_EXE=", path); +- } else if (S_ISCHR(st.st_mode)) { +- if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u", +- major(st.st_rdev), +- minor(st.st_rdev)) < 0) +- return -ENOMEM; +- } else if (S_ISBLK(st.st_mode)) { +- if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u", +- major(st.st_rdev), +- minor(st.st_rdev)) < 0) +- return -ENOMEM; ++ if (!t) ++ return log_oom(); ++ } ++ ++ r = sd_journal_add_match(j, t, 0); ++ ++ if (r >=0 && t2) ++ r = sd_journal_add_match(j, t2, 0); ++ ++ } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { ++ r = add_matches_for_device(j, path); ++ if (r < 0) ++ return r; + } else { + log_error("File is neither a device node, nor regular file, nor executable: %s", *i); + return -EINVAL; + } + +- if (!t) +- return log_oom(); +- +- r = sd_journal_add_match(j, t, 0); +- if (t2) +- r = sd_journal_add_match(j, t2, 0); + have_term = true; +- + } else { + r = sd_journal_add_match(j, *i, 0); + have_term = true; diff --git a/SOURCES/0282-journalctl-add-match-for-the-current-boot-when-calle.patch b/SOURCES/0282-journalctl-add-match-for-the-current-boot-when-calle.patch new file mode 100644 index 00000000..5ac2fc2f --- /dev/null +++ b/SOURCES/0282-journalctl-add-match-for-the-current-boot-when-calle.patch @@ -0,0 +1,27 @@ +From fb7acf90df3d675261b18f8e7c2de315dadee756 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 3 Feb 2016 11:22:52 +0100 +Subject: [PATCH] journalctl: add match for the current boot when called with + devpath + +Cherry-picked from: 485fd9a7b9d59b9f2302a873f7ee5ccac256dd93 +Related: #947636 +--- + src/journal/journalctl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 3db1cd24e..6948ed689 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -207,6 +207,10 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) { + d = udev_device_get_parent(d); + } + ++ r = add_match_this_boot(j, arg_machine); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add match for the current boot: %m"); ++ + return 0; + } + diff --git a/SOURCES/0283-man-clarify-what-happens-when-journalctl-is-called-w.patch b/SOURCES/0283-man-clarify-what-happens-when-journalctl-is-called-w.patch new file mode 100644 index 00000000..741a3fe9 --- /dev/null +++ b/SOURCES/0283-man-clarify-what-happens-when-journalctl-is-called-w.patch @@ -0,0 +1,33 @@ +From a4f12d4849daed23651ab3c23b5ff830aa32b2a0 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 3 Feb 2016 10:38:29 +0100 +Subject: [PATCH] man: clarify what happens when journalctl is called with + devpath + +Cherry-picked from: 3cea8e06e45fc1757de8f74da29fb5fb181db4eb +Related: #947636 +--- + man/journalctl.xml | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index 2764f66ed..0981fba72 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -91,8 +91,14 @@ + paths may be specified. If a file path refers to an executable + file, this is equivalent to an _EXE= match + for the canonicalized binary path. Similarly, if a path refers +- to a device node, this is equivalent to a +- _KERNEL_DEVICE= match for the device. ++ to a device node then match is added for the kernel name of the ++ device (_KERNEL_DEVICE=). Also, matches for the ++ kernel names of all the parent devices are added automatically. ++ Device node paths are not stable across reboots, therefore match ++ for the current boot id (_BOOT_ID=) is ++ always added as well. Note that only the log entries for ++ the existing device nodes maybe queried by providing path to ++ the device node. + + Additional constraints may be added using options + , , etc, to diff --git a/SOURCES/0284-core-downgrade-warning-about-duplicate-device-names.patch b/SOURCES/0284-core-downgrade-warning-about-duplicate-device-names.patch new file mode 100644 index 00000000..3cbc9d04 --- /dev/null +++ b/SOURCES/0284-core-downgrade-warning-about-duplicate-device-names.patch @@ -0,0 +1,26 @@ +From ad2cedec3cf3e6ddefd70d9f3dece3ca837676cf Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 23 Apr 2015 13:50:01 +0200 +Subject: [PATCH] core: downgrade warning about duplicate device names + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/031094.html + +Cherry-picked from: 5259bcf6a638d8d489db1ddefd55327aa15f3e51 +Resolves: #1296249 +--- + src/core/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/device.c b/src/core/device.c +index 8a6855dfc..1995e3c0b 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -317,7 +317,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa + if (u && + DEVICE(u)->sysfs && + !path_equal(DEVICE(u)->sysfs, sysfs)) { +- log_unit_error(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); ++ log_unit_debug(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); + return -EEXIST; + } + diff --git a/SOURCES/0285-udev-downgrade-a-few-warnings-to-debug-messages.patch b/SOURCES/0285-udev-downgrade-a-few-warnings-to-debug-messages.patch new file mode 100644 index 00000000..00a87c3e --- /dev/null +++ b/SOURCES/0285-udev-downgrade-a-few-warnings-to-debug-messages.patch @@ -0,0 +1,44 @@ +From 95a6f0f1b2a24e40380af5db1797ee60c8763ca2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 14 Apr 2015 15:48:26 +0200 +Subject: [PATCH] udev: downgrade a few warnings to debug messages + +https://bugs.freedesktop.org/show_bug.cgi?id=89885 + +Cherry-picked from: 8d8ce9e2 +Resolves: #1289461 +--- + src/udev/udev-builtin-blkid.c | 2 +- + src/udev/udev-builtin-usb_id.c | 6 ++---- + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c +index 89995831b..2b2c3dad6 100644 +--- a/src/udev/udev-builtin-blkid.c ++++ b/src/udev/udev-builtin-blkid.c +@@ -263,7 +263,7 @@ static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool t + + fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC); + if (fd < 0) { +- fprintf(stderr, "error: %s: %m\n", udev_device_get_devnode(dev)); ++ err = log_debug_errno(errno, "Failure opening block device %s: %m", udev_device_get_devnode(dev)); + goto out; + } + +diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c +index ab0d96e37..64b763c1e 100644 +--- a/src/udev/udev-builtin-usb_id.c ++++ b/src/udev/udev-builtin-usb_id.c +@@ -168,10 +168,8 @@ static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len + return log_oom(); + + fd = open(filename, O_RDONLY|O_CLOEXEC); +- if (fd < 0) { +- fprintf(stderr, "error opening USB device 'descriptors' file\n"); +- return -errno; +- } ++ if (fd < 0) ++ return log_debug_errno(errno, "Error opening USB device 'descriptors' file: %m"); + + size = read(fd, buf, sizeof(buf)); + if (size < 18 || size == sizeof(buf)) diff --git a/SOURCES/0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch b/SOURCES/0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch new file mode 100644 index 00000000..cef6b48d --- /dev/null +++ b/SOURCES/0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch @@ -0,0 +1,26 @@ +From ffe00d391c0cfc52897820bb19c6a0b8a43680d8 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 5 Oct 2015 12:19:13 +0200 +Subject: [PATCH] man: LEVEL in systemd-analyze set-log level is not optional + +rhbz#1268336 + +Cherry-picked from: 62b29f83cdd3059fda5bf5d2e098293f6dccf863 +Resolves: #1268336 +--- + man/systemd-analyze.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml +index b2e0f42d5..e58d9a74e 100644 +--- a/man/systemd-analyze.xml ++++ b/man/systemd-analyze.xml +@@ -93,7 +93,7 @@ + systemd-analyze + OPTIONS + set-log-level +- LEVEL ++ LEVEL + + + systemd-analyze diff --git a/SOURCES/0287-Revert-udev-fibre-channel-fix-NPIV-support.patch b/SOURCES/0287-Revert-udev-fibre-channel-fix-NPIV-support.patch new file mode 100644 index 00000000..b10569c7 --- /dev/null +++ b/SOURCES/0287-Revert-udev-fibre-channel-fix-NPIV-support.patch @@ -0,0 +1,57 @@ +From 4c895cb7bbb307f3c865d9a37f448605797d2b42 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 29 Feb 2016 16:33:38 +0100 +Subject: [PATCH] Revert "udev: fibre channel: fix NPIV support" + +This reverts commit 569d98e9caae425120bf28f6b440e6cc117abc0d. + +Related: #1266934 +--- + src/udev/udev-builtin-path_id.c | 27 +++------------------------ + 1 file changed, 3 insertions(+), 24 deletions(-) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 695ac7fc1..9ca608468 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -92,9 +92,6 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s + static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; +- struct udev_device *rportdev; +- struct udev_device *hostdev; +- struct udev_device *vportdev; + struct udev_device *fcdev = NULL; + const char *port; + char *lun = NULL; +@@ -103,27 +100,9 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, + if (targetdev == NULL) + return NULL; + +- rportdev = udev_device_get_parent(targetdev); +- if (rportdev == NULL) +- goto skip_npiv_check; +- +- hostdev = udev_device_get_parent(rportdev); +- if (hostdev == NULL) +- goto skip_npiv_check; +- +- vportdev = udev_device_get_parent(hostdev); +- if (vportdev == NULL) +- goto skip_npiv_check; +- +- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); +- +-skip_npiv_check: +- if (fcdev == NULL) { +- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); +- if (fcdev == NULL) +- return NULL; +- } +- ++ fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); ++ if (fcdev == NULL) ++ return NULL; + port = udev_device_get_sysattr_value(fcdev, "port_name"); + if (port == NULL) { + parent = NULL; diff --git a/SOURCES/0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch b/SOURCES/0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch new file mode 100644 index 00000000..49fd8ad6 --- /dev/null +++ b/SOURCES/0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch @@ -0,0 +1,125 @@ +From 05004e584a76645dcbcaaa4d5c2d3d3255900770 Mon Sep 17 00:00:00 2001 +From: Mauricio Faria de Oliveira +Date: Tue, 23 Feb 2016 15:02:02 -0300 +Subject: [PATCH] udev: path-id: fibre channel NPIV - use fc_vport's port_name + +With the Fibre Channel NPIV (N_Port ID Virtualization) feature, +a single physical N_Port (e.g., PCI address) can have multiple +N_Port IDs (e.g., different fc_host nodes) - which can connect +to the same target LUN (e.g., fc_remote_port's port_name and +LUN number). + +Thus, in order to be unique, the device persistent path should +include the fc_vport's port_name (only if the fc_vport is used), +in addition to the already in use PCI address, fc_remote_port's +port_name and LUN number. + +The patch merges the 2 proposals submitted upstream, addressing +some problems with both: +- #2500 (don't replace the fc_rport's port_name with fc_vport's) +- #2665 (don't add a fc_host/fc_vport's port_name if not needed) + +Links +- https://github.com/systemd/systemd/pull/2500/ +- https://github.com/systemd/systemd/pull/2665/ + +Built, checked, tested on RHEL Server 7.1 with no regressions. + +With the patch, /dev/disk/by-path symlinks are created correctly, +and are unique, backward-compatible with the physical port case: +- physical port (no vport field) +- virtual ports (w/ vport field) + + # ls -l /dev/disk/by-path | grep 0001:09:00.0 + <...> pci-0001:09:00.0-fc-0x500507680b2255fe-lun-0 -> ../../sdh + <...> pci-0001:09:00.0-fc-0x500507680b2255ff-lun-0 -> ../../sdi + <...> pci-0001:09:00.0-vport-0x5001a4aaf00a6785-fc-0x500507680b2255fe-lun-0 -> ../../sde + <...> pci-0001:09:00.0-vport-0x5001a4aaf00a6785-fc-0x500507680b2255ff-lun-0 -> ../../sdd + <...> pci-0001:09:00.0-vport-0x5001a4ad99d8c2de-fc-0x500507680b2255fe-lun-0 -> ../../sdc + <...> pci-0001:09:00.0-vport-0x5001a4ad99d8c2de-fc-0x500507680b2255ff-lun-0 -> ../../sdb + +Accordingly w/ sysfs: + + # ls -ld /sys/block/sd* | grep host1 + <...> /sys/block/sdb -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-0/host3/rport-3:0-1/target3:0:0/3:0:0:0/block/sdb + <...> /sys/block/sdc -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-0/host3/rport-3:0-2/target3:0:1/3:0:1:0/block/sdc + <...> /sys/block/sdd -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-2/host5/rport-5:0-1/target5:0:0/5:0:0:0/block/sdd + <...> /sys/block/sde -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-2/host5/rport-5:0-2/target5:0:1/5:0:1:0/block/sde + <...> /sys/block/sdh -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/rport-1:0-3/target1:0:0/1:0:0:0/block/sdh + <...> /sys/block/sdi -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/rport-1:0-4/target1:0:1/1:0:1:0/block/sdi + +The symlinks still include the fc_remote_port's (target) port_name: + + # grep . /sys/class/fc_remote_ports/rport-{3:0-{1,2},5:0-{1,2},1:0-{3,4}}/port_name + /sys/class/fc_remote_ports/rport-3:0-1/port_name:0x500507680b2255ff + /sys/class/fc_remote_ports/rport-3:0-2/port_name:0x500507680b2255fe + /sys/class/fc_remote_ports/rport-5:0-1/port_name:0x500507680b2255ff + /sys/class/fc_remote_ports/rport-5:0-2/port_name:0x500507680b2255fe + /sys/class/fc_remote_ports/rport-1:0-3/port_name:0x500507680b2255fe + /sys/class/fc_remote_ports/rport-1:0-4/port_name:0x500507680b2255ff + +And now include the fc_vport's (virtual host) port_name *if* it's from a fc_vport: + + # grep . /sys/class/fc_host/host1/port_name /sys/class/fc_vports/vport-1:0-{0,2}/port_name + /sys/class/fc_host/host1/port_name:0x10000090fa8f0ebc + /sys/class/fc_vports/vport-1:0-0/port_name:0x5001a4ad99d8c2de + /sys/class/fc_vports/vport-1:0-2/port_name:0x5001a4aaf00a6785 + +Signed-off-by: Mauricio Faria de Oliveira +Reported-by: Srikanth B. Aithal + +Cherry-picked from: 6a3d3f9e5970cf982ac37c65d0b856146b675a12 +Resolves: #1266934 +--- + src/udev/udev-builtin-path_id.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 9ca608468..3b72922d4 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -92,7 +92,11 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s + static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; ++ struct udev_device *rportdev; ++ struct udev_device *hostdev; ++ struct udev_device *vportdev; + struct udev_device *fcdev = NULL; ++ struct udev_device *fc_vportdev = NULL; + const char *port; + char *lun = NULL; + +@@ -113,6 +117,32 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, + path_prepend(path, "fc-%s-%s", port, lun); + if (lun) + free(lun); ++ ++ /* NPIV */ ++ rportdev = udev_device_get_parent(targetdev); ++ if (rportdev == NULL) ++ goto out; ++ ++ hostdev = udev_device_get_parent(rportdev); ++ if (hostdev == NULL) ++ goto out; ++ ++ vportdev = udev_device_get_parent(hostdev); ++ if (vportdev == NULL) ++ goto out; ++ ++ fc_vportdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); ++ if (fc_vportdev == NULL) ++ goto out; ++ ++ port = udev_device_get_sysattr_value(fc_vportdev, "port_name"); ++ if (port == NULL) ++ goto out_npiv; ++ ++ path_prepend(path, "vport-%s", port); ++ ++out_npiv: ++ udev_device_unref(fc_vportdev); + out: + udev_device_unref(fcdev); + return parent; diff --git a/SOURCES/0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch b/SOURCES/0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch new file mode 100644 index 00000000..ddea68ff --- /dev/null +++ b/SOURCES/0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch @@ -0,0 +1,45 @@ +From f3b1b4ae42a2d0d6383c6587a842418abad645a9 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 25 Jan 2016 15:21:28 +0100 +Subject: [PATCH] systemctl: is-active/failed should return 0 if at least one + unit is in given state + +Previously we have return the not-found code, in the case that we found a +unit which does not belong to set active (resp. failed), which is the +opposite than what is written in man page. + +Cherry-picked from: d60f6ad0cb690d920b8acbfb545bad29554609f1 +Resolves: #1254650 +--- + src/systemctl/systemctl.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 5d3a85fd9..bf5bb398b 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -3002,6 +3002,7 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch + _cleanup_strv_free_ char **names = NULL; + char **name; + int r; ++ bool found = false; + + assert(bus); + assert(args); +@@ -3016,11 +3017,13 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch + state = check_one_unit(bus, *name, good_states, arg_quiet); + if (state < 0) + return state; +- if (state == 0) +- r = code; ++ if (state > 0) ++ found = true; + } + +- return r; ++ /* use the given return code for the case that we won't find ++ * any unit which matches the list */ ++ return found ? 0 : code; + } + + static int check_unit_active(sd_bus *bus, char **args) { diff --git a/SOURCES/0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch b/SOURCES/0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch new file mode 100644 index 00000000..2f35ee26 --- /dev/null +++ b/SOURCES/0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch @@ -0,0 +1,34 @@ +From d77ced281c6d1f47b5dfc3abff6817d8f5756af9 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 25 Feb 2016 15:15:04 +0100 +Subject: [PATCH] rules: set SYSTEMD_READY=0 on + DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 only with ADD event + +The "SYSTEMD_READY=0" will cause automatic unmount +of mountpoint that is on top of such DM device +if this is used with multipath which sets +DM_UDEV_DISABLE_OTHER_RULES_FLAG in case +we have a CHANGE event thatcomes after DM multipath +device reload when one of the paths is down or up. + +See https://bugzilla.redhat.com/show_bug.cgi?id=1312011 + +Cherry-picked from: 83a3642f617975d596b5001b1699c3d16773a6e5 +Resolves: #1312011 +--- + rules/99-systemd.rules.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in +index b66d727a4..a4f4bf3df 100644 +--- a/rules/99-systemd.rules.in ++++ b/rules/99-systemd.rules.in +@@ -12,7 +12,7 @@ SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270 + KERNEL=="vport*", TAG+="systemd" + + SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd" +-SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" ++SUBSYSTEM=="block", KERNEL!="ram*", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" + + # Ignore encrypted devices with no identified superblock on it, since + # we are probably still calling mke2fs or mkswap on it. diff --git a/SOURCES/0291-s390-add-personality-support.patch b/SOURCES/0291-s390-add-personality-support.patch new file mode 100644 index 00000000..d751c1c6 --- /dev/null +++ b/SOURCES/0291-s390-add-personality-support.patch @@ -0,0 +1,109 @@ +From 9435bd3d692c7b07e527b6a616018fa5620502e2 Mon Sep 17 00:00:00 2001 +From: Hendrik Brueckner +Date: Thu, 24 Sep 2015 12:47:22 +0200 +Subject: [PATCH] s390: add personality support + +Introduce personality support for Linux on z Systems to run +particular services with a 64-bit or 31-bit personality. + +Cherry-picked from: 7517f51ef9921d3360453c8eec2c97256d320ceb +Resolves: #1300344 +--- + Makefile.am | 1 + + src/shared/util.c | 27 +++++++++++++++++++++++++++ + src/test/test-execute.c | 8 ++++++-- + test/exec-personality-s390.service | 7 +++++++ + 4 files changed, 41 insertions(+), 2 deletions(-) + create mode 100644 test/exec-personality-s390.service + +diff --git a/Makefile.am b/Makefile.am +index 255937643..3af720bda 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1483,6 +1483,7 @@ EXTRA_DIST += \ + test/exec-ignoresigpipe-yes.service \ + test/exec-personality-x86-64.service \ + test/exec-personality-x86.service \ ++ test/exec-personality-s390.service \ + test/exec-privatedevices-no.service \ + test/exec-privatedevices-yes.service \ + test/exec-privatetmp-no.service \ +diff --git a/src/shared/util.c b/src/shared/util.c +index dc5185269..a24aa7f93 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -6748,6 +6748,19 @@ unsigned long personality_from_string(const char *p) { + + if (streq(p, "x86")) + return PER_LINUX; ++ ++#elif defined(__s390x__) ++ ++ if (streq(p, "s390")) ++ return PER_LINUX32; ++ ++ if (streq(p, "s390x")) ++ return PER_LINUX; ++ ++#elif defined(__s390__) ++ ++ if (streq(p, "s390")) ++ return PER_LINUX; + #endif + + /* personality(7) documents that 0xffffffffUL is used for +@@ -6770,6 +6783,20 @@ const char* personality_to_string(unsigned long p) { + + if (p == PER_LINUX) + return "x86"; ++ ++#elif defined(__s390x__) ++ ++ if (p == PER_LINUX) ++ return "s390x"; ++ ++ if (p == PER_LINUX32) ++ return "s390"; ++ ++#elif defined(__s390__) ++ ++ if (p == PER_LINUX) ++ return "s390"; ++ + #endif + + return NULL; +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 91ccaf72b..00f3607b4 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -77,10 +77,14 @@ static void test_exec_workingdirectory(Manager *m) { + } + + static void test_exec_personality(Manager *m) { +- test(m, "exec-personality-x86.service", 0, CLD_EXITED); +- + #if defined(__x86_64__) + test(m, "exec-personality-x86-64.service", 0, CLD_EXITED); ++ ++#elif defined(__s390__) ++ test(m, "exec-personality-s390.service", 0, CLD_EXITED); ++ ++#else ++ test(m, "exec-personality-x86.service", 0, CLD_EXITED); + #endif + } + +diff --git a/test/exec-personality-s390.service b/test/exec-personality-s390.service +new file mode 100644 +index 000000000..f3c3b03e3 +--- /dev/null ++++ b/test/exec-personality-s390.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for Personality=s390 ++ ++[Service] ++ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "s390")' ++Type=oneshot ++Personality=s390 diff --git a/SOURCES/0292-socket_address_listen-do-not-rely-on-errno.patch b/SOURCES/0292-socket_address_listen-do-not-rely-on-errno.patch new file mode 100644 index 00000000..07aec586 --- /dev/null +++ b/SOURCES/0292-socket_address_listen-do-not-rely-on-errno.patch @@ -0,0 +1,34 @@ +From 2ae0271ada810c06c12755699f0db955fc51061d Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Thu, 10 Mar 2016 10:19:56 +0100 +Subject: [PATCH] socket_address_listen - do not rely on errno + +Currently socket_address_listen() calls mac_selinux_bind() to bind a UNIX +socket and checks its return value and errno for EADDRINUSE. This is not +correct. When there's an SELinux context change made for the new socket, +bind() is not the last function called in mac_selinux_bind(). In that +case the last call is setfscreatecon() from libselinux which can change +errno as it uses access() to check if /proc/thread-self is available. +It fails on kernels before 3.17 and errno is set to ENOENT. + +It's safe to check only the return value at it's set to -errno. + +Cherry-picked from: a0c9496cc826957fe0f3926f619e073f17a9ab4d +Resolves: #1316452 +--- + src/shared/socket-label.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c +index a6289eb50..713e71ba3 100644 +--- a/src/shared/socket-label.c ++++ b/src/shared/socket-label.c +@@ -119,7 +119,7 @@ int socket_address_listen( + + r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); + +- if (r < 0 && errno == EADDRINUSE) { ++ if (r == -EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + r = bind(fd, &a->sockaddr.sa, a->size); diff --git a/SOURCES/0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch b/SOURCES/0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch new file mode 100644 index 00000000..e637af4a --- /dev/null +++ b/SOURCES/0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch @@ -0,0 +1,48 @@ +From b6fea1a0e0fd830e1aa82accf389cb8bfd0f0f37 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 9 Feb 2016 09:57:45 +0100 +Subject: [PATCH] path_id: reintroduce by-path links for virtio block devices + +Enumeration of virtio buses is global and hence +non-deterministic. However, we are guaranteed there is never going to be +more than one virtio bus per parent PCI device. While populating +ID_PATH we simply skip virtio part of the syspath and we extend the path +using the sysname of the parent PCI device. + +With this patch udev creates following by-path links for virtio-blk +device /dev/vda which contains two partitions. + +ls -l /dev/disk/by-path/ +total 0 +lrwxrwxrwx 1 root root 9 Feb 9 10:47 virtio-pci-0000:00:05.0 -> ../../vda +lrwxrwxrwx 1 root root 10 Feb 9 10:47 virtio-pci-0000:00:05.0-part1 -> ../../vda1 +lrwxrwxrwx 1 root root 10 Feb 9 10:47 virtio-pci-0000:00:05.0-part2 -> ../../vda2 + +See: +http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030328.html + +Fixes #2501 + +Cherry-picked from: f073b1b3c0f4f0df1b0bd61042ce85fb5d27d407 +Resolves: #952567 +--- + src/udev/udev-builtin-path_id.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 3b72922d4..8359e236a 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -698,6 +698,12 @@ restart: + path_prepend(&path, "xen-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "xen"); + supported_parent = true; ++ } else if (streq(subsys, "virtio")) { ++ while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent))) ++ parent = udev_device_get_parent(parent); ++ path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent)); ++ supported_transport = true; ++ supported_parent = true; + } else if (streq(subsys, "scm")) { + path_prepend(&path, "scm-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "scm"); diff --git a/SOURCES/0294-journal-fix-error-handling-when-compressing-journal-.patch b/SOURCES/0294-journal-fix-error-handling-when-compressing-journal-.patch new file mode 100644 index 00000000..e397d6c4 --- /dev/null +++ b/SOURCES/0294-journal-fix-error-handling-when-compressing-journal-.patch @@ -0,0 +1,67 @@ +From f45b66a348f5778bd391ad1b0a0e09bf5789b415 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sat, 24 Oct 2015 13:17:54 +0200 +Subject: [PATCH] journal: fix error handling when compressing journal objects + +Let's make sure we handle compression errors properly, and don't +misunderstand an error for success. + +Also, let's actually compress things if lz4 is enabled. + +Fixes #1662. + +Cherry-picked from: d1afbcd22170e95c79261340071d376fe41fc3af +Resolves: #1292447 +--- + src/journal/journal-file.c | 12 +++++++----- + src/journal/journal-file.h | 5 +++++ + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index f500568fe..a8f92e23a 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -1051,23 +1051,25 @@ static int journal_file_append_data( + o->data.hash = htole64(hash); + + #if defined(HAVE_XZ) || defined(HAVE_LZ4) +- if (f->compress_xz && +- size >= COMPRESSION_SIZE_THRESHOLD) { ++ if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { + size_t rsize; + + compression = compress_blob(data, size, o->data.payload, &rsize); + +- if (compression) { ++ if (compression >= 0) { + o->object.size = htole64(offsetof(Object, data.payload) + rsize); + o->object.flags |= compression; + + log_debug("Compressed data object %"PRIu64" -> %zu using %s", + size, rsize, object_compressed_to_string(compression)); +- } ++ } else ++ /* Compression didn't work, we don't really care why, let's continue without compression */ ++ compression = 0; ++ + } + #endif + +- if (!compression && size > 0) ++ if (compression == 0 && size > 0) + memcpy(o->data.payload, data, size); + + r = journal_file_link_data(f, o, p, hash); +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index 403c8f760..0f29b092b 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -229,3 +229,8 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t * + int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to); + + bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); ++ ++static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) { ++ assert(f); ++ return f->compress_xz || f->compress_lz4; ++} diff --git a/SOURCES/0295-journal-irrelevant-coding-style-fixes.patch b/SOURCES/0295-journal-irrelevant-coding-style-fixes.patch new file mode 100644 index 00000000..15a6c330 --- /dev/null +++ b/SOURCES/0295-journal-irrelevant-coding-style-fixes.patch @@ -0,0 +1,45 @@ +From d205f5f85569e2dddca96362ce2db4e2a0b99d00 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sat, 24 Oct 2015 15:08:15 +0200 +Subject: [PATCH] journal: irrelevant coding style fixes + +Cherry-picked from: 0240c603691e006165d8687d6a2c70859755b11f +Related: #1292447 +--- + src/journal/compress.c | 9 +++++---- + src/journal/journal-file.c | 2 +- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/journal/compress.c b/src/journal/compress.c +index 6923753f8..c9a3399cc 100644 +--- a/src/journal/compress.c ++++ b/src/journal/compress.c +@@ -51,10 +51,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ + #ifdef HAVE_XZ + static const lzma_options_lzma opt = { + 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT, +- LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4}; +- static const lzma_filter filters[2] = { +- {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt}, +- {LZMA_VLI_UNKNOWN, NULL} ++ LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4 ++ }; ++ static const lzma_filter filters[] = { ++ { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt }, ++ { LZMA_VLI_UNKNOWN, NULL } + }; + lzma_ret ret; + size_t out_pos = 0; +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index a8f92e23a..892fe4734 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -1032,7 +1032,7 @@ static int journal_file_append_data( + r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p); + if (r < 0) + return r; +- else if (r > 0) { ++ if (r > 0) { + + if (ret) + *ret = o; diff --git a/SOURCES/0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch b/SOURCES/0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch new file mode 100644 index 00000000..43f31cf6 --- /dev/null +++ b/SOURCES/0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch @@ -0,0 +1,4358 @@ +From 272378080241106862a9cca2e4e84857fe1aaf5c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 8 Oct 2015 22:31:56 +0200 +Subject: [PATCH] install: follow unit file symlinks in /usr, but not /etc when + looking for [Install] data + +Some distributions use alias unit files via symlinks in /usr to cover +for legacy service names. With this change we'll allow "systemctl +enable" on such aliases. + +Previously, our rule was that symlinks are user configuration that +"systemctl enable" + "systemctl disable" creates and removes, while unit +files is where the instructions to do so are store. As a result of the +rule we'd never read install information through symlinks, since that +would mix enablement state with installation instructions. + +Now, the new rule is that only symlinks inside of /etc are +configuration. Unit files, and symlinks in /usr are now valid for +installation instructions. + +This patch is quite a rework of the whole install logic, and makes the +following addional changes: + +- Adds a complete test "test-instal-root" that tests the install logic + pretty comprehensively. + +- Never uses canonicalize_file_name(), because that's incompatible with + operation relative to a specific root directory. + +- unit_file_get_state() is reworked to return a proper error, and + returns the state in a call-by-ref parameter. This cleans up confusion + between the enum type and errno-like errors. + +- The new logic puts a limit on how long to follow unit file symlinks: + it will do so only for 64 steps at max. + +- The InstallContext object's fields are renamed to will_process and + has_processed (will_install and has_installed) since they are also + used for deinstallation and all kinds of other operations. + +- The root directory is always verified before use. + +- install.c is reordered to place the exported functions together. + +- Stricter rules are followed when traversing symlinks: the unit suffix + must say identical, and it's not allowed to link between regular units + and templated units. + +- Various modernizations + +- The "invalid" unit file state has been renamed to "bad", in order to + avoid confusion between UNIT_FILE_INVALID and + _UNIT_FILE_STATE_INVALID. Given that the state should normally not be + seen and is not documented this should not be a problematic change. + The new name is now documented however. + +Fixes #1375, #1718, #1706 + +Cherry-picked from: 79413b673b45adc98dfeaec882bbdda2343cb2f9 +Resolves: #1159308 +--- + Makefile.am | 12 +- + man/systemctl.xml | 14 +- + src/core/dbus-manager.c | 6 +- + src/core/dbus-unit.c | 4 +- + src/core/load-fragment.c | 2 +- + src/core/manager.c | 2 +- + src/core/snapshot.c | 2 +- + src/core/unit.c | 19 +- + src/dbus1-generator/dbus1-generator.c | 2 +- + src/firstboot/firstboot.c | 18 +- + src/shared/cgroup-util.c | 6 +- + src/shared/install.c | 1909 +++++++++++++++++++-------------- + src/shared/install.h | 46 +- + src/shared/path-util.c | 34 + + src/shared/path-util.h | 27 + + src/shared/unit-name.c | 32 +- + src/shared/unit-name.h | 14 +- + src/shared/util.c | 21 + + src/shared/util.h | 1 + + src/systemctl/systemctl.c | 6 +- + src/sysv-generator/sysv-generator.c | 10 +- + src/test/test-install-root.c | 663 ++++++++++++ + src/test/test-install.c | 71 +- + 23 files changed, 1998 insertions(+), 923 deletions(-) + create mode 100644 src/test/test-install-root.c + +diff --git a/Makefile.am b/Makefile.am +index 3af720bda..3a09e0a62 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1427,7 +1427,8 @@ tests += \ + test-copy \ + test-cap-list \ + test-sigbus \ +- test-verbs ++ test-verbs \ ++ test-install-root + + EXTRA_DIST += \ + test/a.service \ +@@ -1721,6 +1722,15 @@ test_verbs_SOURCES = \ + test_verbs_LDADD = \ + libsystemd-shared.la + ++test_install_root_SOURCES = \ ++ src/test/test-install-root.c ++ ++test_install_root_LDADD = \ ++ libsystemd-units.la \ ++ libsystemd-label.la \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la ++ + test_namespace_LDADD = \ + libsystemd-core.la + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index c6f584278..2d0678d18 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -905,10 +905,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + list-unit-files PATTERN... + + +- List installed unit files. If one or more +- PATTERNs are specified, only +- units whose filename (just the last component of the path) +- matches one of them are shown. ++ List installed unit files and their enablement state ++ (as reported by is-enabled). If one or ++ more PATTERNs are specified, ++ only units whose filename (just the last component of the ++ path) matches one of them are shown. + + + +@@ -1108,6 +1109,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + Unit file is not enabled. + 1 + ++ ++ bad ++ Unit file is invalid or another error occured. Note that is-enabled wil not actually return this state, but print an error message instead. However the unit file listing printed by list-unit-files might show it. ++ > 0 ++ + + + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 1ec350e03..faa124d92 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1530,9 +1530,9 @@ static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- state = unit_file_get_state(scope, NULL, name); +- if (state < 0) +- return state; ++ r = unit_file_get_state(scope, NULL, name, &state); ++ if (r < 0) ++ return r; + + return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state)); + } +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 625d21ab8..227915efc 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -919,7 +919,7 @@ static int bus_unit_set_transient_property( + if (r < 0) + return r; + +- if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice")) ++ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN) || !endswith(s, ".slice")) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s); + + if (isempty(s)) { +@@ -967,7 +967,7 @@ static int bus_unit_set_transient_property( + return r; + + while ((r = sd_bus_message_read(message, "s", &other)) > 0) { +- if (!unit_name_is_valid(other, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); + + if (mode != UNIT_CHECK) { +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index ec4cf4eef..70c09188a 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3409,7 +3409,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { + * unit name. */ + name = basename(*filename); + +- if (unit_name_is_valid(name, TEMPLATE_VALID)) { ++ if (unit_name_is_valid(name, UNIT_NAME_ANY)) { + + id = set_get(names, name); + if (!id) { +diff --git a/src/core/manager.c b/src/core/manager.c +index 7483a96ec..bde17ce0b 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1328,7 +1328,7 @@ int manager_load_unit_prepare( + + t = unit_name_to_type(name); + +- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, TEMPLATE_INVALID)) ++ if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + + ret = manager_get_unit(m, name); +diff --git a/src/core/snapshot.c b/src/core/snapshot.c +index b1d844877..f222ec232 100644 +--- a/src/core/snapshot.c ++++ b/src/core/snapshot.c +@@ -201,7 +201,7 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, + assert(_s); + + if (name) { +- if (!unit_name_is_valid(name, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(name, UNIT_NAME_PLAIN)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + + if (unit_name_to_type(name) != UNIT_SNAPSHOT) +diff --git a/src/core/unit.c b/src/core/unit.c +index 4fb2fd300..db5aa987e 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -158,7 +158,7 @@ int unit_add_name(Unit *u, const char *text) { + if (!s) + return -ENOMEM; + +- if (!unit_name_is_valid(s, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return -EINVAL; + + assert_se((t = unit_name_to_type(s)) >= 0); +@@ -3119,12 +3119,18 @@ int unit_following_set(Unit *u, Set **s) { + } + + UnitFileState unit_get_unit_file_state(Unit *u) { ++ int r; ++ + assert(u); + +- if (u->unit_file_state < 0 && u->fragment_path) +- u->unit_file_state = unit_file_get_state( +- u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, +- NULL, basename(u->fragment_path)); ++ if (u->unit_file_state < 0 && u->fragment_path) { ++ r = unit_file_get_state(u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, ++ NULL, ++ basename(u->fragment_path), ++ &u->unit_file_state); ++ if (r < 0) ++ u->unit_file_state = UNIT_FILE_BAD; ++ } + + return u->unit_file_state; + } +@@ -3135,7 +3141,8 @@ int unit_get_unit_file_preset(Unit *u) { + if (u->unit_file_preset < 0 && u->fragment_path) + u->unit_file_preset = unit_file_query_preset( + u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, +- NULL, basename(u->fragment_path)); ++ NULL, ++ basename(u->fragment_path)); + + return u->unit_file_preset; + } +diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c +index 2e08af2df..c909a4b1d 100644 +--- a/src/dbus1-generator/dbus1-generator.c ++++ b/src/dbus1-generator/dbus1-generator.c +@@ -188,7 +188,7 @@ static int add_dbus(const char *path, const char *fname, const char *type) { + } + + if (service) { +- if (!unit_name_is_valid(service, TEMPLATE_INVALID)) { ++ if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { + log_warning("Unit name %s is not valid, ignoring.", service); + return 0; + } +diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c +index a37ca170f..b77c1d887 100644 +--- a/src/firstboot/firstboot.c ++++ b/src/firstboot/firstboot.c +@@ -50,8 +50,6 @@ static bool arg_copy_locale = false; + static bool arg_copy_timezone = false; + static bool arg_copy_root_password = false; + +-#define prefix_roota(p) (arg_root ? (const char*) strjoina(arg_root, p) : (const char*) p) +- + static void clear_string(char *x) { + + if (!x) +@@ -85,13 +83,13 @@ static void print_welcome(void) { + if (done) + return; + +- os_release = prefix_roota("/etc/os-release"); ++ os_release = prefix_roota(arg_root, "/etc/os-release"); + r = parse_env_file(os_release, NEWLINE, + "PRETTY_NAME", &pretty_name, + NULL); + if (r == -ENOENT) { + +- os_release = prefix_roota("/usr/lib/os-release"); ++ os_release = prefix_roota(arg_root, "/usr/lib/os-release"); + r = parse_env_file(os_release, NEWLINE, + "PRETTY_NAME", &pretty_name, + NULL); +@@ -249,7 +247,7 @@ static int process_locale(void) { + unsigned i = 0; + int r; + +- etc_localeconf = prefix_roota("/etc/locale.conf"); ++ etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf"); + if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -323,7 +321,7 @@ static int process_timezone(void) { + const char *etc_localtime, *e; + int r; + +- etc_localtime = prefix_roota("/etc/localtime"); ++ etc_localtime = prefix_roota(arg_root, "/etc/localtime"); + if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -402,7 +400,7 @@ static int process_hostname(void) { + const char *etc_hostname; + int r; + +- etc_hostname = prefix_roota("/etc/hostname"); ++ etc_hostname = prefix_roota(arg_root, "/etc/hostname"); + if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -427,7 +425,7 @@ static int process_machine_id(void) { + char id[SD_ID128_STRING_MAX]; + int r; + +- etc_machine_id = prefix_roota("/etc/machine-id"); ++ etc_machine_id = prefix_roota(arg_root, "/etc/machine-id"); + if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -453,7 +451,7 @@ static int prompt_root_password(void) { + if (!arg_prompt_root_password) + return 0; + +- etc_shadow = prefix_roota("/etc/shadow"); ++ etc_shadow = prefix_roota(arg_root, "/etc/shadow"); + if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -542,7 +540,7 @@ static int process_root_password(void) { + const char *etc_shadow; + int r; + +- etc_shadow = prefix_roota("/etc/shadow"); ++ etc_shadow = prefix_roota(arg_root, "/etc/shadow"); + if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index dfd8689b7..cf757d2b2 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -1147,7 +1147,7 @@ int cg_path_decode_unit(const char *cgroup, char **unit){ + c = strndupa(cgroup, e - cgroup); + c = cg_unescape(c); + +- if (!unit_name_is_valid(c, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return -EINVAL; + + s = strdup(c); +@@ -1536,7 +1536,7 @@ int cg_slice_to_path(const char *unit, char **ret) { + assert(unit); + assert(ret); + +- if (!unit_name_is_valid(unit, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN)) + return -EINVAL; + + if (!endswith(unit, ".slice")) +@@ -1553,7 +1553,7 @@ int cg_slice_to_path(const char *unit, char **ret) { + + strcpy(stpncpy(n, p, dash - p), ".slice"); + +- if (!unit_name_is_valid(n, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(n, UNIT_NAME_PLAIN)) + return -EINVAL; + + escaped = cg_escape(n); +diff --git a/src/shared/install.c b/src/shared/install.c +index aa197e91b..5288bb450 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -39,15 +39,24 @@ + #include "specifier.h" + #include "install-printf.h" + #include "special.h" ++#include "fileio.h" ++ ++#define UNIT_FILE_FOLLOW_SYMLINK_MAX 64 ++ ++typedef enum SearchFlags { ++ SEARCH_LOAD = 1, ++ SEARCH_FOLLOW_CONFIG_SYMLINKS = 2, ++} SearchFlags; + + typedef struct { +- OrderedHashmap *will_install; +- OrderedHashmap *have_installed; ++ OrderedHashmap *will_process; ++ OrderedHashmap *have_processed; + } InstallContext; + + static int in_search_path(const char *path, char **search) { + _cleanup_free_ char *parent = NULL; + int r; ++ char **i; + + assert(path); + +@@ -55,7 +64,11 @@ static int in_search_path(const char *path, char **search) { + if (r < 0) + return r; + +- return strv_contains(search, parent); ++ STRV_FOREACH(i, search) ++ if (path_equal(parent, *i)) ++ return true; ++ ++ return false; + } + + static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { +@@ -66,6 +79,9 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(ret); + ++ /* This determines where we shall create or remove our ++ * installation ("configuration") symlinks */ ++ + switch (scope) { + + case UNIT_FILE_SYSTEM: +@@ -113,6 +129,186 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d + return 0; + } + ++static bool is_config_path(UnitFileScope scope, const char *path) { ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(path); ++ ++ /* Checks whether the specified path is intended for ++ * configuration or is outside of it */ ++ ++ switch (scope) { ++ ++ case UNIT_FILE_SYSTEM: ++ case UNIT_FILE_GLOBAL: ++ return path_startswith(path, "/etc") || ++ path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) || ++ path_startswith(path, "/run"); ++ ++ ++ case UNIT_FILE_USER: { ++ _cleanup_free_ char *p = NULL; ++ ++ r = user_config_home(&p); ++ if (r < 0) ++ return r; ++ if (r > 0 && path_startswith(path, p)) ++ return true; ++ ++ free(p); ++ p = NULL; ++ ++ r = user_runtime_dir(&p); ++ if (r < 0) ++ return r; ++ if (r > 0 && path_startswith(path, p)) ++ return true; ++ ++ return false; ++ } ++ ++ default: ++ assert_not_reached("Bad scope"); ++ } ++} ++ ++ ++static int verify_root_dir(UnitFileScope scope, const char **root_dir) { ++ int r; ++ ++ assert(root_dir); ++ ++ /* Verifies that the specified root directory to operate on ++ * makes sense. Reset it to NULL if it is the root directory ++ * or set to empty */ ++ ++ if (isempty(*root_dir) || path_equal(*root_dir, "/")) { ++ *root_dir = NULL; ++ return 0; ++ } ++ ++ if (scope != UNIT_FILE_SYSTEM) ++ return -EINVAL; ++ ++ r = is_dir(*root_dir, true); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return -ENOTDIR; ++ ++ return 0; ++} ++ ++int unit_file_changes_add( ++ UnitFileChange **changes, ++ unsigned *n_changes, ++ UnitFileChangeType type, ++ const char *path, ++ const char *source) { ++ ++ UnitFileChange *c; ++ unsigned i; ++ ++ assert(path); ++ assert(!changes == !n_changes); ++ ++ if (!changes) ++ return 0; ++ ++ c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); ++ if (!c) ++ return -ENOMEM; ++ ++ *changes = c; ++ i = *n_changes; ++ ++ c[i].type = type; ++ c[i].path = strdup(path); ++ if (!c[i].path) ++ return -ENOMEM; ++ ++ path_kill_slashes(c[i].path); ++ ++ if (source) { ++ c[i].source = strdup(source); ++ if (!c[i].source) { ++ free(c[i].path); ++ return -ENOMEM; ++ } ++ ++ path_kill_slashes(c[i].path); ++ } else ++ c[i].source = NULL; ++ ++ *n_changes = i+1; ++ return 0; ++} ++ ++void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { ++ unsigned i; ++ ++ assert(changes || n_changes == 0); ++ ++ if (!changes) ++ return; ++ ++ for (i = 0; i < n_changes; i++) { ++ free(changes[i].path); ++ free(changes[i].source); ++ } ++ ++ free(changes); ++} ++ ++static int create_symlink( ++ const char *old_path, ++ const char *new_path, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ _cleanup_free_ char *dest = NULL; ++ int r; ++ ++ assert(old_path); ++ assert(new_path); ++ ++ /* Actually create a symlink, and remember that we did. Is ++ * smart enough to check if there's already a valid symlink in ++ * place. */ ++ ++ mkdir_parents_label(new_path, 0755); ++ ++ if (symlink(old_path, new_path) >= 0) { ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); ++ return 0; ++ } ++ ++ if (errno != EEXIST) ++ return -errno; ++ ++ r = readlink_malloc(new_path, &dest); ++ if (r < 0) ++ return r; ++ ++ if (path_equal(dest, old_path)) ++ return 0; ++ ++ if (!force) ++ return -EEXIST; ++ ++ r = symlink_atomic(old_path, new_path); ++ if (r < 0) ++ return r; ++ ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); ++ ++ return 0; ++} ++ + static int mark_symlink_for_removal( + Set **remove_symlinks_to, + const char *p) { +@@ -136,7 +332,7 @@ static int mark_symlink_for_removal( + if (r < 0) + return r == -EEXIST ? 0 : r; + +- return 0; ++ return 1; + } + + static int remove_marked_symlinks_fd( +@@ -144,10 +340,9 @@ static int remove_marked_symlinks_fd( + int fd, + const char *path, + const char *config_path, +- bool *deleted, ++ bool *restart, + UnitFileChange **changes, +- unsigned *n_changes, +- char** instance_whitelist) { ++ unsigned *n_changes) { + + _cleanup_closedir_ DIR *d = NULL; + int r = 0; +@@ -156,7 +351,7 @@ static int remove_marked_symlinks_fd( + assert(fd >= 0); + assert(path); + assert(config_path); +- assert(deleted); ++ assert(restart); + + d = fdopendir(fd); + if (!d) { +@@ -205,42 +400,23 @@ static int remove_marked_symlinks_fd( + } + + /* This will close nfd, regardless whether it succeeds or not */ +- q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, instance_whitelist); ++ q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes); + if (q < 0 && r == 0) + r = q; + + } else if (de->d_type == DT_LNK) { + _cleanup_free_ char *p = NULL, *dest = NULL; +- int q; + bool found; ++ int q; + +- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) + continue; + +- if (unit_name_is_instance(de->d_name) && +- instance_whitelist && +- !strv_contains(instance_whitelist, de->d_name)) { +- +- _cleanup_free_ char *w; +- +- /* OK, the file is not listed directly +- * in the whitelist, so let's check if +- * the template of it might be +- * listed. */ +- +- w = unit_name_template(de->d_name); +- if (!w) +- return -ENOMEM; +- +- if (!strv_contains(instance_whitelist, w)) +- continue; +- } +- + p = path_make_absolute(de->d_name, path); + if (!p) + return -ENOMEM; + +- q = readlink_and_canonicalize(p, &dest); ++ q = readlink_malloc(p, &dest); + if (q < 0) { + if (q == -ENOENT) + continue; +@@ -250,9 +426,15 @@ static int remove_marked_symlinks_fd( + continue; + } + ++ /* We remove all links pointing to a file or ++ * path that is marked, as well as all files ++ * sharing the same name as a file that is ++ * marked. */ ++ + found = +- set_get(remove_symlinks_to, dest) || +- set_get(remove_symlinks_to, basename(dest)); ++ set_contains(remove_symlinks_to, dest) || ++ set_contains(remove_symlinks_to, basename(dest)) || ++ set_contains(remove_symlinks_to, de->d_name); + + if (!found) + continue; +@@ -264,18 +446,15 @@ static int remove_marked_symlinks_fd( + } + + path_kill_slashes(p); +- rmdir_parents(p, config_path); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); ++ (void) rmdir_parents(p, config_path); + +- if (!set_get(remove_symlinks_to, p)) { ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); + +- q = mark_symlink_for_removal(&remove_symlinks_to, p); +- if (q < 0) { +- if (r == 0) +- r = q; +- } else +- *deleted = true; +- } ++ q = mark_symlink_for_removal(&remove_symlinks_to, p); ++ if (q < 0) ++ return q; ++ if (q > 0) ++ *restart = true; + } + } + +@@ -286,12 +465,11 @@ static int remove_marked_symlinks( + Set *remove_symlinks_to, + const char *config_path, + UnitFileChange **changes, +- unsigned *n_changes, +- char** instance_whitelist) { ++ unsigned *n_changes) { + + _cleanup_close_ int fd = -1; + int r = 0; +- bool deleted; ++ bool restart; + + assert(config_path); + +@@ -304,7 +482,7 @@ static int remove_marked_symlinks( + + do { + int q, cfd; +- deleted = false; ++ restart = false; + + cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (cfd < 0) { +@@ -313,15 +491,16 @@ static int remove_marked_symlinks( + } + + /* This takes possession of cfd and closes it */ +- q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, instance_whitelist); ++ q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes); + if (r == 0) + r = q; +- } while (deleted); ++ } while (restart); + + return r; + } + + static int find_symlinks_fd( ++ const char *root_dir, + const char *name, + int fd, + const char *path, +@@ -380,7 +559,7 @@ static int find_symlinks_fd( + } + + /* This will close nfd, regardless whether it succeeds or not */ +- q = find_symlinks_fd(name, nfd, p, config_path, same_name_link); ++ q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link); + if (q > 0) + return 1; + if (r == 0) +@@ -397,7 +576,7 @@ static int find_symlinks_fd( + return -ENOMEM; + + /* Acquire symlink destination */ +- q = readlink_and_canonicalize(p, &dest); ++ q = readlink_malloc(p, &dest); + if (q < 0) { + if (q == -ENOENT) + continue; +@@ -407,6 +586,18 @@ static int find_symlinks_fd( + continue; + } + ++ /* Make absolute */ ++ if (!path_is_absolute(dest)) { ++ char *x; ++ ++ x = prefix_root(root_dir, dest); ++ if (!x) ++ return -ENOMEM; ++ ++ free(dest); ++ dest = x; ++ } ++ + /* Check if the symlink itself matches what we + * are looking for */ + if (path_is_absolute(name)) +@@ -442,6 +633,7 @@ static int find_symlinks_fd( + } + + static int find_symlinks( ++ const char *root_dir, + const char *name, + const char *config_path, + bool *same_name_link) { +@@ -460,7 +652,7 @@ static int find_symlinks( + } + + /* This takes possession of fd and closes it */ +- return find_symlinks_fd(name, fd, config_path, config_path, same_name_link); ++ return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link); + } + + static int find_symlinks_in_scope( +@@ -469,385 +661,104 @@ static int find_symlinks_in_scope( + const char *name, + UnitFileState *state) { + +- int r; + _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL; + bool same_name_link_runtime = false, same_name_link = false; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- /* First look in runtime config path */ +- r = get_config_path(scope, true, root_dir, &normal_path); ++ /* First look in the normal config path */ ++ r = get_config_path(scope, false, root_dir, &normal_path); + if (r < 0) + return r; + +- r = find_symlinks(name, normal_path, &same_name_link_runtime); ++ r = find_symlinks(root_dir, name, normal_path, &same_name_link); + if (r < 0) + return r; +- else if (r > 0) { +- *state = UNIT_FILE_ENABLED_RUNTIME; ++ if (r > 0) { ++ *state = UNIT_FILE_ENABLED; + return r; + } + +- /* Then look in the normal config path */ +- r = get_config_path(scope, false, root_dir, &runtime_path); ++ /* Then look in runtime config path */ ++ r = get_config_path(scope, true, root_dir, &runtime_path); + if (r < 0) + return r; + +- r = find_symlinks(name, runtime_path, &same_name_link); ++ r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime); + if (r < 0) + return r; +- else if (r > 0) { +- *state = UNIT_FILE_ENABLED; ++ if (r > 0) { ++ *state = UNIT_FILE_ENABLED_RUNTIME; + return r; + } + + /* Hmm, we didn't find it, but maybe we found the same name + * link? */ ++ if (same_name_link) { ++ *state = UNIT_FILE_LINKED; ++ return 1; ++ } + if (same_name_link_runtime) { + *state = UNIT_FILE_LINKED_RUNTIME; + return 1; +- } else if (same_name_link) { +- *state = UNIT_FILE_LINKED; +- return 1; + } + + return 0; + } + +-int unit_file_mask( +- UnitFileScope scope, +- bool runtime, +- const char *root_dir, +- char **files, +- bool force, +- UnitFileChange **changes, +- unsigned *n_changes) { +- +- char **i; +- _cleanup_free_ char *prefix = NULL; +- int r; ++static void install_info_free(InstallInfo *i) { + +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ if (!i) ++ return; + +- r = get_config_path(scope, runtime, root_dir, &prefix); +- if (r < 0) +- return r; ++ free(i->name); ++ free(i->path); ++ strv_free(i->aliases); ++ strv_free(i->wanted_by); ++ strv_free(i->required_by); ++ strv_free(i->also); ++ free(i->default_instance); ++ free(i->symlink_target); ++ free(i); ++} + +- STRV_FOREACH(i, files) { +- _cleanup_free_ char *path = NULL; ++static OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) { ++ InstallInfo *i; + +- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) { +- if (r == 0) +- r = -EINVAL; +- continue; +- } ++ while ((i = ordered_hashmap_steal_first(m))) ++ install_info_free(i); + +- path = path_make_absolute(*i, prefix); +- if (!path) { +- r = -ENOMEM; +- break; +- } ++ ordered_hashmap_free(m); + +- if (symlink("/dev/null", path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); +- continue; +- } ++ return NULL; ++} + +- if (errno == EEXIST) { ++static void install_context_done(InstallContext *c) { ++ assert(c); + +- if (null_or_empty_path(path) > 0) +- continue; ++ c->will_process = install_info_hashmap_free(c->will_process); ++ c->have_processed = install_info_hashmap_free(c->have_processed); ++} + +- if (force) { +- if (symlink_atomic("/dev/null", path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); +- continue; +- } +- } ++static InstallInfo *install_info_find(InstallContext *c, const char *name) { ++ InstallInfo *i; + +- if (r == 0) +- r = -EEXIST; +- } else { +- if (r == 0) +- r = -errno; +- } +- } ++ i = ordered_hashmap_get(c->have_processed, name); ++ if (i) ++ return i; + +- return r; +-} +- +-int unit_file_unmask( +- UnitFileScope scope, +- bool runtime, +- const char *root_dir, +- char **files, +- UnitFileChange **changes, +- unsigned *n_changes) { +- +- char **i, *config_path = NULL; +- int r, q; +- Set *remove_symlinks_to = NULL; +- +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); +- +- r = get_config_path(scope, runtime, root_dir, &config_path); +- if (r < 0) +- goto finish; +- +- STRV_FOREACH(i, files) { +- _cleanup_free_ char *path = NULL; +- +- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) { +- if (r == 0) +- r = -EINVAL; +- continue; +- } +- +- path = path_make_absolute(*i, config_path); +- if (!path) { +- r = -ENOMEM; +- break; +- } +- +- q = null_or_empty_path(path); +- if (q > 0) { +- if (unlink(path) < 0) +- q = -errno; +- else { +- q = mark_symlink_for_removal(&remove_symlinks_to, path); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- } +- } +- +- if (q != -ENOENT && r == 0) +- r = q; +- } +- +- +-finish: +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); +- if (r == 0) +- r = q; +- +- set_free_free(remove_symlinks_to); +- free(config_path); +- +- return r; +-} +- +-int unit_file_link( +- UnitFileScope scope, +- bool runtime, +- const char *root_dir, +- char **files, +- bool force, +- UnitFileChange **changes, +- unsigned *n_changes) { +- +- _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- char **i; +- _cleanup_free_ char *config_path = NULL; +- int r, q; +- +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); +- +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); +- if (r < 0) +- return r; +- +- r = get_config_path(scope, runtime, root_dir, &config_path); +- if (r < 0) +- return r; +- +- STRV_FOREACH(i, files) { +- _cleanup_free_ char *path = NULL; +- char *fn; +- struct stat st; +- +- fn = basename(*i); +- +- if (!path_is_absolute(*i) || +- !unit_name_is_valid(fn, TEMPLATE_VALID)) { +- if (r == 0) +- r = -EINVAL; +- continue; +- } +- +- if (lstat(*i, &st) < 0) { +- if (r == 0) +- r = -errno; +- continue; +- } +- +- if (!S_ISREG(st.st_mode)) { +- r = -ENOENT; +- continue; +- } +- +- q = in_search_path(*i, paths.unit_path); +- if (q < 0) +- return q; +- +- if (q > 0) +- continue; +- +- path = path_make_absolute(fn, config_path); +- if (!path) +- return -ENOMEM; +- +- if (symlink(*i, path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); +- continue; +- } +- +- if (errno == EEXIST) { +- _cleanup_free_ char *dest = NULL; +- +- q = readlink_and_make_absolute(path, &dest); +- if (q < 0 && errno != ENOENT) { +- if (r == 0) +- r = q; +- continue; +- } +- +- if (q >= 0 && path_equal(dest, *i)) +- continue; +- +- if (force) { +- if (symlink_atomic(*i, path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); +- continue; +- } +- } +- +- if (r == 0) +- r = -EEXIST; +- } else { +- if (r == 0) +- r = -errno; +- } +- } +- +- return r; +-} +- +-void unit_file_list_free(Hashmap *h) { +- UnitFileList *i; +- +- while ((i = hashmap_steal_first(h))) { +- free(i->path); +- free(i); +- } +- +- hashmap_free(h); +-} +- +-int unit_file_changes_add( +- UnitFileChange **changes, +- unsigned *n_changes, +- UnitFileChangeType type, +- const char *path, +- const char *source) { +- +- UnitFileChange *c; +- unsigned i; +- +- assert(path); +- assert(!changes == !n_changes); +- +- if (!changes) +- return 0; +- +- c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); +- if (!c) +- return -ENOMEM; +- +- *changes = c; +- i = *n_changes; +- +- c[i].type = type; +- c[i].path = strdup(path); +- if (!c[i].path) +- return -ENOMEM; +- +- path_kill_slashes(c[i].path); +- +- if (source) { +- c[i].source = strdup(source); +- if (!c[i].source) { +- free(c[i].path); +- return -ENOMEM; +- } +- +- path_kill_slashes(c[i].path); +- } else +- c[i].source = NULL; +- +- *n_changes = i+1; +- return 0; +-} +- +-void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { +- unsigned i; +- +- assert(changes || n_changes == 0); +- +- if (!changes) +- return; +- +- for (i = 0; i < n_changes; i++) { +- free(changes[i].path); +- free(changes[i].source); +- } +- +- free(changes); +-} +- +-static void install_info_free(InstallInfo *i) { +- assert(i); +- +- free(i->name); +- free(i->path); +- strv_free(i->aliases); +- strv_free(i->wanted_by); +- strv_free(i->required_by); +- strv_free(i->also); +- free(i->default_instance); +- free(i); +-} +- +-static void install_info_hashmap_free(OrderedHashmap *m) { +- InstallInfo *i; +- +- if (!m) +- return; +- +- while ((i = ordered_hashmap_steal_first(m))) +- install_info_free(i); +- +- ordered_hashmap_free(m); +-} +- +-static void install_context_done(InstallContext *c) { +- assert(c); +- +- install_info_hashmap_free(c->will_install); +- install_info_hashmap_free(c->have_installed); +- +- c->will_install = c->have_installed = NULL; ++ return ordered_hashmap_get(c->will_process, name); + } + + static int install_info_add( + InstallContext *c, + const char *name, +- const char *path) { ++ const char *path, ++ InstallInfo **ret) { ++ + InstallInfo *i = NULL; + int r; + +@@ -857,20 +768,24 @@ static int install_info_add( + if (!name) + name = basename(path); + +- if (!unit_name_is_valid(name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- if (ordered_hashmap_get(c->have_installed, name) || +- ordered_hashmap_get(c->will_install, name)) ++ i = install_info_find(c, name); ++ if (i) { ++ if (ret) ++ *ret = i; + return 0; ++ } + +- r = ordered_hashmap_ensure_allocated(&c->will_install, &string_hash_ops); ++ r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops); + if (r < 0) + return r; + + i = new0(InstallInfo, 1); + if (!i) + return -ENOMEM; ++ i->type = _UNIT_FILE_TYPE_INVALID; + + i->name = strdup(name); + if (!i->name) { +@@ -886,10 +801,13 @@ static int install_info_add( + } + } + +- r = ordered_hashmap_put(c->will_install, i->name, i); ++ r = ordered_hashmap_put(c->will_process, i->name, i); + if (r < 0) + goto fail; + ++ if (ret) ++ *ret = i; ++ + return 0; + + fail: +@@ -901,15 +819,16 @@ fail: + + static int install_info_add_auto( + InstallContext *c, +- const char *name_or_path) { ++ const char *name_or_path, ++ InstallInfo **ret) { + + assert(c); + assert(name_or_path); + + if (path_is_absolute(name_or_path)) +- return install_info_add(c, NULL, name_or_path); ++ return install_info_add(c, NULL, name_or_path, ret); + else +- return install_info_add(c, name_or_path, NULL); ++ return install_info_add(c, name_or_path, NULL, ret); + } + + static int config_parse_also( +@@ -928,6 +847,7 @@ static int config_parse_also( + const char *word, *state; + InstallContext *c = data; + InstallInfo *i = userdata; ++ int r; + + assert(filename); + assert(lvalue); +@@ -935,19 +855,20 @@ static int config_parse_also( + + FOREACH_WORD_QUOTED(word, l, rvalue, state) { + _cleanup_free_ char *n; +- int r; + + n = strndup(word, l); + if (!n) + return -ENOMEM; + +- r = install_info_add(c, n, NULL); ++ r = install_info_add(c, n, NULL, NULL); + if (r < 0) + return r; + +- r = strv_extend(&i->also, n); ++ r = strv_push(&i->also, n); + if (r < 0) + return r; ++ ++ n = NULL; + } + if (!isempty(state)) + log_syntax(unit, LOG_ERR, filename, line, EINVAL, +@@ -1026,9 +947,7 @@ static int unit_file_load( + InstallInfo *info, + const char *path, + const char *root_dir, +- bool allow_symlink, +- bool load, +- bool *also) { ++ SearchFlags flags) { + + const ConfigTableItem items[] = { + { "Install", "Alias", config_parse_strv, 0, &info->aliases }, +@@ -1041,7 +960,9 @@ static int unit_file_load( + }; + + _cleanup_fclose_ FILE *f = NULL; +- int fd, r; ++ _cleanup_close_ int fd = -1; ++ struct stat st; ++ int r; + + assert(c); + assert(info); +@@ -1050,20 +971,43 @@ static int unit_file_load( + if (!isempty(root_dir)) + path = strjoina(root_dir, "/", path); + +- if (!load) { +- r = access(path, F_OK) ? -errno : 0; +- return r; ++ if (!(flags & SEARCH_LOAD)) { ++ r = lstat(path, &st); ++ if (r < 0) ++ return -errno; ++ ++ if (null_or_empty(&st)) ++ info->type = UNIT_FILE_TYPE_MASKED; ++ else if (S_ISREG(st.st_mode)) ++ info->type = UNIT_FILE_TYPE_REGULAR; ++ else if (S_ISLNK(st.st_mode)) ++ return -ELOOP; ++ else if (S_ISDIR(st.st_mode)) ++ return -EISDIR; ++ else ++ return -ENOTTY; ++ ++ return 0; + } + +- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW)); ++ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; ++ if (fstat(fd, &st) < 0) ++ return -errno; ++ if (null_or_empty(&st)) { ++ info->type = UNIT_FILE_MASKED; ++ return 0; ++ } ++ if (S_ISDIR(st.st_mode)) ++ return -EISDIR; ++ if (!S_ISREG(st.st_mode)) ++ return -ENOTTY; + + f = fdopen(fd, "re"); +- if (!f) { +- safe_close(fd); +- return -ENOMEM; +- } ++ if (!f) ++ return -errno; ++ fd = -1; + + r = config_parse(NULL, path, f, + NULL, +@@ -1072,8 +1016,7 @@ static int unit_file_load( + if (r < 0) + return r; + +- if (also) +- *also = !strv_isempty(info->also); ++ info->type = UNIT_FILE_TYPE_REGULAR; + + return + (int) strv_length(info->aliases) + +@@ -1081,14 +1024,73 @@ static int unit_file_load( + (int) strv_length(info->required_by); + } + ++static int unit_file_load_or_readlink( ++ InstallContext *c, ++ InstallInfo *info, ++ const char *path, ++ const char *root_dir, ++ SearchFlags flags) { ++ ++ _cleanup_free_ char *np = NULL; ++ int r; ++ ++ r = unit_file_load(c, info, path, root_dir, flags); ++ if (r != -ELOOP) ++ return r; ++ ++ /* This is a symlink, let's read it. */ ++ ++ r = readlink_and_make_absolute_root(root_dir, path, &np); ++ if (r < 0) ++ return r; ++ ++ if (path_equal(np, "/dev/null")) ++ info->type = UNIT_FILE_TYPE_MASKED; ++ else { ++ const char *bn; ++ UnitType a, b; ++ ++ bn = basename(np); ++ ++ if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) { ++ ++ if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN)) ++ return -EINVAL; ++ ++ } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { ++ ++ if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) ++ return -EINVAL; ++ ++ } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) { ++ ++ if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) ++ return -EINVAL; ++ } else ++ return -EINVAL; ++ ++ /* Enforce that the symlink destination does not ++ * change the unit file type. */ ++ ++ a = unit_name_to_type(info->name); ++ b = unit_name_to_type(bn); ++ if (a < 0 || b < 0 || a != b) ++ return -EINVAL; ++ ++ info->type = UNIT_FILE_TYPE_SYMLINK; ++ info->symlink_target = np; ++ np = NULL; ++ } ++ ++ return 0; ++} ++ + static int unit_file_search( + InstallContext *c, + InstallInfo *info, + const LookupPaths *paths, + const char *root_dir, +- bool allow_symlink, +- bool load, +- bool *also) { ++ SearchFlags flags) { + + char **p; + int r; +@@ -1097,8 +1099,12 @@ static int unit_file_search( + assert(info); + assert(paths); + ++ /* Was this unit already loaded? */ ++ if (info->type != _UNIT_FILE_TYPE_INVALID) ++ return 0; ++ + if (info->path) +- return unit_file_load(c, info, info->path, root_dir, allow_symlink, load, also); ++ return unit_file_load_or_readlink(c, info, info->path, root_dir, flags); + + assert(info->name); + +@@ -1109,14 +1115,15 @@ static int unit_file_search( + if (!path) + return -ENOMEM; + +- r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also); +- if (r >= 0) { ++ r = unit_file_load_or_readlink(c, info, path, root_dir, flags); ++ if (r < 0) { ++ if (r != -ENOENT) ++ return r; ++ } else { + info->path = path; + path = NULL; + return r; + } +- if (r != -ENOENT && r != -ELOOP) +- return r; + } + + if (unit_name_is_instance(info->name)) { +@@ -1138,92 +1145,149 @@ static int unit_file_search( + if (!path) + return -ENOMEM; + +- r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also); +- if (r >= 0) { ++ r = unit_file_load_or_readlink(c, info, path, root_dir, flags); ++ if (r < 0) { ++ if (r != -ENOENT) ++ return r; ++ } else { + info->path = path; + path = NULL; + return r; + } +- if (r != -ENOENT && r != -ELOOP) +- return r; + } + } + + return -ENOENT; + } + +-static int unit_file_can_install( +- const LookupPaths *paths, ++static int install_info_follow( ++ InstallContext *c, ++ InstallInfo *i, + const char *root_dir, +- const char *name, +- bool allow_symlink, +- bool *also) { ++ SearchFlags flags) { ++ ++ assert(c); ++ assert(i); ++ ++ if (i->type != UNIT_FILE_TYPE_SYMLINK) ++ return -EINVAL; ++ if (!i->symlink_target) ++ return -EINVAL; ++ ++ /* If the basename doesn't match, the caller should add a ++ * complete new entry for this. */ ++ ++ if (!streq(basename(i->symlink_target), i->name)) ++ return -EXDEV; ++ ++ free(i->path); ++ i->path = i->symlink_target; ++ i->symlink_target = NULL; ++ i->type = _UNIT_FILE_TYPE_INVALID; ++ ++ return unit_file_load_or_readlink(c, i, i->path, root_dir, flags); ++} ++ ++static int install_info_traverse( ++ UnitFileScope scope, ++ InstallContext *c, ++ const char *root_dir, ++ const LookupPaths *paths, ++ InstallInfo *start, ++ SearchFlags flags, ++ InstallInfo **ret) { + +- _cleanup_(install_context_done) InstallContext c = {}; + InstallInfo *i; ++ unsigned k = 0; + int r; + + assert(paths); +- assert(name); ++ assert(start); ++ assert(c); + +- r = install_info_add_auto(&c, name); ++ r = unit_file_search(c, start, paths, root_dir, flags); + if (r < 0) + return r; + +- assert_se(i = ordered_hashmap_first(c.will_install)); ++ i = start; ++ while (i->type == UNIT_FILE_TYPE_SYMLINK) { ++ /* Follow the symlink */ + +- r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true, also); ++ if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX) ++ return -ELOOP; + +- if (r >= 0) +- r = +- (int) strv_length(i->aliases) + +- (int) strv_length(i->wanted_by) + +- (int) strv_length(i->required_by); ++ if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path)) ++ return -ELOOP; + +- return r; +-} ++ r = install_info_follow(c, i, root_dir, flags); ++ if (r < 0) { ++ _cleanup_free_ char *buffer = NULL; ++ const char *bn; + +-static int create_symlink( +- const char *old_path, +- const char *new_path, +- bool force, +- UnitFileChange **changes, +- unsigned *n_changes) { ++ if (r != -EXDEV) ++ return r; + +- _cleanup_free_ char *dest = NULL; +- int r; ++ /* Target has a different name, create a new ++ * install info object for that, and continue ++ * with that. */ + +- assert(old_path); +- assert(new_path); ++ bn = basename(i->symlink_target); + +- mkdir_parents_label(new_path, 0755); ++ if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) && ++ unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) { + +- if (symlink(old_path, new_path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); +- return 0; ++ _cleanup_free_ char *instance = NULL; ++ ++ r = unit_name_to_instance(i->name, &instance); ++ if (r < 0) ++ return r; ++ ++ buffer = unit_name_replace_instance(bn, instance); ++ if (!buffer) ++ return -ENOMEM; ++ ++ bn = buffer; ++ } ++ ++ r = install_info_add(c, bn, NULL, &i); ++ if (r < 0) ++ return r; ++ ++ r = unit_file_search(c, i, paths, root_dir, flags); ++ if (r < 0) ++ return r; ++ } ++ ++ /* Try again, with the new target we found. */ + } + +- if (errno != EEXIST) +- return -errno; ++ if (ret) ++ *ret = i; + +- r = readlink_and_make_absolute(new_path, &dest); +- if (r < 0) +- return r; ++ return 0; ++} ++ ++static int install_info_discover( ++ UnitFileScope scope, ++ InstallContext *c, ++ const char *root_dir, ++ const LookupPaths *paths, ++ const char *name, ++ SearchFlags flags, ++ InstallInfo **ret) { + +- if (path_equal(dest, old_path)) +- return 0; ++ InstallInfo *i; ++ int r; + +- if (!force) +- return -EEXIST; ++ assert(c); ++ assert(paths); ++ assert(name); + +- r = symlink_atomic(old_path, new_path); ++ r = install_info_add_auto(c, name, &i); + if (r < 0) + return r; + +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); +- +- return 0; ++ return install_info_traverse(scope, c, root_dir, paths, i, flags, ret); + } + + static int install_info_symlink_alias( +@@ -1298,7 +1362,7 @@ static int install_info_symlink_wants( + if (q < 0) + return q; + +- if (!unit_name_is_valid(dst, TEMPLATE_VALID)) { ++ if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) { + r = -EINVAL; + continue; + } +@@ -1358,6 +1422,9 @@ static int install_info_apply( + assert(paths); + assert(config_path); + ++ if (i->type != UNIT_FILE_TYPE_REGULAR) ++ return 0; ++ + r = install_info_symlink_alias(i, config_path, force, changes, n_changes); + + q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes); +@@ -1376,53 +1443,59 @@ static int install_info_apply( + } + + static int install_context_apply( ++ UnitFileScope scope, + InstallContext *c, + const LookupPaths *paths, + const char *config_path, + const char *root_dir, + bool force, ++ SearchFlags flags, + UnitFileChange **changes, + unsigned *n_changes) { + + InstallInfo *i; +- int r, q; ++ int r; + + assert(c); + assert(paths); + assert(config_path); + +- if (!ordered_hashmap_isempty(c->will_install)) { +- r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); +- if (r < 0) +- return r; ++ if (ordered_hashmap_isempty(c->will_process)) ++ return 0; + +- r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install)); +- if (r < 0) +- return r; +- } ++ r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); ++ if (r < 0) ++ return r; + + r = 0; +- while ((i = ordered_hashmap_first(c->will_install))) { +- assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); ++ while ((i = ordered_hashmap_first(c->will_process))) { ++ int q; + +- q = unit_file_search(c, i, paths, root_dir, false, true, NULL); +- if (q < 0) { +- if (r >= 0) +- r = q; ++ q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); ++ if (q < 0) ++ return q; + ++ r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL); ++ if (r < 0) + return r; +- } else if (r >= 0) +- r += q; ++ ++ if (i->type != UNIT_FILE_TYPE_REGULAR) ++ continue; + + q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes); +- if (r >= 0 && q < 0) +- r = q; ++ if (r >= 0) { ++ if (q < 0) ++ r = q; ++ else ++ r+= q; ++ } + } + + return r; + } + + static int install_context_mark_for_removal( ++ UnitFileScope scope, + InstallContext *c, + const LookupPaths *paths, + Set **remove_symlinks_to, +@@ -1430,96 +1503,109 @@ static int install_context_mark_for_removal( + const char *root_dir) { + + InstallInfo *i; +- int r, q; ++ int r; + + assert(c); + assert(paths); + assert(config_path); + + /* Marks all items for removal */ +- +- if (!ordered_hashmap_isempty(c->will_install)) { +- r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); ++ if (!ordered_hashmap_isempty(c->will_process)) { ++ r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); + if (r < 0) + return r; + +- r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install)); ++ r = ordered_hashmap_reserve(c->have_processed, ordered_hashmap_size(c->will_process)); + if (r < 0) + return r; + } + + r = 0; +- while ((i = ordered_hashmap_first(c->will_install))) { +- assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); +- +- q = unit_file_search(c, i, paths, root_dir, false, true, NULL); +- if (q == -ENOENT) { +- /* do nothing */ +- } else if (q < 0) { +- if (r >= 0) +- r = q; ++ while ((i = ordered_hashmap_first(c->will_process))) { ++ ++ r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); ++ if (r < 0) ++ return r; + ++ r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); ++ if (r < 0) + return r; +- } else if (r >= 0) +- r += q; +- +- if (unit_name_is_instance(i->name)) { +- char *unit_file; +- +- if (i->path) { +- unit_file = basename(i->path); +- +- if (unit_name_is_instance(unit_file)) +- /* unit file named as instance exists, thus all symlinks +- * pointing to it will be removed */ +- q = mark_symlink_for_removal(remove_symlinks_to, i->name); +- else +- /* does not exist, thus we will mark for removal symlinks +- * to template unit file */ +- q = mark_symlink_for_removal(remove_symlinks_to, unit_file); +- } else { +- /* If i->path is not set, it means that we didn't actually find +- * the unit file. But we can still remove symlinks to the +- * nonexistent template. */ +- unit_file = unit_name_template(i->name); +- if (!unit_file) +- return log_oom(); +- +- q = mark_symlink_for_removal(remove_symlinks_to, unit_file); +- free(unit_file); +- } +- } else +- q = mark_symlink_for_removal(remove_symlinks_to, i->name); + +- if (r >= 0 && q < 0) ++ if (i->type != UNIT_FILE_TYPE_REGULAR) ++ continue; ++ ++ r = mark_symlink_for_removal(remove_symlinks_to, i->name); ++ if (r < 0) ++ return r; ++ } ++ ++ return 0; ++} ++ ++int unit_file_mask( ++ UnitFileScope scope, ++ bool runtime, ++ const char *root_dir, ++ char **files, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ _cleanup_free_ char *prefix = NULL; ++ char **i; ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ r = get_config_path(scope, runtime, root_dir, &prefix); ++ if (r < 0) ++ return r; ++ ++ STRV_FOREACH(i, files) { ++ _cleanup_free_ char *path = NULL; ++ int q; ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) { ++ if (r == 0) ++ r = -EINVAL; ++ continue; ++ } ++ ++ path = path_make_absolute(*i, prefix); ++ if (!path) ++ return -ENOMEM; ++ ++ q = create_symlink("/dev/null", path, force, changes, n_changes); ++ if (q < 0 && r >= 0) + r = q; + } + + return r; + } + +-int unit_file_add_dependency( ++int unit_file_unmask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, +- char *target, +- UnitDependency dep, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +- _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- _cleanup_(install_context_done) InstallContext c = {}; ++ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + _cleanup_free_ char *config_path = NULL; ++ _cleanup_free_ char **todo = NULL; ++ size_t n_todo = 0, n_allocated = 0; + char **i; +- int r; +- InstallInfo *info; ++ int r, q; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + +@@ -1528,57 +1614,222 @@ int unit_file_add_dependency( + return r; + + STRV_FOREACH(i, files) { +- UnitFileState state; ++ _cleanup_free_ char *path = NULL; + +- state = unit_file_get_state(scope, root_dir, *i); +- if (state < 0) +- return log_error_errno(state, "Failed to get unit file state for %s: %m", *i); ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) ++ return -EINVAL; + +- if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { +- log_error("Failed to enable unit: Unit %s is masked", *i); +- return -ENOTSUP; +- } ++ path = path_make_absolute(*i, config_path); ++ if (!path) ++ return -ENOMEM; + +- r = install_info_add_auto(&c, *i); ++ r = null_or_empty_path(path); ++ if (r == -ENOENT) ++ continue; + if (r < 0) + return r; ++ if (r == 0) ++ continue; ++ ++ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) ++ return -ENOMEM; ++ ++ todo[n_todo++] = *i; + } + +- if (!ordered_hashmap_isempty(c.will_install)) { +- r = ordered_hashmap_ensure_allocated(&c.have_installed, &string_hash_ops); +- if (r < 0) +- return r; ++ strv_uniq(todo); + +- r = ordered_hashmap_reserve(c.have_installed, ordered_hashmap_size(c.will_install)); +- if (r < 0) +- return r; ++ r = 0; ++ STRV_FOREACH(i, todo) { ++ _cleanup_free_ char *path = NULL; ++ ++ path = path_make_absolute(*i, config_path); ++ if (!path) ++ return -ENOMEM; ++ ++ if (unlink(path) < 0) { ++ if (errno != -ENOENT && r >= 0) ++ r = -errno; ++ } else { ++ q = mark_symlink_for_removal(&remove_symlinks_to, path); ++ if (q < 0) ++ return q; ++ ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); ++ } + } + +- while ((info = ordered_hashmap_first(c.will_install))) { +- assert_se(ordered_hashmap_move_one(c.have_installed, c.will_install, info->name) == 0); ++ q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); ++ if (r >= 0) ++ r = q; + +- r = unit_file_search(&c, info, &paths, root_dir, false, false, NULL); +- if (r < 0) +- return r; ++ return r; ++} + +- if (dep == UNIT_WANTS) +- r = strv_extend(&info->wanted_by, target); +- else if (dep == UNIT_REQUIRES) +- r = strv_extend(&info->required_by, target); +- else +- r = -EINVAL; ++int unit_file_link( ++ UnitFileScope scope, ++ bool runtime, ++ const char *root_dir, ++ char **files, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { + +- if (r < 0) +- return r; ++ _cleanup_lookup_paths_free_ LookupPaths paths = {}; ++ _cleanup_free_ char *config_path = NULL; ++ _cleanup_free_ char **todo = NULL; ++ size_t n_todo = 0, n_allocated = 0; ++ char **i; ++ int r,q; + +- r = install_info_apply(info, &paths, config_path, root_dir, force, changes, n_changes); +- if (r < 0) +- return r; ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ if (r < 0) ++ return r; ++ ++ r = get_config_path(scope, runtime, root_dir, &config_path); ++ if (r < 0) ++ return r; ++ ++ STRV_FOREACH(i, files) { ++ _cleanup_free_ char *full = NULL; ++ struct stat st; ++ char *fn; ++ ++ if (!path_is_absolute(*i)) ++ return -EINVAL; ++ ++ fn = basename(*i); ++ if (!unit_name_is_valid(fn, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ full = prefix_root(root_dir, *i); ++ if (!full) ++ return -ENOMEM; ++ ++ if (lstat(full, &st) < 0) ++ return -errno; ++ if (S_ISLNK(st.st_mode)) ++ return -ELOOP; ++ if (S_ISDIR(st.st_mode)) ++ return -EISDIR; ++ if (!S_ISREG(st.st_mode)) ++ return -ENOTTY; ++ ++ q = in_search_path(*i, paths.unit_path); ++ if (q < 0) ++ return q; ++ if (q > 0) ++ continue; ++ ++ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) ++ return -ENOMEM; ++ ++ todo[n_todo++] = *i; + } + +- return 0; ++ strv_uniq(todo); ++ ++ r = 0; ++ STRV_FOREACH(i, todo) { ++ _cleanup_free_ char *path = NULL; ++ ++ path = path_make_absolute(basename(*i), config_path); ++ if (!path) ++ return -ENOMEM; ++ ++ q = create_symlink(*i, path, force, changes, n_changes); ++ if (q < 0 && r >= 0) ++ r = q; ++ } ++ ++ return r; ++} ++ ++int unit_file_add_dependency( ++ UnitFileScope scope, ++ bool runtime, ++ const char *root_dir, ++ char **files, ++ const char *target, ++ UnitDependency dep, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ _cleanup_lookup_paths_free_ LookupPaths paths = {}; ++ _cleanup_(install_context_done) InstallContext c = {}; ++ _cleanup_free_ char *config_path = NULL; ++ InstallInfo *i, *target_info; ++ char **f; ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(target); ++ ++ if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES)) ++ return -EINVAL; ++ ++ if (!unit_name_is_valid(target, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ if (r < 0) ++ return r; ++ ++ r = get_config_path(scope, runtime, root_dir, &config_path); ++ if (r < 0) ++ return r; ++ ++ r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); ++ if (r < 0) ++ return r; ++ if (target_info->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ ++ assert(target_info->type == UNIT_FILE_TYPE_REGULAR); ++ ++ STRV_FOREACH(f, files) { ++ char ***l; ++ ++ r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ ++ assert(i->type == UNIT_FILE_TYPE_REGULAR); ++ ++ /* We didn't actually load anything from the unit ++ * file, but instead just add in our new symlink to ++ * create. */ ++ ++ if (dep == UNIT_WANTS) ++ l = &i->wanted_by; ++ else ++ l = &i->required_by; ++ ++ strv_free(*l); ++ *l = strv_new(target_info->name, NULL); ++ if (!*l) ++ return -ENOMEM; ++ } ++ ++ return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + } + ++ + int unit_file_enable( + UnitFileScope scope, + bool runtime, +@@ -1590,13 +1841,18 @@ int unit_file_enable( + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(install_context_done) InstallContext c = {}; +- char **i; + _cleanup_free_ char *config_path = NULL; ++ InstallInfo *i; ++ char **f; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -1605,21 +1861,14 @@ int unit_file_enable( + if (r < 0) + return r; + +- STRV_FOREACH(i, files) { +- UnitFileState state; +- +- /* We only want to know if this unit is masked, so we ignore +- * errors from unit_file_get_state, deferring other checks. +- * This allows templated units to be enabled on the fly. */ +- state = unit_file_get_state(scope, root_dir, *i); +- if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { +- log_error("Failed to enable unit: Unit %s is masked", *i); +- return -ENOTSUP; +- } +- +- r = install_info_add_auto(&c, *i); ++ STRV_FOREACH(f, files) { ++ r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i); + if (r < 0) + return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ ++ assert(i->type == UNIT_FILE_TYPE_REGULAR); + } + + /* This will return the number of symlink rules that were +@@ -1627,7 +1876,7 @@ int unit_file_enable( + useful to determine whether the passed files had any + installation data at all. */ + +- return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); ++ return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); + } + + int unit_file_disable( +@@ -1640,14 +1889,18 @@ int unit_file_disable( + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(install_context_done) InstallContext c = {}; +- char **i; + _cleanup_free_ char *config_path = NULL; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- int r, q; ++ char **i; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -1657,18 +1910,19 @@ int unit_file_disable( + return r; + + STRV_FOREACH(i, files) { +- r = install_info_add_auto(&c, *i); ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ r = install_info_add(&c, *i, NULL, NULL); + if (r < 0) + return r; + } + +- r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir); +- +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); +- if (r >= 0) +- r = q; ++ r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir); ++ if (r < 0) ++ return r; + +- return r; ++ return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + } + + int unit_file_reenable( +@@ -1679,21 +1933,30 @@ int unit_file_reenable( + bool force, + UnitFileChange **changes, + unsigned *n_changes) { ++ ++ char **n; + int r; ++ size_t l, i; ++ ++ /* First, we invoke the disable command with only the basename... */ ++ l = strv_length(files); ++ n = newa(char*, l+1); ++ for (i = 0; i < l; i++) ++ n[i] = basename(files[i]); ++ n[i] = NULL; + +- r = unit_file_disable(scope, runtime, root_dir, files, +- changes, n_changes); ++ r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes); + if (r < 0) + return r; + +- return unit_file_enable(scope, runtime, root_dir, files, force, +- changes, n_changes); ++ /* But the enable command with the full name */ ++ return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes); + } + + int unit_file_set_default( + UnitFileScope scope, + const char *root_dir, +- const char *file, ++ const char *name, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { +@@ -1701,42 +1964,40 @@ int unit_file_set_default( + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_free_ char *config_path = NULL; +- char *path; ++ InstallInfo *i; ++ const char *path; + int r; +- InstallInfo *i = NULL; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); +- assert(file); ++ assert(name); + +- if (unit_name_to_type(file) != UNIT_TARGET) ++ if (unit_name_to_type(name) != UNIT_TARGET) ++ return -EINVAL; ++ if (streq(name, SPECIAL_DEFAULT_TARGET)) + return -EINVAL; + +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + +- r = get_config_path(scope, false, root_dir, &config_path); ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; + +- r = install_info_add_auto(&c, file); ++ r = get_config_path(scope, false, root_dir, &config_path); + if (r < 0) + return r; + +- assert_se(i = ordered_hashmap_first(c.will_install)); +- +- r = unit_file_search(&c, i, &paths, root_dir, false, true, NULL); ++ r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i); + if (r < 0) + return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; + + path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET); + +- r = create_symlink(i->path, path, force, changes, n_changes); +- if (r < 0) +- return r; +- +- return 0; ++ return create_symlink(i->path, path, force, changes, n_changes); + } + + int unit_file_get_default( +@@ -1745,127 +2006,100 @@ int unit_file_get_default( + char **name) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- char **p; ++ _cleanup_(install_context_done) InstallContext c = {}; ++ InstallInfo *i; ++ char *n; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + +- STRV_FOREACH(p, paths.unit_path) { +- _cleanup_free_ char *path = NULL, *tmp = NULL; +- char *n; +- +- path = path_join(root_dir, *p, SPECIAL_DEFAULT_TARGET); +- if (!path) +- return -ENOMEM; +- +- r = readlink_malloc(path, &tmp); +- if (r == -ENOENT) +- continue; +- else if (r == -EINVAL) +- /* not a symlink */ +- n = strdup(SPECIAL_DEFAULT_TARGET); +- else if (r < 0) +- return r; +- else +- n = strdup(basename(tmp)); ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ if (r < 0) ++ return r; + +- if (!n) +- return -ENOMEM; ++ r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; + +- *name = n; +- return 0; +- } ++ n = strdup(i->name); ++ if (!n) ++ return -ENOMEM; + +- return -ENOENT; ++ *name = n; ++ return 0; + } + + UnitFileState unit_file_lookup_state( + UnitFileScope scope, + const char *root_dir, + const LookupPaths *paths, +- const char *name) { +- +- UnitFileState state = _UNIT_FILE_STATE_INVALID; +- char **i; +- _cleanup_free_ char *path = NULL; ++ const char *name, ++ UnitFileState *ret) { ++ _cleanup_(install_context_done) InstallContext c = {}; ++ InstallInfo *i; ++ UnitFileState state; + int r; + + assert(paths); ++ assert(name); + +- if (!unit_name_is_valid(name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- STRV_FOREACH(i, paths->unit_path) { +- struct stat st; +- char *partial; +- bool also = false; +- +- free(path); +- path = path_join(root_dir, *i, name); +- if (!path) +- return -ENOMEM; ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; + +- if (root_dir) +- partial = path + strlen(root_dir); +- else +- partial = path; ++ r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; + +- /* +- * Search for a unit file in our default paths, to +- * be sure, that there are no broken symlinks. +- */ +- if (lstat(path, &st) < 0) { +- r = -errno; +- if (errno != ENOENT) +- return r; ++ /* Shortcut things, if the caller just wants to know if this unit exists. */ ++ if (!ret) ++ return 0; + +- if (!unit_name_is_instance(name)) +- continue; +- } else { +- if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) +- return -ENOENT; ++ switch (i->type) { + +- r = null_or_empty_path(path); +- if (r < 0 && r != -ENOENT) +- return r; +- else if (r > 0) { +- state = path_startswith(*i, "/run") ? +- UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; +- return state; +- } +- } ++ case UNIT_FILE_TYPE_MASKED: ++ state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; ++ break; + +- r = find_symlinks_in_scope(scope, root_dir, name, &state); ++ case UNIT_FILE_TYPE_REGULAR: ++ r = find_symlinks_in_scope(scope, root_dir, i->name, &state); + if (r < 0) + return r; +- else if (r > 0) +- return state; +- +- r = unit_file_can_install(paths, root_dir, partial, true, &also); +- if (r < 0 && errno != ENOENT) +- return r; +- else if (r > 0) +- return UNIT_FILE_DISABLED; +- else if (r == 0) { +- if (also) +- return UNIT_FILE_INDIRECT; +- return UNIT_FILE_STATIC; ++ if (r == 0) { ++ if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i)) ++ state = UNIT_FILE_DISABLED; ++ else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i)) ++ state = UNIT_FILE_INDIRECT; ++ else ++ state = UNIT_FILE_STATIC; + } ++ ++ break; ++ ++ default: ++ assert_not_reached("Unexpect unit file type."); + } + +- return r < 0 ? r : state; ++ *ret = state; ++ return 0; + } + +-UnitFileState unit_file_get_state( ++int unit_file_get_state( + UnitFileScope scope, + const char *root_dir, +- const char *name) { ++ const char *name, ++ UnitFileState *ret) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + int r; +@@ -1874,14 +2108,15 @@ UnitFileState unit_file_get_state( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- if (root_dir && scope != UNIT_FILE_SYSTEM) +- return -EINVAL; ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; + + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; + +- return unit_file_lookup_state(scope, root_dir, &paths, name); ++ return unit_file_lookup_state(scope, root_dir, &paths, name, ret); + } + + int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { +@@ -1893,6 +2128,13 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ if (!unit_name_is_valid(name, UNIT_NAME_ANY)) ++ return -EINVAL; ++ + if (scope == UNIT_FILE_SYSTEM) + r = conf_files_list(&files, ".preset", root_dir, + "/etc/systemd/system-preset", +@@ -1909,13 +2151,14 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + "/usr/lib/systemd/user-preset", + NULL); + else +- return 1; ++ return 1; /* Default is "enable" */ + + if (r < 0) + return r; + + STRV_FOREACH(p, files) { + _cleanup_fclose_ FILE *f; ++ char line[LINE_MAX]; + + f = fopen(*p, "re"); + if (!f) { +@@ -1925,39 +2168,38 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + return -errno; + } + +- for (;;) { +- char line[LINE_MAX], *l; +- +- if (!fgets(line, sizeof(line), f)) +- break; ++ FOREACH_LINE(line, f, return -errno) { ++ const char *parameter; ++ char *l; + + l = strstrip(line); +- if (!*l) +- continue; + +- if (strchr(COMMENTS "\n", *l)) ++ if (isempty(l)) ++ continue; ++ if (strchr(COMMENTS, *l)) + continue; + +- if (first_word(l, "enable")) { +- l += 6; +- l += strspn(l, WHITESPACE); +- +- if (fnmatch(l, name, FNM_NOESCAPE) == 0) { ++ parameter = first_word(l, "enable"); ++ if (parameter) { ++ if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { + log_debug("Preset file says enable %s.", name); + return 1; + } + +- } else if (first_word(l, "disable")) { +- l += 7; +- l += strspn(l, WHITESPACE); ++ continue; ++ } + +- if (fnmatch(l, name, FNM_NOESCAPE) == 0) { ++ parameter = first_word(l, "disable"); ++ if (parameter) { ++ if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { + log_debug("Preset file says disable %s.", name); + return 0; + } + +- } else +- log_debug("Couldn't parse line '%s'", l); ++ continue; ++ } ++ ++ log_debug("Couldn't parse line '%s'", l); + } + } + +@@ -1966,6 +2208,86 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + return 1; + } + ++static int execute_preset( ++ UnitFileScope scope, ++ InstallContext *plus, ++ InstallContext *minus, ++ const LookupPaths *paths, ++ const char *config_path, ++ const char *root_dir, ++ char **files, ++ UnitFilePresetMode mode, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ int r; ++ ++ assert(plus); ++ assert(minus); ++ assert(paths); ++ assert(config_path); ++ ++ if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { ++ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; ++ ++ r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, root_dir); ++ if (r < 0) ++ return r; ++ ++ r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); ++ } else ++ r = 0; ++ ++ if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { ++ int q; ++ ++ /* Returns number of symlinks that where supposed to be installed. */ ++ q = install_context_apply(scope, plus, paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); ++ if (r >= 0) { ++ if (q < 0) ++ r = q; ++ else ++ r+= q; ++ } ++ } ++ ++ return r; ++} ++ ++static int preset_prepare_one( ++ UnitFileScope scope, ++ InstallContext *plus, ++ InstallContext *minus, ++ LookupPaths *paths, ++ const char *root_dir, ++ UnitFilePresetMode mode, ++ const char *name) { ++ ++ InstallInfo *i; ++ int r; ++ ++ if (install_info_find(plus, name) || ++ install_info_find(minus, name)) ++ return 0; ++ ++ r = unit_file_query_preset(scope, root_dir, name); ++ if (r < 0) ++ return r; ++ ++ if (r > 0) { ++ r = install_info_discover(scope, plus, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ } else ++ r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ ++ return r; ++} ++ + int unit_file_preset( + UnitFileScope scope, + bool runtime, +@@ -1980,12 +2302,16 @@ int unit_file_preset( + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_free_ char *config_path = NULL; + char **i; +- int r, q; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -1995,44 +2321,15 @@ int unit_file_preset( + return r; + + STRV_FOREACH(i, files) { +- +- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + +- r = unit_file_query_preset(scope, root_dir, *i); +- if (r < 0) +- return r; +- +- if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY) +- r = install_info_add_auto(&plus, *i); +- else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY) +- r = install_info_add_auto(&minus, *i); +- else +- r = 0; ++ r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i); + if (r < 0) + return r; + } + +- r = 0; +- +- if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { +- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- +- r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); +- +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); +- if (r == 0) +- r = q; +- } +- +- if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { +- /* Returns number of symlinks that where supposed to be installed. */ +- q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); +- if (r == 0) +- r = q; +- } +- +- return r; ++ return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes); + } + + int unit_file_preset_all( +@@ -2048,12 +2345,16 @@ int unit_file_preset_all( + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_free_ char *config_path = NULL; + char **i; +- int r, q; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -2092,48 +2393,21 @@ int unit_file_preset_all( + if (hidden_file(de->d_name)) + continue; + +- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) + continue; + + dirent_ensure_type(d, de); + +- if (de->d_type != DT_REG) ++ if (!IN_SET(de->d_type, DT_LNK, DT_REG)) + continue; + +- r = unit_file_query_preset(scope, root_dir, de->d_name); +- if (r < 0) +- return r; +- +- if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY) +- r = install_info_add_auto(&plus, de->d_name); +- else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY) +- r = install_info_add_auto(&minus, de->d_name); +- else +- r = 0; ++ r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name); + if (r < 0) + return r; + } + } + +- r = 0; +- +- if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { +- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- +- r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); +- +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, NULL); +- if (r == 0) +- r = q; +- } +- +- if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { +- q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); +- if (r == 0) +- r = q; +- } +- +- return r; ++ return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes); + } + + static void unit_file_list_free_one(UnitFileList *f) { +@@ -2144,6 +2418,17 @@ static void unit_file_list_free_one(UnitFileList *f) { + free(f); + } + ++Hashmap* unit_file_list_free(Hashmap *h) { ++ UnitFileList *i; ++ ++ while ((i = hashmap_steal_first(h))) ++ unit_file_list_free_one(i); ++ ++ hashmap_free(h); ++ ++ return NULL; ++} ++ + DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one); + + int unit_file_get_list( +@@ -2159,14 +2444,9 @@ int unit_file_get_list( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(h); + +- if (root_dir && scope != UNIT_FILE_SYSTEM) +- return -EINVAL; +- +- if (root_dir) { +- r = access(root_dir, F_OK); +- if (r < 0) +- return -errno; +- } ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; + + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) +@@ -2191,7 +2471,6 @@ int unit_file_get_list( + for (;;) { + _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL; + struct dirent *de; +- _cleanup_free_ char *path = NULL; + + errno = 0; + de = readdir(d); +@@ -2204,7 +2483,7 @@ int unit_file_get_list( + if (hidden_file(de->d_name)) + continue; + +- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) + continue; + + if (hashmap_get(h, de->d_name)) +@@ -2223,44 +2502,14 @@ int unit_file_get_list( + if (!f->path) + return -ENOMEM; + +- r = null_or_empty_path(f->path); +- if (r < 0 && r != -ENOENT) +- return r; +- else if (r > 0) { +- f->state = +- path_startswith(*i, "/run") ? +- UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; +- goto found; +- } +- +- r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state); ++ r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state); + if (r < 0) +- return r; +- else if (r > 0) { +- f->state = UNIT_FILE_ENABLED; +- goto found; +- } +- +- path = path_make_absolute(de->d_name, *i); +- if (!path) +- return -ENOMEM; ++ f->state = UNIT_FILE_BAD; + +- r = unit_file_can_install(&paths, root_dir, path, true, NULL); +- if (r == -EINVAL || /* Invalid setting? */ +- r == -EBADMSG || /* Invalid format? */ +- r == -ENOENT /* Included file not found? */) +- f->state = UNIT_FILE_INVALID; +- else if (r < 0) +- return r; +- else if (r > 0) +- f->state = UNIT_FILE_DISABLED; +- else +- f->state = UNIT_FILE_STATIC; +- +- found: + r = hashmap_put(h, basename(f->path), f); + if (r < 0) + return r; ++ + f = NULL; /* prevent cleanup */ + } + } +@@ -2278,7 +2527,7 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { + [UNIT_FILE_STATIC] = "static", + [UNIT_FILE_DISABLED] = "disabled", + [UNIT_FILE_INDIRECT] = "indirect", +- [UNIT_FILE_INVALID] = "invalid", ++ [UNIT_FILE_BAD] = "bad", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); +diff --git a/src/shared/install.h b/src/shared/install.h +index d729e6ed1..87a40b67c 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -24,6 +24,7 @@ + #include "hashmap.h" + #include "unit-name.h" + #include "path-lookup.h" ++#include "strv.h" + + typedef enum UnitFileScope { + UNIT_FILE_SYSTEM, +@@ -43,7 +44,7 @@ typedef enum UnitFileState { + UNIT_FILE_STATIC, + UNIT_FILE_DISABLED, + UNIT_FILE_INDIRECT, +- UNIT_FILE_INVALID, ++ UNIT_FILE_BAD, + _UNIT_FILE_STATE_MAX, + _UNIT_FILE_STATE_INVALID = -1 + } UnitFileState; +@@ -74,6 +75,14 @@ typedef struct UnitFileList { + UnitFileState state; + } UnitFileList; + ++typedef enum UnitFileType { ++ UNIT_FILE_TYPE_REGULAR, ++ UNIT_FILE_TYPE_SYMLINK, ++ UNIT_FILE_TYPE_MASKED, ++ _UNIT_FILE_TYPE_MAX, ++ _UNIT_FILE_TYPE_INVALID = -1, ++} UnitFileType; ++ + typedef struct { + char *name; + char *path; +@@ -85,8 +94,26 @@ typedef struct { + char **also; + + char *default_instance; ++ ++ UnitFileType type; ++ ++ char *symlink_target; + } InstallInfo; + ++static inline bool UNIT_FILE_INSTALL_INFO_HAS_RULES(InstallInfo *i) { ++ assert(i); ++ ++ return !strv_isempty(i->aliases) || ++ !strv_isempty(i->wanted_by) || ++ !strv_isempty(i->required_by); ++} ++ ++static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(InstallInfo *i) { ++ assert(i); ++ ++ return !strv_isempty(i->also); ++} ++ + int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); + int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); + int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +@@ -97,21 +124,14 @@ int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char + int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); + int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); + int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name); +-int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); +- +-UnitFileState unit_file_lookup_state( +- UnitFileScope scope, +- const char *root_dir, +- const LookupPaths *paths, +- const char *name); +-UnitFileState unit_file_get_state( +- UnitFileScope scope, +- const char *root_dir, +- const char *filename); ++int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); ++ ++int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret); ++int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); + + int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); ++Hashmap* unit_file_list_free(Hashmap *h); + +-void unit_file_list_free(Hashmap *h); + int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source); + void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes); + +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index d5510bf56..1181ffb9d 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -704,3 +704,37 @@ int fsck_exists(const char *fstype) { + + return 0; + } ++ ++char *prefix_root(const char *root, const char *path) { ++ char *n, *p; ++ size_t l; ++ ++ /* If root is passed, prefixes path with it. Otherwise returns ++ * it as is. */ ++ ++ assert(path); ++ ++ /* First, drop duplicate prefixing slashes from the path */ ++ while (path[0] == '/' && path[1] == '/') ++ path++; ++ ++ if (isempty(root) || path_equal(root, "/")) ++ return strdup(path); ++ ++ l = strlen(root) + 1 + strlen(path) + 1; ++ ++ n = new(char, l); ++ if (!n) ++ return NULL; ++ ++ p = stpcpy(n, root); ++ ++ while (p > n && p[-1] == '/') ++ p--; ++ ++ if (path[0] != '/') ++ *(p++) = '/'; ++ ++ strcpy(p, path); ++ return n; ++} +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index ca81b49cb..71bb740e9 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -63,6 +63,33 @@ bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool + + int fsck_exists(const char *fstype); + ++char *prefix_root(const char *root, const char *path); ++ ++/* Similar to prefix_root(), but returns an alloca() buffer, or ++ * possibly a const pointer into the path parameter */ ++#define prefix_roota(root, path) \ ++ ({ \ ++ const char* _path = (path), *_root = (root), *_ret; \ ++ char *_p, *_n; \ ++ size_t _l; \ ++ while (_path[0] == '/' && _path[1] == '/') \ ++ _path ++; \ ++ if (isempty(_root) || path_equal(_root, "/")) \ ++ _ret = _path; \ ++ else { \ ++ _l = strlen(_root) + 1 + strlen(_path) + 1; \ ++ _n = alloca(_l); \ ++ _p = stpcpy(_n, _root); \ ++ while (_p > _n && _p[-1] == '/') \ ++ _p--; \ ++ if (_path[0] != '/') \ ++ *(_p++) = '/'; \ ++ strcpy(_p, _path); \ ++ _ret = _n; \ ++ } \ ++ _ret; \ ++ }) ++ + /* Iterates through the path prefixes of the specified path, going up + * the tree, to root. Also returns "" (and not "/"!) for the root + * directory. Excludes the specified directory itself */ +diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c +index f728af4a8..b7827d14b 100644 +--- a/src/shared/unit-name.c ++++ b/src/shared/unit-name.c +@@ -63,16 +63,13 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); + +-bool unit_name_is_valid(const char *n, enum template_valid template_ok) { ++bool unit_name_is_valid(const char *n, UnitNameFlags flags) { + const char *e, *i, *at; + +- /* Valid formats: +- * +- * string@instance.suffix +- * string.suffix +- */ ++ assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0); + +- assert(IN_SET(template_ok, TEMPLATE_VALID, TEMPLATE_INVALID)); ++ if (_unlikely_(flags == 0)) ++ return false; + + if (isempty(n)) + return false; +@@ -96,15 +93,22 @@ bool unit_name_is_valid(const char *n, enum template_valid template_ok) { + return false; + } + +- if (at) { +- if (at == n) +- return false; ++ if (at == n) ++ return false; + +- if (template_ok != TEMPLATE_VALID && at+1 == e) +- return false; +- } ++ if (flags & UNIT_NAME_PLAIN) ++ if (!at) ++ return true; ++ ++ if (flags & UNIT_NAME_INSTANCE) ++ if (at && e > at + 1) ++ return true; ++ ++ if (flags & UNIT_NAME_TEMPLATE) ++ if (at && e == at + 1) ++ return true; + +- return true; ++ return false; + } + + bool unit_instance_is_valid(const char *i) { +diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h +index 6f139cc4c..436486062 100644 +--- a/src/shared/unit-name.h ++++ b/src/shared/unit-name.h +@@ -107,6 +107,13 @@ enum UnitDependency { + _UNIT_DEPENDENCY_INVALID = -1 + }; + ++typedef enum UnitNameFlags { ++ UNIT_NAME_PLAIN = 1, /* Allow foo.service */ ++ UNIT_NAME_INSTANCE = 2, /* Allow foo@bar.service */ ++ UNIT_NAME_TEMPLATE = 4, /* Allow foo@.service */ ++ UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE, ++} UnitNameFlags; ++ + const char *unit_type_to_string(UnitType i) _const_; + UnitType unit_type_from_string(const char *s) _pure_; + +@@ -117,12 +124,7 @@ int unit_name_to_instance(const char *n, char **instance); + char* unit_name_to_prefix(const char *n); + char* unit_name_to_prefix_and_instance(const char *n); + +-enum template_valid { +- TEMPLATE_INVALID, +- TEMPLATE_VALID, +-}; +- +-bool unit_name_is_valid(const char *n, enum template_valid template_ok) _pure_; ++bool unit_name_is_valid(const char *n, UnitNameFlags flags) _pure_; + bool unit_prefix_is_valid(const char *p) _pure_; + bool unit_instance_is_valid(const char *i) _pure_; + +diff --git a/src/shared/util.c b/src/shared/util.c +index a24aa7f93..036677eb4 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -1094,6 +1094,27 @@ int readlink_and_canonicalize(const char *p, char **r) { + return 0; + } + ++ ++int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) { ++ _cleanup_free_ char *target = NULL, *t = NULL; ++ const char *full; ++ int r; ++ ++ full = prefix_roota(root, path); ++ r = readlink_malloc(full, &target); ++ if (r < 0) ++ return r; ++ ++ t = file_in_same_dir(path, target); ++ if (!t) ++ return -ENOMEM; ++ ++ *ret = t; ++ t = NULL; ++ ++ return 0; ++} ++ + int reset_all_signal_handlers(void) { + int sig, r = 0; + +diff --git a/src/shared/util.h b/src/shared/util.h +index b4a4a491f..a441e44ff 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -281,6 +281,7 @@ int readlink_malloc(const char *p, char **r); + int readlink_value(const char *p, char **ret); + int readlink_and_make_absolute(const char *p, char **r); + int readlink_and_canonicalize(const char *p, char **r); ++int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); + + int reset_all_signal_handlers(void); + int reset_signal_mask(void); +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index bf5bb398b..95ddf3be7 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1304,7 +1304,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { + if (u->state == UNIT_FILE_MASKED || + u->state == UNIT_FILE_MASKED_RUNTIME || + u->state == UNIT_FILE_DISABLED || +- u->state == UNIT_FILE_INVALID) { ++ u->state == UNIT_FILE_BAD) { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } else if (u->state == UNIT_FILE_ENABLED) { +@@ -5637,8 +5637,8 @@ static int unit_is_enabled(sd_bus *bus, char **args) { + STRV_FOREACH(name, names) { + UnitFileState state; + +- state = unit_file_get_state(arg_scope, arg_root, *name); +- if (state < 0) ++ r = unit_file_get_state(arg_scope, arg_root, *name, &state); ++ if (r < 0) + return log_error_errno(state, "Failed to get unit file state for %s: %m", *name); + + if (state == UNIT_FILE_ENABLED || +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index d60e75a06..7e0e7fc28 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -712,6 +712,7 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { + + static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + char **path; ++ int r; + + STRV_FOREACH(path, lp->sysvinit_path) { + _cleanup_closedir_ DIR *d = NULL; +@@ -728,7 +729,6 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + _cleanup_free_ char *fpath = NULL, *name = NULL; + _cleanup_free_ SysvStub *service = NULL; + struct stat st; +- int r; + + if (hidden_file(de->d_name)) + continue; +@@ -755,8 +755,12 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + if (!fpath) + return log_oom(); + +- if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) { +- log_debug("Native unit for %s already exists, skipping", name); ++ r = unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name, NULL); ++ if (r < 0 && r != -ENOENT) { ++ log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); ++ continue; ++ } else if (r >= 0) { ++ log_debug("Native unit for %s already exists, skipping.", name); + continue; + } + +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +new file mode 100644 +index 000000000..89d91d3d6 +--- /dev/null ++++ b/src/test/test-install-root.c +@@ -0,0 +1,663 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2011 Lennart Poettering ++ ++ systemd is free software; you can redistribute it and/or modify it ++ under the terms of the GNU Lesser General Public License as published by ++ the Free Software Foundation; either version 2.1 of the License, or ++ (at your option) any later version. ++ ++ systemd is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with systemd; If not, see . ++***/ ++ ++#include "fileio.h" ++#include "install.h" ++#include "mkdir.h" ++#include "util.h" ++ ++static void test_basic_mask_and_enable(const char *root) { ++ const char *p; ++ UnitFileState state; ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/a.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/b.service"); ++ assert_se(symlink("a.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/c.service"); ++ assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/d.service"); ++ assert_se(symlink("c.service", p) >= 0); ++ ++ /* This one is interesting, as d follows a relative, then an absolute symlink */ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/dev/null")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ ++ /* Enabling a masked unit should fail! */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ /* Enabling it again should succeed but be a NOP */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ /* Disabling a disabled unit must suceed but be a NOP */ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ /* Let's enable this indirectly via a symlink */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ /* Let's try to reenable */ ++ ++ assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ assert_se(changes[1].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); ++ assert_se(streq(changes[1].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++} ++ ++static void test_linked_units(const char *root) { ++ const char *p, *q; ++ UnitFileState state; ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0, i; ++ ++ /* ++ * We'll test three cases here: ++ * ++ * a) a unit file in /opt, that we use "systemctl link" and ++ * "systemctl enable" on to make it available to the system ++ * ++ * b) a unit file in /opt, that is statically linked into ++ * /usr/lib/systemd/system, that "enable" should work on ++ * correctly. ++ * ++ * c) a unit file in /opt, that is linked into ++ * /etc/systemd/system, and where "enable" should result in ++ * -ELOOP, since using information from /etc to generate ++ * information in /etc should not be allowed. ++ */ ++ ++ p = strjoina(root, "/opt/linked.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/opt/linked2.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/opt/linked3.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/linked2.service"); ++ assert_se(symlink("/opt/linked2.service", p) >= 0); ++ ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service"); ++ assert_se(symlink("/opt/linked3.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); ++ ++ /* First, let's link the unit into the search path */ ++ assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/opt/linked.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); ++ ++ /* Let's unlink it from the search path again */ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ ++ /* Now, let's not just link it, but also enable it */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); ++ q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ for (i = 0 ; i < n_changes; i++) { ++ assert_se(changes[i].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[i].source, "/opt/linked.service")); ++ ++ if (p && streq(changes[i].path, p)) ++ p = NULL; ++ else if (q && streq(changes[i].path, q)) ++ q = NULL; ++ else ++ assert_not_reached("wut?"); ++ } ++ assert(!p && !q); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ /* And let's unlink it again */ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); ++ q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ for (i = 0; i < n_changes; i++) { ++ assert_se(changes[i].type == UNIT_FILE_UNLINK); ++ ++ if (p && streq(changes[i].path, p)) ++ p = NULL; ++ else if (q && streq(changes[i].path, q)) ++ q = NULL; ++ else ++ assert_not_reached("wut?"); ++ } ++ assert(!p && !q); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service"); ++ q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service"); ++ for (i = 0 ; i < n_changes; i++) { ++ assert_se(changes[i].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[i].source, "/opt/linked2.service")); ++ ++ if (p && streq(changes[i].path, p)) ++ p = NULL; ++ else if (q && streq(changes[i].path, q)) ++ q = NULL; ++ else ++ assert_not_reached("wut?"); ++ } ++ assert(!p && !q); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++} ++ ++static void test_default(const char *root) { ++ _cleanup_free_ char *def = NULL; ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ const char *p; ++ ++ p = strjoina(root, "/usr/lib/systemd/system/test-default-real.target"); ++ assert_se(write_string_file(p, "# pretty much empty") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/test-default.target"); ++ assert_se(symlink("test-default-real.target", p) >= 0); ++ ++ assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); ++ ++ assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); ++ ++ assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/default.target"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0); ++ assert_se(streq_ptr(def, "test-default-real.target")); ++} ++ ++static void test_add_dependency(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ const char *p; ++ ++ p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target"); ++ assert_se(write_string_file(p, "# pretty much empty") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target"); ++ assert_se(symlink("real-add-dependency-test-target.target", p) >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service"); ++ assert_se(write_string_file(p, "# pretty much empty") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); ++ assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); ++ ++ assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++} ++ ++static void test_template_enable(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ UnitFileState state; ++ const char *p; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/template@.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "DefaultInstance=def\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service"); ++ assert_se(symlink("template@.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@def.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++} ++ ++static void test_indirect(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ UnitFileState state; ++ const char *p; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/indirecta.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "Also=indirectb.service\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/indirectb.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/indirectc.service"); ++ assert_se(symlink("indirecta.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++} ++ ++static void test_preset_and_list(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0, i; ++ const char *p, *q; ++ UnitFileState state; ++ bool got_yes = false, got_no = false; ++ Iterator j; ++ UnitFileList *fl; ++ Hashmap *h; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); ++ assert_se(write_string_file(p, ++ "enable *-yes.*\n" ++ "disable *\n") >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ ++ assert_se(n_changes > 0); ++ ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); ++ ++ for (i = 0; i < n_changes; i++) { ++ ++ if (changes[i].type == UNIT_FILE_SYMLINK) { ++ assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); ++ assert_se(streq(changes[i].path, p)); ++ } else ++ assert_se(changes[i].type == UNIT_FILE_UNLINK); ++ } ++ ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(h = hashmap_new(&string_hash_ops)); ++ assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h) >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); ++ q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); ++ ++ HASHMAP_FOREACH(fl, h, j) { ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0); ++ assert_se(fl->state == state); ++ ++ if (streq(fl->path, p)) { ++ got_yes = true; ++ assert_se(fl->state == UNIT_FILE_ENABLED); ++ } else if (streq(fl->path, q)) { ++ got_no = true; ++ assert_se(fl->state == UNIT_FILE_DISABLED); ++ } else ++ assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT)); ++ } ++ ++ unit_file_list_free(h); ++ ++ assert_se(got_yes && got_no); ++} ++ ++int main(int argc, char *argv[]) { ++ char root[] = "/tmp/rootXXXXXX"; ++ const char *p; ++ ++ assert_se(mkdtemp(root)); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, "/run/systemd/system/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, "/opt/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system-preset/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ test_basic_mask_and_enable(root); ++ test_linked_units(root); ++ test_default(root); ++ test_add_dependency(root); ++ test_template_enable(root); ++ test_indirect(root); ++ test_preset_and_list(root); ++ ++ assert_se(rm_rf_dangerous(root, false, true, false)); ++ ++ return 0; ++} +diff --git a/src/test/test-install.c b/src/test/test-install.c +index 467970b00..08a1faf2c 100644 +--- a/src/test/test-install.c ++++ b/src/test/test-install.c +@@ -50,17 +50,19 @@ int main(int argc, char* argv[]) { + const char *const files2[] = { "/home/lennart/test.service", NULL }; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; ++ UnitFileState state = 0; + + h = hashmap_new(&string_hash_ops); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + assert_se(r == 0); + + HASHMAP_FOREACH(p, h, i) { +- UnitFileState s; ++ UnitFileState s = _UNIT_FILE_STATE_INVALID; + +- s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path)); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s); + +- assert_se(p->state == s); ++ assert_se((r < 0 && p->state == UNIT_FILE_BAD) || ++ (p->state == s)); + + fprintf(stderr, "%s (%s)\n", + p->path, +@@ -82,7 +84,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + log_error("disable"); + +@@ -95,7 +99,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_DISABLED); + + log_error("mask"); + changes = NULL; +@@ -110,7 +116,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_MASKED); + + log_error("unmask"); + changes = NULL; +@@ -125,7 +133,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_DISABLED); + + log_error("mask"); + changes = NULL; +@@ -137,7 +147,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_MASKED); + + log_error("disable"); + changes = NULL; +@@ -152,7 +164,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_MASKED); + + log_error("umask"); + changes = NULL; +@@ -164,7 +178,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_DISABLED); + + log_error("enable files2"); + changes = NULL; +@@ -176,19 +192,22 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r < 0); + + log_error("link files2"); + changes = NULL; +@@ -200,19 +219,22 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_LINKED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r < 0); + + log_error("link files2"); + changes = NULL; +@@ -224,7 +246,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_LINKED); + + log_error("reenable files2"); + changes = NULL; +@@ -236,19 +260,22 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r < 0); + log_error("preset files"); + changes = NULL; + n_changes = 0; +@@ -259,7 +286,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0])) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + return 0; + } diff --git a/SOURCES/0297-core-look-for-instance-when-processing-template-name.patch b/SOURCES/0297-core-look-for-instance-when-processing-template-name.patch new file mode 100644 index 00000000..b57ba56c --- /dev/null +++ b/SOURCES/0297-core-look-for-instance-when-processing-template-name.patch @@ -0,0 +1,41 @@ +From 0e6ec33b5e8c8790e60d1b79801dc360dad010d3 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 16 Mar 2016 15:47:18 +0100 +Subject: [PATCH] core: look for instance when processing template name + +If first attempt to merge units failed and we are trying to do +merge the other way around and at the same time we are working with +template name, then other unit can't possibly be template, because it is +not possible to have template unit running, only instances of the +template. Thus we need to look for already active instance instead. + +rhel-only (upstream review pending) + +Related: #1159308 +--- + src/core/load-fragment.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 70c09188a..b188ec99d 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3472,8 +3472,17 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { + /* Hmm, we couldn't merge the other unit into + * ours? Then let's try it the other way + * round */ ++ if (unit_name_is_template(k) && (*u)->instance) { ++ _cleanup_free_ char *instance = NULL; ++ ++ instance = unit_name_replace_instance(k, (*u)->instance); ++ if(!instance) ++ return -ENOMEM; ++ other = manager_get_unit((*u)->manager, instance); ++ ++ } else ++ other = manager_get_unit((*u)->manager, k); + +- other = manager_get_unit((*u)->manager, k); + free(k); + + if (other) { diff --git a/SOURCES/0298-core-improve-error-message-when-starting-template-wi.patch b/SOURCES/0298-core-improve-error-message-when-starting-template-wi.patch new file mode 100644 index 00000000..2f32bf3d --- /dev/null +++ b/SOURCES/0298-core-improve-error-message-when-starting-template-wi.patch @@ -0,0 +1,30 @@ +From 9b33863a2cfa31bbe57bab685776b64731f528f1 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 30 Mar 2016 13:49:50 +0200 +Subject: [PATCH] core: improve error message when starting template without + instance + +Cherry-picked from: 5d512d54429aa9d2f4a0ca215bb2e982db720d6b +Resolves: #1142369 +--- + src/core/manager.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index bde17ce0b..bb5050303 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1328,8 +1328,12 @@ int manager_load_unit_prepare( + + t = unit_name_to_type(name); + +- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) ++ if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { ++ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) ++ return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is missing the instance name.", name); ++ + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); ++ } + + ret = manager_get_unit(m, name); + if (ret) { diff --git a/SOURCES/0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch b/SOURCES/0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch new file mode 100644 index 00000000..a57bd86e --- /dev/null +++ b/SOURCES/0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch @@ -0,0 +1,28 @@ +From b0edbac36cd75bfd5624f20884043553da14ced2 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 13 Jan 2016 08:41:54 +0100 +Subject: [PATCH] man/tmpfiles.d: add note about permissions and ownership of + symlinks + +...because this is might not be obvious. + +Cherry-picked from: b908bb63c41eaf3c44004b6b737d105c39df2075 +Resolves: #1296288 +--- + man/tmpfiles.d.xml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml +index 9b4e11c1b..fc1fe13ac 100644 +--- a/man/tmpfiles.d.xml ++++ b/man/tmpfiles.d.xml +@@ -187,7 +187,8 @@ + be removed and be replaced by the symlink. If the argument + is omitted, symlinks to files with the same name residing in + the directory /usr/share/factory/ are +- created. ++ created. Note that permissions and ownership on symlinks ++ are ignored. + + + diff --git a/SOURCES/0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch b/SOURCES/0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch new file mode 100644 index 00000000..d491adb3 --- /dev/null +++ b/SOURCES/0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch @@ -0,0 +1,185 @@ +From 595a93d716680715a751737ec2f87b06ea582763 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 13 Apr 2015 15:16:54 +0200 +Subject: [PATCH] tmpfiles: don't follow symlinks when adjusting ACLs, fille + attributes, access modes or ownership + +Cherry-picked from: 48b8aaa82724bc2d8440470f414fb0d2416f29c +Resolves: #1296288 +--- + src/tmpfiles/tmpfiles.c | 112 ++++++++++++++++++++++++++++++++---------------- + 1 file changed, 74 insertions(+), 38 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index d0e6567d8..64c733aaa 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -570,51 +570,69 @@ finish: + } + + static int path_set_perms(Item *i, const char *path) { ++ _cleanup_close_ int fd = -1; + struct stat st; +- bool st_valid; + + assert(i); + assert(path); + +- st_valid = stat(path, &st) == 0; ++ /* We open the file with O_PATH here, to make the operation ++ * somewhat atomic. Also there's unfortunately no fchmodat() ++ * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via ++ * O_PATH. */ ++ ++ fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); ++ if (fd < 0) ++ return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path); ++ ++ if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0) ++ return log_error_errno(errno, "Failed to fstat() file %s: %m", path); ++ ++ if (S_ISLNK(st.st_mode)) ++ log_debug("Skipping mode an owner fix for symlink %s.", path); ++ else { ++ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; ++ xsprintf(fn, "/proc/self/fd/%i", fd); + +- /* not using i->path directly because it may be a glob */ +- if (i->mode_set) { +- mode_t m = i->mode; ++ /* not using i->path directly because it may be a glob */ ++ if (i->mode_set) { ++ mode_t m = i->mode; + +- if (i->mask_perms && st_valid) { +- if (!(st.st_mode & 0111)) +- m &= ~0111; +- if (!(st.st_mode & 0222)) ++ if (i->mask_perms) { ++ if (!(st.st_mode & 0111)) ++ m &= ~0111; ++ if (!(st.st_mode & 0222)) + m &= ~0222; +- if (!(st.st_mode & 0444)) +- m &= ~0444; +- if (!S_ISDIR(st.st_mode)) +- m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ +- } ++ if (!(st.st_mode & 0444)) ++ m &= ~0444; ++ if (!S_ISDIR(st.st_mode)) ++ m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ ++ } + +- if (st_valid && m == (st.st_mode & 07777)) +- log_debug("\"%s\" has right mode %o", path, st.st_mode); +- else { +- log_debug("chmod \"%s\" to mode %o", path, m); +- if (chmod(path, m) < 0) +- return log_error_errno(errno, "chmod(%s) failed: %m", path); ++ if (m == (st.st_mode & 07777)) ++ log_debug("\"%s\" has right mode %o", path, st.st_mode); ++ else { ++ log_debug("chmod \"%s\" to mode %o", path, m); ++ if (chmod(fn, m) < 0) ++ return log_error_errno(errno, "chmod(%s) failed: %m", path); ++ } + } +- } +- +- if ((!st_valid || i->uid != st.st_uid || i->gid != st.st_gid) && +- (i->uid_set || i->gid_set)) { +- log_debug("chown \"%s\" to "UID_FMT"."GID_FMT, +- path, +- i->uid_set ? i->uid : UID_INVALID, +- i->gid_set ? i->gid : GID_INVALID); +- if (chown(path, +- i->uid_set ? i->uid : UID_INVALID, +- i->gid_set ? i->gid : GID_INVALID) < 0) + ++ if ((i->uid != st.st_uid || i->gid != st.st_gid) && ++ (i->uid_set || i->gid_set)) { ++ log_debug("chown \"%s\" to "UID_FMT"."GID_FMT, ++ path, ++ i->uid_set ? i->uid : UID_INVALID, ++ i->gid_set ? i->gid : GID_INVALID); ++ if (chown(fn, ++ i->uid_set ? i->uid : UID_INVALID, ++ i->gid_set ? i->gid : GID_INVALID) < 0) + return log_error_errno(errno, "chown(%s) failed: %m", path); ++ } + } + ++ fd = safe_close(fd); ++ + return label_fix(path, false, false); + } + +@@ -699,10 +717,10 @@ static int get_acls_from_arg(Item *item) { + } + + #ifdef HAVE_ACL +-static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) { ++static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) { ++ _cleanup_(acl_free_charpp) char *t = NULL; + _cleanup_(acl_freep) acl_t dup = NULL; + int r; +- _cleanup_(acl_free_charpp) char *t = NULL; + + /* Returns 0 for success, positive error if already warned, + * negative error otherwise. */ +@@ -728,16 +746,16 @@ static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modif + return r; + + t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE); +- log_debug("\"%s\": setting %s ACL \"%s\"", path, ++ log_debug("Setting %s ACL %s on %s.", + type == ACL_TYPE_ACCESS ? "access" : "default", +- strna(t)); ++ strna(t), pretty); + + r = acl_set_file(path, type, dup); + if (r < 0) + return -log_error_errno(errno, + "Setting %s ACL \"%s\" on %s failed: %m", + type == ACL_TYPE_ACCESS ? "access" : "default", +- strna(t), path); ++ strna(t), pretty); + + return 0; + } +@@ -746,14 +764,32 @@ static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modif + static int path_set_acls(Item *item, const char *path) { + int r = 0; + #ifdef HAVE_ACL ++ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; ++ _cleanup_close_ int fd = -1; ++ struct stat st; ++ + assert(item); + assert(path); + ++ fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); ++ if (fd < 0) ++ return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); ++ ++ if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0) ++ return log_error_errno(errno, "Failed to fstat() file %s: %m", path); ++ ++ if (S_ISLNK(st.st_mode)) { ++ log_debug("Skipping ACL fix for symlink %s.", path); ++ return 0; ++ } ++ ++ xsprintf(fn, "/proc/self/fd/%i", fd); ++ + if (item->acl_access) +- r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force); ++ r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force); + + if (r == 0 && item->acl_default) +- r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force); ++ r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force); + + if (r > 0) + return -r; /* already warned */ diff --git a/SOURCES/0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch b/SOURCES/0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch new file mode 100644 index 00000000..dac2bc6f --- /dev/null +++ b/SOURCES/0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch @@ -0,0 +1,43 @@ +From 0fa424a08a31af512a698b60b497cfc0cf0554e0 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 25 Jan 2016 17:16:27 +0100 +Subject: [PATCH] udev: filter out non-sensically high onboard indexes reported + by the kernel + +Let's not accept onboard interface indexes, that are so high that they are obviously non-sensical. + +Fixes: #2407 + +Cherry-picked from: 6c1e69f9456d022f14dd00737126cfa4d9cca10 +Resolves: #1230210 +--- + src/udev/udev-builtin-net_id.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index ffd6ea416..19e1f2631 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -101,6 +101,8 @@ + #include "udev.h" + #include "fileio.h" + ++#define ONBOARD_INDEX_MAX (16*1024-1) ++ + enum netname_type{ + NET_UNDEF, + NET_PCI, +@@ -147,6 +149,13 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + if (idx <= 0) + return -EINVAL; + ++ /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for ++ * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary ++ * cut-off, which is somewhere beyond the realistic number of physical network interface a system might ++ * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */ ++ if (idx > ONBOARD_INDEX_MAX) ++ return -ENOENT; ++ + /* kernel provided port index for multiple ports on a single PCI function */ + attr = udev_device_get_sysattr_value(dev, "dev_port"); + if (attr) diff --git a/SOURCES/0302-test-execute-add-tests-for-RuntimeDirectory.patch b/SOURCES/0302-test-execute-add-tests-for-RuntimeDirectory.patch new file mode 100644 index 00000000..b54b6ea7 --- /dev/null +++ b/SOURCES/0302-test-execute-add-tests-for-RuntimeDirectory.patch @@ -0,0 +1,74 @@ +From fb798a267d2bad8df98f49c2a4a309efa5569759 Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Mon, 21 Sep 2015 15:36:07 +0200 +Subject: [PATCH] test-execute: add tests for RuntimeDirectory + +Cherry-picked from: cc3ddc851fbe5adf9dfc7e4a702a8b5b6a1186d6 +Resolves: #1324826 +--- + src/test/test-execute.c | 7 +++++++ + test/exec-runtimedirectory-mode.service | 8 ++++++++ + test/exec-runtimedirectory.service | 7 +++++++ + 3 files changed, 22 insertions(+) + create mode 100644 test/exec-runtimedirectory-mode.service + create mode 100644 test/exec-runtimedirectory.service + +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 00f3607b4..90b1c871c 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -141,6 +141,11 @@ static void test_exec_umask(Manager *m) { + test(m, "exec-umask-0177.service", 0, CLD_EXITED); + } + ++static void test_exec_runtimedirectory(Manager *m) { ++ test(m, "exec-runtimedirectory.service", 0, CLD_EXITED); ++ test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); ++} ++ + int main(int argc, char *argv[]) { + test_function_t tests[] = { + test_exec_workingdirectory, +@@ -154,6 +159,7 @@ int main(int argc, char *argv[]) { + test_exec_group, + test_exec_environment, + test_exec_umask, ++ test_exec_runtimedirectory, + NULL, + }; + test_function_t *test = NULL; +@@ -169,6 +175,7 @@ int main(int argc, char *argv[]) { + return EXIT_TEST_SKIP; + } + ++ assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0); + assert_se(set_unit_path(TEST_DIR ":") >= 0); + + r = manager_new(SYSTEMD_USER, true, &m); +diff --git a/test/exec-runtimedirectory-mode.service b/test/exec-runtimedirectory-mode.service +new file mode 100644 +index 000000000..ba6d7ee39 +--- /dev/null ++++ b/test/exec-runtimedirectory-mode.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for RuntimeDirectoryMode ++ ++[Service] ++ExecStart=/bin/sh -c 's=$(stat -c %a /tmp/test-exec_runtimedirectory-mode); echo $s; exit $(test $s = "750")' ++Type=oneshot ++RuntimeDirectory=test-exec_runtimedirectory-mode ++RuntimeDirectoryMode=0750 +diff --git a/test/exec-runtimedirectory.service b/test/exec-runtimedirectory.service +new file mode 100644 +index 000000000..c12a6c63d +--- /dev/null ++++ b/test/exec-runtimedirectory.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for RuntimeDirectory ++ ++[Service] ++ExecStart=/bin/sh -c 'exit $(test -d /tmp/test-exec_runtimedirectory)' ++Type=oneshot ++RuntimeDirectory=test-exec_runtimedirectory diff --git a/SOURCES/0303-core-fix-group-ownership-when-Group-is-set.patch b/SOURCES/0303-core-fix-group-ownership-when-Group-is-set.patch new file mode 100644 index 00000000..6fdf04ad --- /dev/null +++ b/SOURCES/0303-core-fix-group-ownership-when-Group-is-set.patch @@ -0,0 +1,84 @@ +From f2300a5c3226d3a66d77c34ae811401c638f430f Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Mon, 21 Sep 2015 15:45:51 +0200 +Subject: [PATCH] core: fix group ownership when Group is set + +When Group is set in the unit, the runtime directories are owned by +this group and not the default group of the user (same for cgroup paths +and standard outputs) + +Fix #1231 + +Cherry-picked from: 5bc7452b3219456e07f931e40da30bb94a884293 +Resolves: #1324826 +--- + src/core/execute.c | 19 +++++++++++-------- + src/test/test-execute.c | 1 + + test/exec-runtimedirectory-owner.service | 9 +++++++++ + 3 files changed, 21 insertions(+), 8 deletions(-) + create mode 100644 test/exec-runtimedirectory-owner.service + +diff --git a/src/core/execute.c b/src/core/execute.c +index 1815e3de2..8172c8b44 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -629,14 +629,6 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_ + * we avoid NSS lookups for gid=0. */ + + if (context->group || username) { +- +- if (context->group) { +- const char *g = context->group; +- +- if ((r = get_group_creds(&g, &gid)) < 0) +- return r; +- } +- + /* First step, initialize groups from /etc/groups */ + if (username && gid != 0) { + if (initgroups(username, gid) < 0) +@@ -1374,6 +1366,17 @@ static int exec_child( + } + } + ++ if (context->group) { ++ const char *g = context->group; ++ ++ r = get_group_creds(&g, &gid); ++ if (r < 0) { ++ *exit_status = EXIT_GROUP; ++ return r; ++ } ++ } ++ ++ + /* If a socket is connected to STDIN/STDOUT/STDERR, we + * must sure to drop O_NONBLOCK */ + if (socket_fd >= 0) +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 90b1c871c..38522a168 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -144,6 +144,7 @@ static void test_exec_umask(Manager *m) { + static void test_exec_runtimedirectory(Manager *m) { + test(m, "exec-runtimedirectory.service", 0, CLD_EXITED); + test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); ++ test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + } + + int main(int argc, char *argv[]) { +diff --git a/test/exec-runtimedirectory-owner.service b/test/exec-runtimedirectory-owner.service +new file mode 100644 +index 000000000..077e08d1c +--- /dev/null ++++ b/test/exec-runtimedirectory-owner.service +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set) ++ ++[Service] ++ExecStart=/bin/sh -c 'f=/tmp/test-exec_runtimedirectory-owner;g=$(stat -c %G $f); echo "$g"; exit $(test $g = "nobody")' ++Type=oneshot ++Group=nobody ++User=root ++RuntimeDirectory=test-exec_runtimedirectory-owner diff --git a/SOURCES/0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch b/SOURCES/0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch new file mode 100644 index 00000000..e3d32375 --- /dev/null +++ b/SOURCES/0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch @@ -0,0 +1,49 @@ +From e591c1a47c067cd2d14dca569cc9f0cce9072200 Mon Sep 17 00:00:00 2001 +From: Andrei Borzenkov +Date: Wed, 3 Jun 2015 20:50:59 +0300 +Subject: [PATCH] fstab-generator: cescape device name in root-fsck service + +We unescape ExecStart line when parsing it, so escape device name +before adding it to unit file. + +fixes #50 + +Cherry-picked from: fa05e97 +Resolves: #1306126 +--- + src/shared/generator.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/shared/generator.c b/src/shared/generator.c +index 3af84a325..be8e24eb4 100644 +--- a/src/shared/generator.c ++++ b/src/shared/generator.c +@@ -35,8 +35,13 @@ + static int write_fsck_sysroot_service(const char *dir, const char *what) { + const char *unit; + _cleanup_free_ char *device = NULL; ++ _cleanup_free_ char *escaped; + _cleanup_fclose_ FILE *f = NULL; + ++ escaped = cescape(what); ++ if (!escaped) ++ return log_oom(); ++ + unit = strjoina(dir, "/systemd-fsck-root.service"); + log_debug("Creating %s", unit); + +@@ -61,11 +66,12 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" +- "ExecStart=" SYSTEMD_FSCK_PATH " %2$s\n" ++ "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n" + "TimeoutSec=0\n", + program_invocation_short_name, + what, +- device); ++ device, ++ escaped); + + fflush(f); + if (ferror(f)) diff --git a/SOURCES/0305-core-add-new-RandomSec-setting-for-time-units.patch b/SOURCES/0305-core-add-new-RandomSec-setting-for-time-units.patch new file mode 100644 index 00000000..6ec19cf5 --- /dev/null +++ b/SOURCES/0305-core-add-new-RandomSec-setting-for-time-units.patch @@ -0,0 +1,227 @@ +From 338b8f9bca1cd7bd65123808fc7f7b2773e637db Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 18 Nov 2015 13:37:30 +0100 +Subject: [PATCH] core: add new RandomSec= setting for time units + +This allows configuration of a random time on top of the elapse events, +in order to spread time events in a network evenly across a range. + +Cherry-picked from: 744c7693751830149ae78fdaf95c6c6f99d59f07 +Resolves: #1305279 +--- + man/systemd.timer.xml | 43 ++++++++++++++++++++++++++++++----- + src/core/dbus-timer.c | 17 ++++++++++++++ + src/core/load-fragment-gperf.gperf.m4 | 1 + + src/core/timer.c | 28 +++++++++++++++++++++++ + src/core/timer.h | 1 + + src/libsystemd/sd-bus/bus-util.c | 16 +++++++++++++ + 6 files changed, 100 insertions(+), 6 deletions(-) + +diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml +index 20890f227..bdd14d888 100644 +--- a/man/systemd.timer.xml ++++ b/man/systemd.timer.xml +@@ -180,13 +180,12 @@ + OnUnitInactiveSec= and ending the time + configured with AccuracySec= later. Within + this time window, the expiry time will be placed at a +- host-specific, randomized but stable position that is ++ host-specific, randomized, but stable position that is + synchronized between all local timer units. This is done in +- order to distribute the wake-up time in networked +- installations, as well as optimizing power consumption to +- suppress unnecessary CPU wake-ups. To get best accuracy, set +- this option to 1us. Note that the timer is still subject to +- the timer slack configured via ++ order to optimize power consumption to suppress unnecessary ++ CPU wake-ups. To get best accuracy, set this option to ++ 1us. Note that the timer is still subject to the timer slack ++ configured via + systemd-system.conf5's + TimerSlackNSec= setting. See + prctl2 +@@ -194,6 +193,38 @@ + this value as high as possible and as low as + necessary. + ++ ++ ++ RandomSec= ++ ++ Delay the timer by a randomly selected, evenly ++ distributed amount of time between 0 and the specified time ++ value. Defaults to 0, indicating that no randomized delay ++ shall be applied. Each timer unit will determine this delay ++ randomly each time it is started, and the delay will simply be ++ added on top of the next determined elapsing time. This is ++ useful to stretch dispatching of similarly configured timer ++ events over a certain amount time, to avoid that they all fire ++ at the same time, possibly resulting in resource ++ congestion. Note the relation to ++ AccuracySec= above: the latter allows the ++ service manager to coalesce timer events within a specified ++ time range in order to minimize wakeups, the former does the ++ opposite: it stretches timer events over a time range, to make ++ it unlikely that they fire simultaneously. If ++ RandomSec= and ++ AccuracySec= are used in conjunction, first ++ the a randomized time is added, and the result is then ++ possibly shifted further to coalesce it with other timer ++ events possibly happening on the system. As mentioned above ++ AccuracySec= defaults to 1min and ++ RandomSec= to 0, thus encouraging ++ coalescing of timer events. In order to optimally stretch ++ timer events over a certain range of time, make sure to set ++ RandomSec= to a higher value, and ++ AccuracySec=1us. ++ ++ + + Unit= + +diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c +index 43e785246..cd7bf44ba 100644 +--- a/src/core/dbus-timer.c ++++ b/src/core/dbus-timer.c +@@ -181,6 +181,7 @@ const sd_bus_vtable bus_timer_vtable[] = { + BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("RandomUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +@@ -284,6 +285,22 @@ static int bus_timer_set_transient_property( + + return 1; + ++ } else if (streq(name, "RandomUSec")) { ++ usec_t u = 0; ++ ++ r = sd_bus_message_read(message, "t", &u); ++ if (r < 0) ++ return r; ++ ++ if (mode != UNIT_CHECK) { ++ char time[FORMAT_TIMESPAN_MAX]; ++ ++ t->random_usec = u; ++ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomSec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); ++ } ++ ++ return 1; ++ + } else if (streq(name, "WakeSystem")) { + + int b; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 53059845e..5106a98ee 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -336,6 +336,7 @@ Timer.OnUnitInactiveSec, config_parse_timer, 0, + Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent) + Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system) + Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec) ++Timer.RandomSec, config_parse_sec, 0, offsetof(Timer, random_usec) + Timer.Unit, config_parse_trigger_unit, 0, 0 + m4_dnl + Path.PathExists, config_parse_path_spec, 0, 0 +diff --git a/src/core/timer.c b/src/core/timer.c +index 48cf9c16a..972dd73df 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -29,6 +29,7 @@ + #include "bus-util.h" + #include "bus-error.h" + #include "mkdir.h" ++#include "util.h" + + static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = UNIT_INACTIVE, +@@ -315,6 +316,28 @@ static usec_t monotonic_to_boottime(usec_t t) { + return 0; + } + ++static void add_random(Timer *t, usec_t *v) { ++ char s[FORMAT_TIMESPAN_MAX]; ++ usec_t add; ++ ++ assert(t); ++ assert(*v); ++ ++ if (t->random_usec == 0) ++ return; ++ if (*v == USEC_INFINITY) ++ return; ++ ++ add = random_u64() % t->random_usec; ++ ++ if (*v + add < *v) /* overflow */ ++ *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */ ++ else ++ *v += add; ++ ++ log_unit_info(UNIT(t)->id, "Adding %s random time.", format_timespan(s, sizeof(s), add, 0)); ++} ++ + static void timer_enter_waiting(Timer *t, bool initial) { + bool found_monotonic = false, found_realtime = false; + usec_t ts_realtime, ts_monotonic; +@@ -431,6 +454,8 @@ static void timer_enter_waiting(Timer *t, bool initial) { + if (found_monotonic) { + char buf[FORMAT_TIMESPAN_MAX]; + ++ add_random(t, &t->next_elapse_monotonic_or_boottime); ++ + log_unit_debug(UNIT(t)->id, "%s: Monotonic timer elapses in %s.", + UNIT(t)->id, + format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0)); +@@ -460,6 +485,9 @@ static void timer_enter_waiting(Timer *t, bool initial) { + + if (found_realtime) { + char buf[FORMAT_TIMESTAMP_MAX]; ++ ++ add_random(t, &t->next_elapse_realtime); ++ + log_unit_debug(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime)); + + if (t->realtime_event_source) { +diff --git a/src/core/timer.h b/src/core/timer.h +index de412a043..b97724525 100644 +--- a/src/core/timer.h ++++ b/src/core/timer.h +@@ -69,6 +69,7 @@ struct Timer { + Unit meta; + + usec_t accuracy_usec; ++ usec_t random_usec; + + LIST_HEAD(TimerValue, values); + usec_t next_elapse_realtime; +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 6d5615082..5ecb3bea4 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1360,6 +1360,22 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + return -EINVAL; + } + ++ if (r < 0) ++ return bus_log_create_error(r); ++ ++ return 0; ++ } else if (streq(field, "RandomSec")) { ++ usec_t t; ++ ++ r = parse_sec(eq, &t); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse RandomSec= parameter: %s", eq); ++ ++ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomUSec"); ++ if (r < 0) ++ return bus_log_create_error(r); ++ ++ r = sd_bus_message_append(m, "v", "t", t); + if (r < 0) + return bus_log_create_error(r); + diff --git a/SOURCES/0306-core-rename-Random-to-RandomizedDelay.patch b/SOURCES/0306-core-rename-Random-to-RandomizedDelay.patch new file mode 100644 index 00000000..82753db3 --- /dev/null +++ b/SOURCES/0306-core-rename-Random-to-RandomizedDelay.patch @@ -0,0 +1,118 @@ +From 510ba7ebe71c8e4e64ead26a44b330d2e4375d9c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 26 Nov 2015 16:32:41 -0500 +Subject: [PATCH] core: rename Random* to RandomizedDelay* + +The name RandomSec is too generic: "Sec" just specifies the default +unit type, and "Random" by itself is not enough. Rename to something +that should give the user general idea what the setting does without +looking at documentation. + +Cherry-picked from: 6f5d79986a9c98b9cacc83f865fed957e4e6e4e6 +Resolves: #1305279 +--- + man/systemd.timer.xml | 8 ++++---- + src/core/dbus-timer.c | 6 +++--- + src/core/load-fragment-gperf.gperf.m4 | 2 +- + src/libsystemd/sd-bus/bus-util.c | 6 +++--- + 4 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml +index bdd14d888..ab83b2c9c 100644 +--- a/man/systemd.timer.xml ++++ b/man/systemd.timer.xml +@@ -195,7 +195,7 @@ + + + +- RandomSec= ++ RandomizedDelaySec= + + Delay the timer by a randomly selected, evenly + distributed amount of time between 0 and the specified time +@@ -212,16 +212,16 @@ + time range in order to minimize wakeups, the former does the + opposite: it stretches timer events over a time range, to make + it unlikely that they fire simultaneously. If +- RandomSec= and ++ RandomizedDelaySec= and + AccuracySec= are used in conjunction, first + the a randomized time is added, and the result is then + possibly shifted further to coalesce it with other timer + events possibly happening on the system. As mentioned above + AccuracySec= defaults to 1min and +- RandomSec= to 0, thus encouraging ++ RandomizedDelaySec= to 0, thus encouraging + coalescing of timer events. In order to optimally stretch + timer events over a certain range of time, make sure to set +- RandomSec= to a higher value, and ++ RandomizedDelaySec= to a higher value, and + AccuracySec=1us. + + +diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c +index cd7bf44ba..478905acc 100644 +--- a/src/core/dbus-timer.c ++++ b/src/core/dbus-timer.c +@@ -181,7 +181,7 @@ const sd_bus_vtable bus_timer_vtable[] = { + BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), +- SD_BUS_PROPERTY("RandomUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +@@ -285,7 +285,7 @@ static int bus_timer_set_transient_property( + + return 1; + +- } else if (streq(name, "RandomUSec")) { ++ } else if (streq(name, "RandomizedDelayUSec")) { + usec_t u = 0; + + r = sd_bus_message_read(message, "t", &u); +@@ -296,7 +296,7 @@ static int bus_timer_set_transient_property( + char time[FORMAT_TIMESPAN_MAX]; + + t->random_usec = u; +- unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomSec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); ++ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); + } + + return 1; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 5106a98ee..85d979751 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -336,7 +336,7 @@ Timer.OnUnitInactiveSec, config_parse_timer, 0, + Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent) + Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system) + Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec) +-Timer.RandomSec, config_parse_sec, 0, offsetof(Timer, random_usec) ++Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_usec) + Timer.Unit, config_parse_trigger_unit, 0, 0 + m4_dnl + Path.PathExists, config_parse_path_spec, 0, 0 +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 5ecb3bea4..3a918361b 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1364,14 +1364,14 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + return bus_log_create_error(r); + + return 0; +- } else if (streq(field, "RandomSec")) { ++ } else if (streq(field, "RandomizedDelaySec")) { + usec_t t; + + r = parse_sec(eq, &t); + if (r < 0) +- return log_error_errno(r, "Failed to parse RandomSec= parameter: %s", eq); ++ return log_error_errno(r, "Failed to parse RandomizedDelaySec= parameter: %s", eq); + +- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomUSec"); ++ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomizedDelayUSec"); + if (r < 0) + return bus_log_create_error(r); + diff --git a/SOURCES/0307-journal-remote-change-owner-of-var-log-journal-remot.patch b/SOURCES/0307-journal-remote-change-owner-of-var-log-journal-remot.patch new file mode 100644 index 00000000..8e9eb5ce --- /dev/null +++ b/SOURCES/0307-journal-remote-change-owner-of-var-log-journal-remot.patch @@ -0,0 +1,26 @@ +From 1c6075b30786cefc73e41b2f1f5459006f37b616 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 15 Jan 2016 15:19:52 +0900 +Subject: [PATCH] journal-remote: change owner of /var/log/journal/remote and + create /var/lib/systemd/journal-upload + +Cherry-picked from: dcdd4411407067fa1e464dc26ab85ae598fcad7d +Resolves: #1327303 +--- + tmpfiles.d/systemd-remote.conf | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tmpfiles.d/systemd-remote.conf b/tmpfiles.d/systemd-remote.conf +index 1b8973a88..e19230f64 100644 +--- a/tmpfiles.d/systemd-remote.conf ++++ b/tmpfiles.d/systemd-remote.conf +@@ -7,5 +7,7 @@ + + # See tmpfiles.d(5) for details + +-z /var/log/journal/remote 2755 root systemd-journal-remote - - +-z /run/log/journal/remote 2755 root systemd-journal-remote - - ++d /var/lib/systemd/journal-upload 0755 systemd-journal-upload systemd-journal-upload - - ++ ++z /var/log/journal/remote 2755 systemd-journal-remote systemd-journal-remote - - ++z /run/log/journal/remote 2755 systemd-journal-remote systemd-journal-remote - - diff --git a/SOURCES/0308-Add-Seal-option-in-the-configuration-file-for-journa.patch b/SOURCES/0308-Add-Seal-option-in-the-configuration-file-for-journa.patch new file mode 100644 index 00000000..cdbbaeff --- /dev/null +++ b/SOURCES/0308-Add-Seal-option-in-the-configuration-file-for-journa.patch @@ -0,0 +1,57 @@ +From f6a8db04fb20d142e514d805c613a1b3e70c454d Mon Sep 17 00:00:00 2001 +From: Michael Scherer +Date: Sun, 20 Dec 2015 13:23:33 +0100 +Subject: [PATCH] Add Seal option in the configuration file for journald-remote + +While journal received remotely can be sealed, it can only be done +on the command line using --seal, so for consistency, we will +also permit to set it in the configuration file. + +Cherry-picked from: 9d3737f13e9b38f88ed7acc800db66c2f025fac9 +Resolves: #1329233 +--- + man/journal-remote.conf.xml | 7 +++++++ + src/journal-remote/journal-remote.c | 1 + + src/journal-remote/journal-remote.conf.in | 1 + + 3 files changed, 9 insertions(+) + +diff --git a/man/journal-remote.conf.xml b/man/journal-remote.conf.xml +index a7b222718..9a385c7e5 100644 +--- a/man/journal-remote.conf.xml ++++ b/man/journal-remote.conf.xml +@@ -72,6 +72,13 @@ + [Remote] section: + + ++ ++ Seal= ++ ++ Periodically sign the data in the journal using Forward Secure Sealing. ++ ++ ++ + + + SplitMode= +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index b7cc6d717..9c515f9c8 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -1174,6 +1174,7 @@ static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode, + + static int parse_config(void) { + const ConfigTableItem items[] = { ++ { "Remote", "Seal", config_parse_bool, 0, &arg_seal }, + { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode }, + { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key }, + { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert }, +diff --git a/src/journal-remote/journal-remote.conf.in b/src/journal-remote/journal-remote.conf.in +index 3e32f34de..7122d6336 100644 +--- a/src/journal-remote/journal-remote.conf.in ++++ b/src/journal-remote/journal-remote.conf.in +@@ -1,4 +1,5 @@ + [Remote] ++# Seal=false + # SplitMode=host + # ServerKeyFile=@CERTIFICATEROOT@/private/journal-remote.pem + # ServerCertificateFile=@CERTIFICATEROOT@/certs/journal-remote.pem diff --git a/SOURCES/0309-tests-fix-make-check-failure.patch b/SOURCES/0309-tests-fix-make-check-failure.patch new file mode 100644 index 00000000..289ab1ea --- /dev/null +++ b/SOURCES/0309-tests-fix-make-check-failure.patch @@ -0,0 +1,26 @@ +From 44eb30c33deb46f92d2c67e78a5fb7aa6b21d145 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 28 Apr 2016 16:04:52 +0200 +Subject: [PATCH] tests: fix make check failure + +Don't call abort() on success. Actually rm_rf_dangerous() returns 0 if +all went well. + +Related: #1159308 +--- + src/test/test-install-root.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index 89d91d3d6..667c3748c 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -657,7 +657,7 @@ int main(int argc, char *argv[]) { + test_indirect(root); + test_preset_and_list(root); + +- assert_se(rm_rf_dangerous(root, false, true, false)); ++ assert_se(rm_rf_dangerous(root, false, true, false) == 0); + + return 0; + } diff --git a/SOURCES/0310-device-make-sure-to-not-ignore-re-plugged-device.patch b/SOURCES/0310-device-make-sure-to-not-ignore-re-plugged-device.patch new file mode 100644 index 00000000..2aeabaa2 --- /dev/null +++ b/SOURCES/0310-device-make-sure-to-not-ignore-re-plugged-device.patch @@ -0,0 +1,65 @@ +From 45ff3d79f079c73c73209940cf6eaa0ea0a95708 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Fri, 22 Jan 2016 07:18:19 +0100 +Subject: [PATCH] device: make sure to not ignore re-plugged device + +systemd automatically mounts device unless 'noauto' is part of the +mount options. This can happen during boot if the device is plugged at +that time or later when the system is already running (the latter case +is not documented AFAICS). + +After the systemd booted, I plugged my USB device which had an entry +in /etc/fstab with the default options and systemd automatically +mounted it. + +However I noticed that if I unplugged and re-plugged the device the +automatic mounting of the device didn't work anymore: systemd didn't +notice that the device was re-plugged. + +This was due to the device unit which was not recycled by the GC +during the unplug event because in the case of automounting, the mount +unit still referenced it. When the device was re-plugged, the old +device unit was reused but it still had the old sysfs path (amongst +other useful information). + +Systemd was confused by the stalled sysfs path and decided to ignore +the plug event. + +This patch fixes this issue by simply not doing the sanity checking on +the sysfs path if the device is in unplugged state. + +Cherry-picked from: ac9d396b2abbae4e7ab84f7b556f70681b66236b +Resolves: #1332606 +--- + src/core/device.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/src/core/device.c b/src/core/device.c +index 1995e3c0b..fc73e263a 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -314,11 +314,19 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa + + u = manager_get_unit(m, e); + +- if (u && +- DEVICE(u)->sysfs && +- !path_equal(DEVICE(u)->sysfs, sysfs)) { +- log_unit_debug(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); +- return -EEXIST; ++ /* The device unit can still be present even if the device was ++ * unplugged: a mount unit can reference it hence preventing ++ * the GC to have garbaged it. That's desired since the device ++ * unit may have a dependency on the mount unit which was ++ * added during the loading of the later. */ ++ if (u && DEVICE(u)->state == DEVICE_PLUGGED) { ++ /* This unit is in plugged state: we're sure it's ++ * attached to a device. */ ++ if (!path_equal(DEVICE(u)->sysfs, sysfs)) { ++ log_unit_debug(u->id, "Dev %s appeared twice with different sysfs paths %s and %s", ++ e, DEVICE(u)->sysfs, sysfs); ++ return -EEXIST; ++ } + } + + if (!u) { diff --git a/SOURCES/0311-device-Ensure-we-have-sysfs-path-before-comparing.patch b/SOURCES/0311-device-Ensure-we-have-sysfs-path-before-comparing.patch new file mode 100644 index 00000000..30fbfd57 --- /dev/null +++ b/SOURCES/0311-device-Ensure-we-have-sysfs-path-before-comparing.patch @@ -0,0 +1,33 @@ +From ce046ce7f8545d174dc8ecb45b27c2049d96f935 Mon Sep 17 00:00:00 2001 +From: Colin Guthrie +Date: Mon, 14 Mar 2016 09:42:07 +0000 +Subject: [PATCH] device: Ensure we have sysfs path before comparing. + +In some cases we do not have a udev device when setting up a unit +(certainly the code gracefully handles this). However, we do +then go on to compare the path via path_equal which will assert +if a null value is passed in. + +See https://bugs.mageia.org/show_bug.cgi?id=17766 + +Not sure if this is the correct fix, but it avoids the crash + +Cherry-picked from: 5e1558f4a09e596561c9168384f2258e7c0718a1 +Resolves: #1332606 +--- + src/core/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/device.c b/src/core/device.c +index fc73e263a..bdc8466ab 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -319,7 +319,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa + * the GC to have garbaged it. That's desired since the device + * unit may have a dependency on the mount unit which was + * added during the loading of the later. */ +- if (u && DEVICE(u)->state == DEVICE_PLUGGED) { ++ if (sysfs && u && DEVICE(u)->state == DEVICE_PLUGGED) { + /* This unit is in plugged state: we're sure it's + * attached to a device. */ + if (!path_equal(DEVICE(u)->sysfs, sysfs)) { diff --git a/SOURCES/0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch b/SOURCES/0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch new file mode 100644 index 00000000..9d3cef1c --- /dev/null +++ b/SOURCES/0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch @@ -0,0 +1,23 @@ +From 805365980feaec626e80c6514b46a6e4de319b77 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 29 Apr 2016 09:40:23 +0200 +Subject: [PATCH] core: fix memory leak on set-default, enable, disable etc + +Cherry-picked from: 24f412ca4150b490648ab8de45c6eda5bd697fd8 +Related: #1331667 +--- + src/core/dbus-manager.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index faa124d92..1a5525e50 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1621,6 +1621,7 @@ static int reply_unit_file_changes_and_free( + if (r < 0) + goto fail; + ++ unit_file_changes_free(changes, n_changes); + return sd_bus_send(bus, reply, NULL); + + fail: diff --git a/SOURCES/0313-nspawn-fix-minor-memory-leak.patch b/SOURCES/0313-nspawn-fix-minor-memory-leak.patch new file mode 100644 index 00000000..400089c2 --- /dev/null +++ b/SOURCES/0313-nspawn-fix-minor-memory-leak.patch @@ -0,0 +1,26 @@ +From 94f823629031f8849c8dc001d56a2c057531f0f2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 28 Oct 2015 18:22:23 +0100 +Subject: [PATCH] nspawn: fix minor memory leak + +When rebooting nspawn containers about 400 times we'd otherwise hit the +fd limit and refuse further reboots. + +Cherry-picked from: 3c747da38ca2f0642b4811812f6e2e2e1449a622 +Related: #1331667 +--- + src/shared/ptyfwd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c +index 31274a141..88b3f4e3c 100644 +--- a/src/shared/ptyfwd.c ++++ b/src/shared/ptyfwd.c +@@ -388,6 +388,7 @@ PTYForward *pty_forward_free(PTYForward *f) { + sd_event_source_unref(f->stdin_event_source); + sd_event_source_unref(f->stdout_event_source); + sd_event_source_unref(f->master_event_source); ++ sd_event_source_unref(f->sigwinch_event_source); + sd_event_unref(f->event); + + if (f->saved_stdout) diff --git a/SOURCES/0314-basic-fix-error-memleak-in-socket-util.patch b/SOURCES/0314-basic-fix-error-memleak-in-socket-util.patch new file mode 100644 index 00000000..8f7cfa26 --- /dev/null +++ b/SOURCES/0314-basic-fix-error-memleak-in-socket-util.patch @@ -0,0 +1,28 @@ +From 605a35e6e8dcb2518a1fa8f92fb5fb00a0419345 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 29 Apr 2016 12:13:06 +0200 +Subject: [PATCH] basic: fix error/memleak in socket-util + +Probably a typo, checking 'ret' instead of the return value 'p'. This +might cause the function to return failure, even though it succeeded. +Furthermore, it might leak resources. + +Cherry-picked from: 0810bc568ace619b16e440805e93256730d45541 +Related: #1331667 +--- + src/shared/socket-util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index a4e26b1d8..407d0afee 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -544,7 +544,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ + + } else { + p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path)); +- if (!ret) ++ if (!p) + return -ENOMEM; + } + diff --git a/SOURCES/0315-core-fix-memory-leak-in-manager_run_generators.patch b/SOURCES/0315-core-fix-memory-leak-in-manager_run_generators.patch new file mode 100644 index 00000000..a72a99b5 --- /dev/null +++ b/SOURCES/0315-core-fix-memory-leak-in-manager_run_generators.patch @@ -0,0 +1,52 @@ +From fa5a3a16e94773baf1dce3881d5cfab556b87113 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Mon, 11 May 2015 23:30:38 -0300 +Subject: [PATCH] core: fix memory leak in manager_run_generators() + +If systemd is built with GCC address sanitizer or leak sanitizer +the following memory leak ocurs: + +May 12 02:02:46 linux.site systemd[326]: ================================================================= +May 12 02:02:46 linux.site systemd[326]: ==326==ERROR: LeakSanitizer: detected memory leaks +May 12 02:02:46 linux.site systemd[326]: Direct leak of 101 byte(s) in 3 object(s) allocated from: +May 12 02:02:46 linux.site systemd[326]: #0 0x7fd1f504993f in strdup (/usr/lib64/libasan.so.2+0x6293f) +May 12 02:02:46 linux.site systemd[326]: #1 0x55d6ffac5336 in strv_new_ap src/shared/strv.c:163 +May 12 02:02:46 linux.site systemd[326]: #2 0x55d6ffac56a9 in strv_new src/shared/strv.c:185 +May 12 02:02:46 linux.site systemd[326]: #3 0x55d6ffa80272 in generator_paths src/shared/path-lookup.c:223 +May 12 02:02:46 linux.site systemd[326]: #4 0x55d6ff9bdb0f in manager_run_generators src/core/manager.c:2828 +May 12 02:02:46 linux.site systemd[326]: #5 0x55d6ff9b1a10 in manager_startup src/core/manager.c:1121 +May 12 02:02:46 linux.site systemd[326]: #6 0x55d6ff9a78e3 in main src/core/main.c:1667 +May 12 02:02:46 linux.site systemd[326]: #7 0x7fd1f394e8c4 in __libc_start_main (/lib64/libc.so.6+0x208c4) +May 12 02:02:46 linux.site systemd[326]: Direct leak of 29 byte(s) in 1 object(s) allocated from: +May 12 02:02:46 linux.site systemd[326]: #0 0x7fd1f504993f in strdup (/usr/lib64/libasan.so.2+0x6293f) +May 12 02:02:46 linux.site systemd[326]: #1 0x55d6ffac5288 in strv_new_ap src/shared/strv.c:152 +May 12 02:02:46 linux.site systemd[326]: #2 0x55d6ffac56a9 in strv_new src/shared/strv.c:185 +May 12 02:02:46 linux.site systemd[326]: #3 0x55d6ffa80272 in generator_paths src/shared/path-lookup.c:223 +May 12 02:02:46 linux.site systemd[326]: #4 0x55d6ff9bdb0f in manager_run_generators src/core/manager.c:2828 +May 12 02:02:46 linux.site systemd[326]: #5 0x55d6ff9b1a10 in manager_startup src/core/manager.c:1121 +May 12 02:02:46 linux.site systemd[326]: #6 0x55d6ff9a78e3 in main src/core/main.c:1667 +May 12 02:02:46 linux.site systemd[326]: #7 0x7fd1f394e8c4 in __libc_start_main (/lib64/libc.so.6+0x208c4) +May 12 02:02:46 linux.site systemd[326]: SUMMARY: AddressSanitizer: 130 byte(s) leaked in 4 allocation(s). + +There is a leak due to the the use of cleanup_free instead +_cleanup_strv_free_ + +Cherry-picked from: f42348ace7feb2311593b8cf6c876856eecf256a +Related: #1331667 +--- + src/core/manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index bb5050303..a1504bf17 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2827,7 +2827,7 @@ static void trim_generator_dir(Manager *m, char **generator) { + } + + static int manager_run_generators(Manager *m) { +- _cleanup_free_ char **paths = NULL; ++ _cleanup_strv_free_ char **paths = NULL; + const char *argv[5]; + char **path; + int r; diff --git a/SOURCES/0316-modules-load-fix-memory-leak.patch b/SOURCES/0316-modules-load-fix-memory-leak.patch new file mode 100644 index 00000000..756fd761 --- /dev/null +++ b/SOURCES/0316-modules-load-fix-memory-leak.patch @@ -0,0 +1,41 @@ +From 3c3d3e3e040d980186fec05506018db2d24faa83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Mon, 11 May 2015 15:37:47 -0300 +Subject: [PATCH] modules-load: fix memory leak + +================================================================= +==64281==ERROR: LeakSanitizer: detected memory leaks + +Direct leak of 32 byte(s) in 1 object(s) allocated from: + #0 0x7f623c961c4a in malloc (/usr/lib64/libasan.so.2+0x96c4a) + #1 0x5651f79ad34e in malloc_multiply (/home/crrodriguez/scm/systemd/systemd-modules-load+0x2134e) + #2 0x5651f79b02d6 in strjoin (/home/crrodriguez/scm/systemd/systemd-modules-load+0x242d6) + #3 0x5651f79be1f5 in files_add (/home/crrodriguez/scm/systemd/systemd-modules-load+0x321f5) + #4 0x5651f79be6a3 in conf_files_list_strv_internal (/home/crrodriguez/scm/systemd/systemd-modules-load+0x326a3) + #5 0x5651f79bea24 in conf_files_list_nulstr (/home/crrodriguez/scm/systemd/systemd-modules-load+0x32a24) + #6 0x5651f79ad01a in main (/home/crrodriguez/scm/systemd/systemd-modules-load+0x2101a) + #7 0x7f623c11586f in __libc_start_main (/lib64/libc.so.6+0x2086f) + +SUMMARY: AddressSanitizer: 32 byte(s) leaked in 1 allocation(s). + +This happens due to the wrong cleanup attribute is used (free vs strv_free) + +Cherry-picked from: 4df3277881cffcd3bc9a5238203d6af7e1fd960f +Related: #1331667 +--- + src/modules-load/modules-load.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c +index 5f678789c..bab9246a3 100644 +--- a/src/modules-load/modules-load.c ++++ b/src/modules-load/modules-load.c +@@ -256,7 +256,7 @@ int main(int argc, char *argv[]) { + } + + } else { +- _cleanup_free_ char **files = NULL; ++ _cleanup_strv_free_ char **files = NULL; + char **fn, **i; + + STRV_FOREACH(i, arg_proc_cmdline_modules) { diff --git a/SOURCES/0317-core-fix-memory-leak-on-failed-preset-all.patch b/SOURCES/0317-core-fix-memory-leak-on-failed-preset-all.patch new file mode 100644 index 00000000..7d2b32b1 --- /dev/null +++ b/SOURCES/0317-core-fix-memory-leak-on-failed-preset-all.patch @@ -0,0 +1,66 @@ +From 9d00fbb87c43e129e1ab29298afc86b7e8eed25c Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Mon, 18 Jan 2016 06:10:33 +0000 +Subject: [PATCH] core: fix memory leak on failed preset-all + +How to reproduce +$ systemctl set-default multi-user # https://github.com/systemd/systemd/issues/2298 +$ systemctl preset-all +Failed to execute operation: Too many levels of symbolic links + +$ systemctl poweroff + +Fixes: +==1== +==1== HEAP SUMMARY: +==1== in use at exit: 65,645 bytes in 7 blocks +==1== total heap usage: 40,539 allocs, 40,532 frees, 30,147,547 bytes allocated +==1== +==1== 109 (24 direct, 85 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 7 +==1== at 0x4C2BBCF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==1== by 0x4C2DE2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==1== by 0x23DA71: unit_file_changes_add (install.c:233) +==1== by 0x23E45D: remove_marked_symlinks_fd (install.c:453) +==1== by 0x23E267: remove_marked_symlinks_fd (install.c:405) +==1== by 0x23E641: remove_marked_symlinks (install.c:494) +==1== by 0x243A91: execute_preset (install.c:2190) +==1== by 0x244343: unit_file_preset_all (install.c:2351) +==1== by 0x18AAA2: method_preset_all_unit_files (dbus-manager.c:1846) +==1== by 0x1D8157: method_callbacks_run (bus-objects.c:420) +==1== by 0x1DA9E9: object_find_and_run (bus-objects.c:1257) +==1== by 0x1DB02B: bus_process_object (bus-objects.c:1373) +==1== +==1== LEAK SUMMARY: +==1== definitely lost: 24 bytes in 1 blocks +==1== indirectly lost: 85 bytes in 1 blocks +==1== possibly lost: 0 bytes in 0 blocks +==1== still reachable: 65,536 bytes in 5 blocks +==1== suppressed: 0 bytes in 0 blocks +==1== Reachable blocks (those to which a pointer was found) are not shown. +==1== To see them, rerun with: --leak-check=full --show-leak-kinds=all +==1== +==1== For counts of detected and suppressed errors, rerun with: -v +==1== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) + +Cherry-picked from: c292c3af38c8c23e183f3e63ef492926cea64bab +Related: #1331667 +--- + src/core/dbus-manager.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 1a5525e50..9eef290ca 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1875,8 +1875,10 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes); +- if (r < 0) ++ if (r < 0) { ++ unit_file_changes_free(changes, n_changes); + return r; ++ } + + return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes); + } diff --git a/SOURCES/0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch b/SOURCES/0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch new file mode 100644 index 00000000..444d226d --- /dev/null +++ b/SOURCES/0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch @@ -0,0 +1,37 @@ +From 68550741351080ab8458d54a6900b2b6ea1ef511 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Sat, 9 May 2015 22:14:09 -0300 +Subject: [PATCH] sd-bus: fix memory leak in test-bus-chat + +Building with address sanitizer enabled on GCC 5.1.x a memory leak +is reported because we never close the bus, fix it by using +cleanup variable attribute. + +Cherry-picked from: 2f50a2d55bf0a8b5959a6864ae1b39e7e9e0ce08 +Related: #1331667 +--- + src/libsystemd/sd-bus/test-bus-chat.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c +index 8625ee6d8..a80aaaeef 100644 +--- a/src/libsystemd/sd-bus/test-bus-chat.c ++++ b/src/libsystemd/sd-bus/test-bus-chat.c +@@ -264,7 +264,7 @@ fail: + + static void* client1(void*p) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; +- sd_bus *bus = NULL; ++ _cleanup_bus_close_unref_ sd_bus *bus = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + const char *hello; + int r; +@@ -347,8 +347,6 @@ finish: + else + sd_bus_send(bus, q, NULL); + +- sd_bus_flush(bus); +- sd_bus_unref(bus); + } + + sd_bus_error_free(&error); diff --git a/SOURCES/0319-core-fix-memory-leak-in-transient-units.patch b/SOURCES/0319-core-fix-memory-leak-in-transient-units.patch new file mode 100644 index 00000000..72aec5cd --- /dev/null +++ b/SOURCES/0319-core-fix-memory-leak-in-transient-units.patch @@ -0,0 +1,55 @@ +From c7d030b3f2b5969751872673e9082d0c10c031b5 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 15 Jan 2016 02:41:27 +0000 +Subject: [PATCH] core: fix memory leak in transient units + +Fixes: +==1== HEAP SUMMARY: +==1== in use at exit: 67,182 bytes in 91 blocks +==1== total heap usage: 70,485 allocs, 70,394 frees, 42,184,635 bytes +allocated +==1== +==1== 5,742 (696 direct, 5,046 indirect) bytes in 29 blocks are +definitely lost in loss record 4 of 7 +==1== at 0x4C2DD9F: realloc (in +/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==1== by 0x21ADDD: realloc_multiply (alloc-util.h:67) +==1== by 0x21BFB0: strv_push (strv.c:448) +==1== by 0x21C245: strv_consume (strv.c:520) +==1== by 0x21C33C: strv_extend (strv.c:559) +==1== by 0x278AD7: unit_write_drop_in (unit.c:3352) +==1== by 0x278EEB: unit_write_drop_in_private (unit.c:3403) +==1== by 0x190C21: bus_service_set_transient_property +(dbus-service.c:254) +==1== by 0x190DBC: bus_service_set_property (dbus-service.c:284) +==1== by 0x18F00E: bus_unit_set_properties (dbus-unit.c:1226) +==1== by 0x186F6A: transient_unit_from_message (dbus-manager.c:683) +==1== by 0x1872B7: method_start_transient_unit (dbus-manager.c:763) +==1== +==1== LEAK SUMMARY: +==1== definitely lost: 696 bytes in 29 blocks +==1== indirectly lost: 5,046 bytes in 58 blocks +==1== possibly lost: 0 bytes in 0 blocks +==1== still reachable: 61,440 bytes in 4 blocks +==1== suppressed: 0 bytes in 0 blocks + +Cherry-picked from: af4fbf3c1fdd4196f7a325602daaa846fe5f3012 +Related: #1331667 +--- + src/core/load-dropin.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c +index 8be190040..42cf00572 100644 +--- a/src/core/load-dropin.c ++++ b/src/core/load-dropin.c +@@ -68,6 +68,9 @@ int unit_load_dropin(Unit *u) { + } + } + ++ strv_free(u->dropin_paths); ++ u->dropin_paths = NULL; ++ + r = unit_find_dropin_paths(u, &u->dropin_paths); + if (r <= 0) + return 0; diff --git a/SOURCES/0320-bus-fix-leak-in-error-path.patch b/SOURCES/0320-bus-fix-leak-in-error-path.patch new file mode 100644 index 00000000..3a61e88c --- /dev/null +++ b/SOURCES/0320-bus-fix-leak-in-error-path.patch @@ -0,0 +1,52 @@ +From 69aaf3c41923fafd9616b1bbec51fa6bcb23b886 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 7 Mar 2015 15:05:50 -0500 +Subject: [PATCH] bus: fix leak in error path + +CID #1271349. + +Cherry-picked from: bcf88fc3f14867f1cabc911c27b661d738281df0 +Related: #1331667 +--- + src/libsystemd/sd-bus/bus-message.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index 295930303..c8402a23a 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -441,7 +441,7 @@ int bus_message_from_header( + size_t extra, + sd_bus_message **ret) { + +- sd_bus_message *m; ++ _cleanup_free_ sd_bus_message *m = NULL; + struct bus_header *h; + size_t a, label_sz; + +@@ -460,15 +460,13 @@ int bus_message_from_header( + return -EBADMSG; + + h = header; +- if (h->version != 1 && +- h->version != 2) ++ if (!IN_SET(h->version, 1, 2)) + return -EBADMSG; + + if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID) + return -EBADMSG; + +- if (h->endian != BUS_LITTLE_ENDIAN && +- h->endian != BUS_BIG_ENDIAN) ++ if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN)) + return -EBADMSG; + + /* Note that we are happy with unknown flags in the flags header! */ +@@ -557,6 +555,7 @@ int bus_message_from_header( + + m->bus = sd_bus_ref(bus); + *ret = m; ++ m = NULL; + + return 0; + } diff --git a/SOURCES/0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch b/SOURCES/0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch new file mode 100644 index 00000000..d3b9d3a7 --- /dev/null +++ b/SOURCES/0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch @@ -0,0 +1,24 @@ +From c95edddeb70a48202a0baf7b71450be87d2d921c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 12 Apr 2016 23:36:37 -0400 +Subject: [PATCH] shared/logs-show: fix memleak in add_matches_for_unit + +Cherry-picked from: 42fbdf45864b46f3eb62a3738b81e687685eb9bd +Related: #1331667 +--- + src/shared/logs-show.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c +index c2495056d..8c374116a 100644 +--- a/src/shared/logs-show.c ++++ b/src/shared/logs-show.c +@@ -1060,7 +1060,7 @@ int add_matches_for_unit(sd_journal *j, const char *unit) { + ); + + if (r == 0 && endswith(unit, ".slice")) { +- char *m5 = strappend("_SYSTEMD_SLICE=", unit); ++ const char *m5 = strjoina("_SYSTEMD_SLICE=", unit); + + /* Show all messages belonging to a slice */ + (void)( diff --git a/SOURCES/0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch b/SOURCES/0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch new file mode 100644 index 00000000..65b0aa50 --- /dev/null +++ b/SOURCES/0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch @@ -0,0 +1,164 @@ +From 75131b469fa9e1e2e3cb623fa1f3d36cba36af78 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Wed, 11 May 2016 19:34:13 +0200 +Subject: [PATCH] logind: introduce LockedHint and SetLockedHint (#3238) + +Desktop environments can keep this property up to date to allow +applications to easily track session's Lock status. + +Cherry-picked from: 42d35e1301928d08dd32ec51f0205252ae658ba5 +Resolves: #1335499 +--- + src/login/logind-session-dbus.c | 50 +++++++++++++++++++++++++++++++++++ + src/login/logind-session.c | 17 ++++++++++++ + src/login/logind-session.h | 4 +++ + src/login/org.freedesktop.login1.conf | 4 +++ + 4 files changed, 75 insertions(+) + +diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c +index 4e7edef52..75b7186e8 100644 +--- a/src/login/logind-session-dbus.c ++++ b/src/login/logind-session-dbus.c +@@ -180,6 +180,24 @@ static int property_get_idle_since_hint( + return sd_bus_message_append(reply, "t", u); + } + ++static int property_get_locked_hint( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ++ Session *s = userdata; ++ ++ assert(bus); ++ assert(reply); ++ assert(s); ++ ++ return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0); ++} ++ + static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + int r; +@@ -255,6 +273,36 @@ static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *user + return sd_bus_reply_method_return(message, NULL); + } + ++static int method_set_locked_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { ++ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; ++ Session *s = userdata; ++ uid_t uid; ++ int r, b; ++ ++ assert(bus); ++ assert(message); ++ assert(s); ++ ++ r = sd_bus_message_read(message, "b", &b); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_creds_get_euid(creds, &uid); ++ if (r < 0) ++ return r; ++ ++ if (uid != 0 && uid != s->user->uid) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint"); ++ ++ session_set_locked_hint(s, b); ++ ++ return sd_bus_reply_method_return(message, NULL); ++} ++ + static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + const char *swho; +@@ -455,6 +503,7 @@ const sd_bus_vtable session_vtable[] = { + SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), ++ SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + + SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("Activate", NULL, NULL, method_activate, SD_BUS_VTABLE_UNPRIVILEGED), +@@ -462,6 +511,7 @@ const sd_bus_vtable session_vtable[] = { + SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0), + SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), ++ SD_BUS_METHOD("SetLockedHint", "b", NULL, method_set_locked_hint, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED), +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index d2e7b4012..dc24539f1 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -843,6 +843,23 @@ void session_set_idle_hint(Session *s, bool b) { + manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); + } + ++int session_get_locked_hint(Session *s) { ++ assert(s); ++ ++ return s->locked_hint; ++} ++ ++void session_set_locked_hint(Session *s, bool b) { ++ assert(s); ++ ++ if (s->locked_hint == b) ++ return; ++ ++ s->locked_hint = b; ++ ++ session_send_changed(s, "LockedHint", NULL); ++} ++ + static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Session *s = userdata; + +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index a007fb5e8..5002b6868 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -111,6 +111,8 @@ struct Session { + bool idle_hint; + dual_timestamp idle_hint_timestamp; + ++ bool locked_hint; ++ + bool in_gc_queue:1; + bool started:1; + bool stopping:1; +@@ -137,6 +139,8 @@ int session_activate(Session *s); + bool session_is_active(Session *s); + int session_get_idle_hint(Session *s, dual_timestamp *t); + void session_set_idle_hint(Session *s, bool b); ++int session_get_locked_hint(Session *s); ++void session_set_locked_hint(Session *s, bool b); + int session_create_fifo(Session *s); + int session_start(Session *s); + int session_stop(Session *s, bool force); +diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf +index 1318328aa..dc7e0bec2 100644 +--- a/src/login/org.freedesktop.login1.conf ++++ b/src/login/org.freedesktop.login1.conf +@@ -160,6 +160,10 @@ + send_interface="org.freedesktop.login1.Session" + send_member="SetIdleHint"/> + ++ ++ + diff --git a/SOURCES/0323-import-use-the-old-curl-api.patch b/SOURCES/0323-import-use-the-old-curl-api.patch new file mode 100644 index 00000000..fb63cd92 --- /dev/null +++ b/SOURCES/0323-import-use-the-old-curl-api.patch @@ -0,0 +1,40 @@ +From 575f559bcd992d7fd2d7d46b695b7f42923b4463 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 6 Apr 2016 15:39:09 +0200 +Subject: [PATCH] import: use the old curl api + +libcurl in rhel does not have CURLOPT_XFERINFO* symbols, so lets use the +old interface. + +RHEL-only +Resolves: #1284974 +--- + src/import/import-job.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/import/import-job.c b/src/import/import-job.c +index 809486500..5f9cfd366 100644 +--- a/src/import/import-job.c ++++ b/src/import/import-job.c +@@ -587,7 +587,7 @@ fail: + return 0; + } + +-static int import_job_progress_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { ++static int import_job_progress_callback(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow) { + ImportJob *j = userdata; + unsigned percent; + usec_t n; +@@ -714,10 +714,10 @@ int import_job_begin(ImportJob *j) { + if (curl_easy_setopt(j->curl, CURLOPT_HEADERDATA, j) != CURLE_OK) + return -EIO; + +- if (curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, import_job_progress_callback) != CURLE_OK) ++ if (curl_easy_setopt(j->curl, CURLOPT_PROGRESSFUNCTION, import_job_progress_callback) != CURLE_OK) + return -EIO; + +- if (curl_easy_setopt(j->curl, CURLOPT_XFERINFODATA, j) != CURLE_OK) ++ if (curl_easy_setopt(j->curl, CURLOPT_PROGRESSDATA, j) != CURLE_OK) + return -EIO; + + if (curl_easy_setopt(j->curl, CURLOPT_NOPROGRESS, 0) != CURLE_OK) diff --git a/SOURCES/0324-importd-drop-dkr-support.patch b/SOURCES/0324-importd-drop-dkr-support.patch new file mode 100644 index 00000000..341a489e --- /dev/null +++ b/SOURCES/0324-importd-drop-dkr-support.patch @@ -0,0 +1,1694 @@ +From b4bfb025f7ab0878e8e7e980dbad5b0a5bed1555 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 10 Dec 2015 12:40:04 +0100 +Subject: [PATCH] importd: drop dkr support + +The current code is not compatible with current dkr protocols anyway, +and dkr has a different focus ("microservices") than nspawn anyway +("whole machine containers"), hence drop support for it, we cannot +reasonably keep this up to date, and it creates the impression we'd +actually care for the microservices usecase. + +Cherry-picked from: b43d75c +Related: #1284974 +--- + Makefile.am | 2 - + TODO | 4 - + configure.ac | 9 - + man/machinectl.xml | 58 --- + src/import/import-dkr.c | 891 -------------------------------- + src/import/import-dkr.h | 36 -- + src/import/importd.c | 111 +--- + src/import/org.freedesktop.import1.conf | 4 - + src/import/pull.c | 119 +---- + src/machine/machinectl.c | 90 +--- + src/shared/import-util.c | 31 -- + src/shared/import-util.h | 4 - + 12 files changed, 5 insertions(+), 1354 deletions(-) + delete mode 100644 src/import/import-dkr.c + delete mode 100644 src/import/import-dkr.h + +diff --git a/Makefile.am b/Makefile.am +index 3a09e0a62..b0a34b212 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5369,8 +5369,6 @@ systemd_pull_SOURCES = \ + src/import/import-raw.h \ + src/import/import-tar.c \ + src/import/import-tar.h \ +- src/import/import-dkr.c \ +- src/import/import-dkr.h \ + src/import/import-job.c \ + src/import/import-job.h \ + src/import/import-common.c \ +diff --git a/TODO b/TODO +index 90b2c4b30..d96d2bf0e 100644 +--- a/TODO ++++ b/TODO +@@ -126,10 +126,6 @@ Features: + + * rework journald sigbus stuff to use mutex + +-* import-dkr: support tarsum checksum verification, if it becomes reality one day... +- +-* import-dkr: convert json bits to nspawn configuration +- + * import: support import from local files, and export to local files + + * core/cgroup: support net_cls modules, and support automatically allocating class ids, then add support for making firewall changes depending on it, to implement a per-service firewall +diff --git a/configure.ac b/configure.ac +index 9103f9b92..2734368dc 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1389,14 +1389,6 @@ AC_ARG_ENABLE([split-usr], + enable_split_usr=no + ])]) + +-AC_ARG_WITH([dkr-index-url], +- [AS_HELP_STRING([--dkr-index-url=URL], [Specify the default index URL to use for image downloads])], +- [DEFAULT_DKR_INDEX_URL="\"$withval\""], +- [DEFAULT_DKR_INDEX_URL="NULL"]) +- +-AC_DEFINE_UNQUOTED(DEFAULT_DKR_INDEX_URL, [$DEFAULT_DKR_INDEX_URL], [Default index URL to use for image downloads]) +-AC_SUBST(DEFAULT_DKR_INDEX_URL) +- + AS_IF([test "x${enable_split_usr}" = "xyes"], [ + AC_DEFINE(HAVE_SPLIT_USR, 1, [Define if /bin, /sbin aren't symlinks into /usr]) + ]) +@@ -1564,7 +1556,6 @@ AC_MSG_RESULT([ + Maximum System UID: ${SYSTEM_UID_MAX} + Maximum System GID: ${SYSTEM_GID_MAX} + Certificate root: ${CERTIFICATEROOT} +- Default dkr Index ${DEFAULT_DKR_INDEX_URL} + + CFLAGS: ${OUR_CFLAGS} ${CFLAGS} + CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} +diff --git a/man/machinectl.xml b/man/machinectl.xml +index 640cb8b7d..b0a7f2ae4 100644 +--- a/man/machinectl.xml ++++ b/man/machinectl.xml +@@ -204,16 +204,6 @@ + image. + + +- +- +- +- Specifies the index server to use for +- downloading dkr images with the +- pull-dkr. Takes a +- http://, https:// +- URL. +- +- + + + +@@ -602,42 +592,6 @@ + below. + + +- +- pull-dkr REMOTE [NAME] +- +- Downloads a dkr container +- image and makes it available locally. The remote name refers +- to a dkr container name. If omitted, the +- local machine name is derived from the dkr +- container name. +- +- Image verification is not available for +- dkr containers, and thus +- must always be specified with +- this command. +- +- This command downloads all (missing) layers for the +- specified container and places them in read-only subvolumes in +- /var/lib/machines/. A writable snapshot +- of the newest layer is then created under the specified local +- machine name. To omit creation of this writable snapshot, pass +- - as local machine name. +- +- The read-only layer subvolumes are prefixed with +- .dkr-, and thus now shown by +- list-images, unless +- is passed. +- +- To specify the dkr index server to +- use for looking up the specified container, use +- . +- +- Note that pressing C-c during execution of this command +- will not abort the download. Use +- cancel-transfer, described +- below. +- +- + + list-transfers + +@@ -728,18 +682,6 @@ + the machine started as system service. With the last command a + login prompt into the container is requested. + +- +- +- Download a Fedora <literal>dkr</literal> image +- +- # machinectl pull-dkr --verify=no mattdm/fedora +-# systemd-nspawn -M fedora +- +- Downloads a dkr image and opens a shell +- in it. Note that the specified download command might require an +- index server to be specified with the +- --dkr-index-url=. +- + + + +diff --git a/src/import/import-dkr.c b/src/import/import-dkr.c +deleted file mode 100644 +index fb72f6cee..000000000 +--- a/src/import/import-dkr.c ++++ /dev/null +@@ -1,891 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 Lennart Poettering +- +- systemd is free software; you can redistribute it and/or modify it +- under the terms of the GNU Lesser General Public License as published by +- the Free Software Foundation; either version 2.1 of the License, or +- (at your option) any later version. +- +- systemd is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public License +- along with systemd; If not, see . +-***/ +- +-#include +-#include +- +-#include "sd-daemon.h" +-#include "json.h" +-#include "strv.h" +-#include "btrfs-util.h" +-#include "utf8.h" +-#include "mkdir.h" +-#include "import-util.h" +-#include "curl-util.h" +-#include "aufs-util.h" +-#include "import-job.h" +-#include "import-common.h" +-#include "import-dkr.h" +- +-typedef enum DkrProgress { +- DKR_SEARCHING, +- DKR_RESOLVING, +- DKR_METADATA, +- DKR_DOWNLOADING, +- DKR_COPYING, +-} DkrProgress; +- +-struct DkrImport { +- sd_event *event; +- CurlGlue *glue; +- +- char *index_url; +- char *image_root; +- +- ImportJob *images_job; +- ImportJob *tags_job; +- ImportJob *ancestry_job; +- ImportJob *json_job; +- ImportJob *layer_job; +- +- char *name; +- char *tag; +- char *id; +- +- char *response_token; +- char **response_registries; +- +- char **ancestry; +- unsigned n_ancestry; +- unsigned current_ancestry; +- +- DkrImportFinished on_finished; +- void *userdata; +- +- char *local; +- bool force_local; +- +- char *temp_path; +- char *final_path; +- +- pid_t tar_pid; +-}; +- +-#define PROTOCOL_PREFIX "https://" +- +-#define HEADER_TOKEN "X-Do" /* the HTTP header for the auth token */ "cker-Token:" +-#define HEADER_REGISTRY "X-Do" /*the HTTP header for the registry */ "cker-Endpoints:" +- +-#define LAYERS_MAX 2048 +- +-static void dkr_import_job_on_finished(ImportJob *j); +- +-DkrImport* dkr_import_unref(DkrImport *i) { +- if (!i) +- return NULL; +- +- if (i->tar_pid > 1) { +- (void) kill_and_sigcont(i->tar_pid, SIGKILL); +- (void) wait_for_terminate(i->tar_pid, NULL); +- } +- +- import_job_unref(i->images_job); +- import_job_unref(i->tags_job); +- import_job_unref(i->ancestry_job); +- import_job_unref(i->json_job); +- import_job_unref(i->layer_job); +- +- curl_glue_unref(i->glue); +- sd_event_unref(i->event); +- +- if (i->temp_path) { +- (void) btrfs_subvol_remove(i->temp_path); +- (void) rm_rf_dangerous(i->temp_path, false, true, false); +- free(i->temp_path); +- } +- +- free(i->name); +- free(i->tag); +- free(i->id); +- free(i->response_token); +- free(i->response_registries); +- strv_free(i->ancestry); +- free(i->final_path); +- free(i->index_url); +- free(i->image_root); +- free(i->local); +- free(i); +- +- return NULL; +-} +- +-int dkr_import_new( +- DkrImport **ret, +- sd_event *event, +- const char *index_url, +- const char *image_root, +- DkrImportFinished on_finished, +- void *userdata) { +- +- _cleanup_(dkr_import_unrefp) DkrImport *i = NULL; +- char *e; +- int r; +- +- assert(ret); +- assert(index_url); +- +- if (!http_url_is_valid(index_url)) +- return -EINVAL; +- +- i = new0(DkrImport, 1); +- if (!i) +- return -ENOMEM; +- +- i->on_finished = on_finished; +- i->userdata = userdata; +- +- i->image_root = strdup(image_root ?: "/var/lib/machines"); +- if (!i->image_root) +- return -ENOMEM; +- +- i->index_url = strdup(index_url); +- if (!i->index_url) +- return -ENOMEM; +- +- e = endswith(i->index_url, "/"); +- if (e) +- *e = 0; +- +- if (event) +- i->event = sd_event_ref(event); +- else { +- r = sd_event_default(&i->event); +- if (r < 0) +- return r; +- } +- +- r = curl_glue_new(&i->glue, i->event); +- if (r < 0) +- return r; +- +- i->glue->on_finished = import_job_curl_on_finished; +- i->glue->userdata = i; +- +- *ret = i; +- i = NULL; +- +- return 0; +-} +- +-static void dkr_import_report_progress(DkrImport *i, DkrProgress p) { +- unsigned percent; +- +- assert(i); +- +- switch (p) { +- +- case DKR_SEARCHING: +- percent = 0; +- if (i->images_job) +- percent += i->images_job->progress_percent * 5 / 100; +- break; +- +- case DKR_RESOLVING: +- percent = 5; +- if (i->tags_job) +- percent += i->tags_job->progress_percent * 5 / 100; +- break; +- +- case DKR_METADATA: +- percent = 10; +- if (i->ancestry_job) +- percent += i->ancestry_job->progress_percent * 5 / 100; +- if (i->json_job) +- percent += i->json_job->progress_percent * 5 / 100; +- break; +- +- case DKR_DOWNLOADING: +- percent = 20; +- percent += 75 * i->current_ancestry / MAX(1U, i->n_ancestry); +- if (i->layer_job) +- percent += i->layer_job->progress_percent * 75 / MAX(1U, i->n_ancestry) / 100; +- +- break; +- +- case DKR_COPYING: +- percent = 95; +- break; +- +- default: +- assert_not_reached("Unknown progress state"); +- } +- +- sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); +- log_debug("Combined progress %u%%", percent); +-} +- +-static int parse_id(const void *payload, size_t size, char **ret) { +- _cleanup_free_ char *buf = NULL, *id = NULL, *other = NULL; +- union json_value v = {}; +- void *json_state = NULL; +- const char *p; +- int t; +- +- assert(payload); +- assert(ret); +- +- if (size <= 0) +- return -EBADMSG; +- +- if (memchr(payload, 0, size)) +- return -EBADMSG; +- +- buf = strndup(payload, size); +- if (!buf) +- return -ENOMEM; +- +- p = buf; +- t = json_tokenize(&p, &id, &v, &json_state, NULL); +- if (t < 0) +- return t; +- if (t != JSON_STRING) +- return -EBADMSG; +- +- t = json_tokenize(&p, &other, &v, &json_state, NULL); +- if (t < 0) +- return t; +- if (t != JSON_END) +- return -EBADMSG; +- +- if (!dkr_id_is_valid(id)) +- return -EBADMSG; +- +- *ret = id; +- id = NULL; +- +- return 0; +-} +- +-static int parse_ancestry(const void *payload, size_t size, char ***ret) { +- _cleanup_free_ char *buf = NULL; +- void *json_state = NULL; +- const char *p; +- enum { +- STATE_BEGIN, +- STATE_ITEM, +- STATE_COMMA, +- STATE_END, +- } state = STATE_BEGIN; +- _cleanup_strv_free_ char **l = NULL; +- size_t n = 0, allocated = 0; +- +- if (size <= 0) +- return -EBADMSG; +- +- if (memchr(payload, 0, size)) +- return -EBADMSG; +- +- buf = strndup(payload, size); +- if (!buf) +- return -ENOMEM; +- +- p = buf; +- for (;;) { +- _cleanup_free_ char *str; +- union json_value v = {}; +- int t; +- +- t = json_tokenize(&p, &str, &v, &json_state, NULL); +- if (t < 0) +- return t; +- +- switch (state) { +- +- case STATE_BEGIN: +- if (t == JSON_ARRAY_OPEN) +- state = STATE_ITEM; +- else +- return -EBADMSG; +- +- break; +- +- case STATE_ITEM: +- if (t == JSON_STRING) { +- if (!dkr_id_is_valid(str)) +- return -EBADMSG; +- +- if (n+1 > LAYERS_MAX) +- return -EFBIG; +- +- if (!GREEDY_REALLOC(l, allocated, n + 2)) +- return -ENOMEM; +- +- l[n++] = str; +- str = NULL; +- l[n] = NULL; +- +- state = STATE_COMMA; +- +- } else if (t == JSON_ARRAY_CLOSE) +- state = STATE_END; +- else +- return -EBADMSG; +- +- break; +- +- case STATE_COMMA: +- if (t == JSON_COMMA) +- state = STATE_ITEM; +- else if (t == JSON_ARRAY_CLOSE) +- state = STATE_END; +- else +- return -EBADMSG; +- break; +- +- case STATE_END: +- if (t == JSON_END) { +- +- if (strv_isempty(l)) +- return -EBADMSG; +- +- if (!strv_is_uniq(l)) +- return -EBADMSG; +- +- l = strv_reverse(l); +- +- *ret = l; +- l = NULL; +- return 0; +- } else +- return -EBADMSG; +- } +- +- } +-} +- +-static const char *dkr_import_current_layer(DkrImport *i) { +- assert(i); +- +- if (strv_isempty(i->ancestry)) +- return NULL; +- +- return i->ancestry[i->current_ancestry]; +-} +- +-static const char *dkr_import_current_base_layer(DkrImport *i) { +- assert(i); +- +- if (strv_isempty(i->ancestry)) +- return NULL; +- +- if (i->current_ancestry <= 0) +- return NULL; +- +- return i->ancestry[i->current_ancestry-1]; +-} +- +-static int dkr_import_add_token(DkrImport *i, ImportJob *j) { +- const char *t; +- +- assert(i); +- assert(j); +- +- if (i->response_token) +- t = strjoina("Authorization: Token ", i->response_token); +- else +- t = HEADER_TOKEN " true"; +- +- j->request_header = curl_slist_new("Accept: application/json", t, NULL); +- if (!j->request_header) +- return -ENOMEM; +- +- return 0; +-} +- +-static bool dkr_import_is_done(DkrImport *i) { +- assert(i); +- assert(i->images_job); +- +- if (i->images_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (!i->tags_job || i->tags_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (!i->ancestry_job || i->ancestry_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (!i->json_job || i->json_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (i->layer_job && i->layer_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (dkr_import_current_layer(i)) +- return false; +- +- return true; +-} +- +-static int dkr_import_make_local_copy(DkrImport *i) { +- int r; +- +- assert(i); +- +- if (!i->local) +- return 0; +- +- if (!i->final_path) { +- i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL); +- if (!i->final_path) +- return log_oom(); +- } +- +- r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local); +- if (r < 0) +- return r; +- +- return 0; +-} +- +-static int dkr_import_job_on_open_disk(ImportJob *j) { +- const char *base; +- DkrImport *i; +- int r; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- assert(i->layer_job == j); +- assert(i->final_path); +- assert(!i->temp_path); +- assert(i->tar_pid <= 0); +- +- r = tempfn_random(i->final_path, &i->temp_path); +- if (r < 0) +- return log_oom(); +- +- mkdir_parents_label(i->temp_path, 0700); +- +- base = dkr_import_current_base_layer(i); +- if (base) { +- const char *base_path; +- +- base_path = strjoina(i->image_root, "/.dkr-", base); +- r = btrfs_subvol_snapshot(base_path, i->temp_path, false, true); +- } else +- r = btrfs_subvol_make(i->temp_path); +- if (r < 0) +- return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path); +- +- j->disk_fd = import_fork_tar(i->temp_path, &i->tar_pid); +- if (j->disk_fd < 0) +- return j->disk_fd; +- +- return 0; +-} +- +-static void dkr_import_job_on_progress(ImportJob *j) { +- DkrImport *i; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- +- dkr_import_report_progress( +- i, +- j == i->images_job ? DKR_SEARCHING : +- j == i->tags_job ? DKR_RESOLVING : +- j == i->ancestry_job || j == i->json_job ? DKR_METADATA : +- DKR_DOWNLOADING); +-} +- +-static int dkr_import_pull_layer(DkrImport *i) { +- _cleanup_free_ char *path = NULL; +- const char *url, *layer = NULL; +- int r; +- +- assert(i); +- assert(!i->layer_job); +- assert(!i->temp_path); +- assert(!i->final_path); +- +- for (;;) { +- layer = dkr_import_current_layer(i); +- if (!layer) +- return 0; /* no more layers */ +- +- path = strjoin(i->image_root, "/.dkr-", layer, NULL); +- if (!path) +- return log_oom(); +- +- if (laccess(path, F_OK) < 0) { +- if (errno == ENOENT) +- break; +- +- return log_error_errno(errno, "Failed to check for container: %m"); +- } +- +- log_info("Layer %s already exists, skipping.", layer); +- +- i->current_ancestry++; +- +- free(path); +- path = NULL; +- } +- +- log_info("Pulling layer %s...", layer); +- +- i->final_path = path; +- path = NULL; +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", layer, "/layer"); +- r = import_job_new(&i->layer_job, url, i->glue, i); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate layer job: %m"); +- +- r = dkr_import_add_token(i, i->layer_job); +- if (r < 0) +- return log_oom(); +- +- i->layer_job->on_finished = dkr_import_job_on_finished; +- i->layer_job->on_open_disk = dkr_import_job_on_open_disk; +- i->layer_job->on_progress = dkr_import_job_on_progress; +- +- r = import_job_begin(i->layer_job); +- if (r < 0) +- return log_error_errno(r, "Failed to start layer job: %m"); +- +- return 0; +-} +- +-static void dkr_import_job_on_finished(ImportJob *j) { +- DkrImport *i; +- int r; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- if (j->error != 0) { +- if (j == i->images_job) +- log_error_errno(j->error, "Failed to retrieve images list. (Wrong index URL?)"); +- else if (j == i->tags_job) +- log_error_errno(j->error, "Failed to retrieve tags list."); +- else if (j == i->ancestry_job) +- log_error_errno(j->error, "Failed to retrieve ancestry list."); +- else if (j == i->json_job) +- log_error_errno(j->error, "Failed to retrieve json data."); +- else +- log_error_errno(j->error, "Failed to retrieve layer data."); +- +- r = j->error; +- goto finish; +- } +- +- if (i->images_job == j) { +- const char *url; +- +- assert(!i->tags_job); +- assert(!i->ancestry_job); +- assert(!i->json_job); +- assert(!i->layer_job); +- +- if (strv_isempty(i->response_registries)) { +- r = -EBADMSG; +- log_error("Didn't get registry information."); +- goto finish; +- } +- +- log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]); +- dkr_import_report_progress(i, DKR_RESOLVING); +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/repositories/", i->name, "/tags/", i->tag); +- r = import_job_new(&i->tags_job, url, i->glue, i); +- if (r < 0) { +- log_error_errno(r, "Failed to allocate tags job: %m"); +- goto finish; +- } +- +- r = dkr_import_add_token(i, i->tags_job); +- if (r < 0) { +- log_oom(); +- goto finish; +- } +- +- i->tags_job->on_finished = dkr_import_job_on_finished; +- i->tags_job->on_progress = dkr_import_job_on_progress; +- +- r = import_job_begin(i->tags_job); +- if (r < 0) { +- log_error_errno(r, "Failed to start tags job: %m"); +- goto finish; +- } +- +- } else if (i->tags_job == j) { +- const char *url; +- char *id = NULL; +- +- assert(!i->ancestry_job); +- assert(!i->json_job); +- assert(!i->layer_job); +- +- r = parse_id(j->payload, j->payload_size, &id); +- if (r < 0) { +- log_error_errno(r, "Failed to parse JSON id."); +- goto finish; +- } +- +- free(i->id); +- i->id = id; +- +- log_info("Tag lookup succeeded, resolved to layer %s.", i->id); +- dkr_import_report_progress(i, DKR_METADATA); +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/ancestry"); +- r = import_job_new(&i->ancestry_job, url, i->glue, i); +- if (r < 0) { +- log_error_errno(r, "Failed to allocate ancestry job: %m"); +- goto finish; +- } +- +- r = dkr_import_add_token(i, i->ancestry_job); +- if (r < 0) { +- log_oom(); +- goto finish; +- } +- +- i->ancestry_job->on_finished = dkr_import_job_on_finished; +- i->ancestry_job->on_progress = dkr_import_job_on_progress; +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/json"); +- r = import_job_new(&i->json_job, url, i->glue, i); +- if (r < 0) { +- log_error_errno(r, "Failed to allocate json job: %m"); +- goto finish; +- } +- +- r = dkr_import_add_token(i, i->json_job); +- if (r < 0) { +- log_oom(); +- goto finish; +- } +- +- i->json_job->on_finished = dkr_import_job_on_finished; +- i->json_job->on_progress = dkr_import_job_on_progress; +- +- r = import_job_begin(i->ancestry_job); +- if (r < 0) { +- log_error_errno(r, "Failed to start ancestry job: %m"); +- goto finish; +- } +- +- r = import_job_begin(i->json_job); +- if (r < 0) { +- log_error_errno(r, "Failed to start json job: %m"); +- goto finish; +- } +- +- } else if (i->ancestry_job == j) { +- char **ancestry = NULL, **k; +- unsigned n; +- +- assert(!i->layer_job); +- +- r = parse_ancestry(j->payload, j->payload_size, &ancestry); +- if (r < 0) { +- log_error_errno(r, "Failed to parse JSON id."); +- goto finish; +- } +- +- n = strv_length(ancestry); +- if (n <= 0 || !streq(ancestry[n-1], i->id)) { +- log_error("Ancestry doesn't end in main layer."); +- strv_free(ancestry); +- r = -EBADMSG; +- goto finish; +- } +- +- log_info("Ancestor lookup succeeded, requires layers:\n"); +- STRV_FOREACH(k, ancestry) +- log_info("\t%s", *k); +- +- strv_free(i->ancestry); +- i->ancestry = ancestry; +- i->n_ancestry = n; +- i->current_ancestry = 0; +- +- dkr_import_report_progress(i, DKR_DOWNLOADING); +- +- r = dkr_import_pull_layer(i); +- if (r < 0) +- goto finish; +- +- } else if (i->layer_job == j) { +- assert(i->temp_path); +- assert(i->final_path); +- +- j->disk_fd = safe_close(j->disk_fd); +- +- if (i->tar_pid > 0) { +- r = wait_for_terminate_and_warn("tar", i->tar_pid, true); +- i->tar_pid = 0; +- if (r < 0) +- goto finish; +- } +- +- r = aufs_resolve(i->temp_path); +- if (r < 0) { +- log_error_errno(r, "Failed to resolve aufs whiteouts: %m"); +- goto finish; +- } +- +- r = btrfs_subvol_set_read_only(i->temp_path, true); +- if (r < 0) { +- log_error_errno(r, "Failed to mark snapshot read-only: %m"); +- goto finish; +- } +- +- if (rename(i->temp_path, i->final_path) < 0) { +- log_error_errno(errno, "Failed to rename snaphsot: %m"); +- goto finish; +- } +- +- log_info("Completed writing to layer %s.", i->final_path); +- +- i->layer_job = import_job_unref(i->layer_job); +- free(i->temp_path); +- i->temp_path = NULL; +- free(i->final_path); +- i->final_path = NULL; +- +- i->current_ancestry ++; +- r = dkr_import_pull_layer(i); +- if (r < 0) +- goto finish; +- +- } else if (i->json_job != j) +- assert_not_reached("Got finished event for unknown curl object"); +- +- if (!dkr_import_is_done(i)) +- return; +- +- dkr_import_report_progress(i, DKR_COPYING); +- +- r = dkr_import_make_local_copy(i); +- if (r < 0) +- goto finish; +- +- r = 0; +- +-finish: +- if (i->on_finished) +- i->on_finished(i, r, i->userdata); +- else +- sd_event_exit(i->event, r); +-} +- +-static int dkr_import_job_on_header(ImportJob *j, const char *header, size_t sz) { +- _cleanup_free_ char *registry = NULL; +- char *token; +- DkrImport *i; +- int r; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- +- r = curl_header_strdup(header, sz, HEADER_TOKEN, &token); +- if (r < 0) +- return log_oom(); +- if (r > 0) { +- free(i->response_token); +- i->response_token = token; +- return 0; +- } +- +- r = curl_header_strdup(header, sz, HEADER_REGISTRY, ®istry); +- if (r < 0) +- return log_oom(); +- if (r > 0) { +- char **l, **k; +- +- l = strv_split(registry, ","); +- if (!l) +- return log_oom(); +- +- STRV_FOREACH(k, l) { +- if (!hostname_is_valid(*k)) { +- log_error("Registry hostname is not valid."); +- strv_free(l); +- return -EBADMSG; +- } +- } +- +- strv_free(i->response_registries); +- i->response_registries = l; +- } +- +- return 0; +-} +- +-int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char *local, bool force_local) { +- const char *url; +- int r; +- +- assert(i); +- +- if (!dkr_name_is_valid(name)) +- return -EINVAL; +- +- if (tag && !dkr_tag_is_valid(tag)) +- return -EINVAL; +- +- if (local && !machine_name_is_valid(local)) +- return -EINVAL; +- +- if (i->images_job) +- return -EBUSY; +- +- if (!tag) +- tag = "latest"; +- +- r = free_and_strdup(&i->local, local); +- if (r < 0) +- return r; +- i->force_local = force_local; +- +- r = free_and_strdup(&i->name, name); +- if (r < 0) +- return r; +- r = free_and_strdup(&i->tag, tag); +- if (r < 0) +- return r; +- +- url = strjoina(i->index_url, "/v1/repositories/", name, "/images"); +- +- r = import_job_new(&i->images_job, url, i->glue, i); +- if (r < 0) +- return r; +- +- r = dkr_import_add_token(i, i->images_job); +- if (r < 0) +- return r; +- +- i->images_job->on_finished = dkr_import_job_on_finished; +- i->images_job->on_header = dkr_import_job_on_header; +- i->images_job->on_progress = dkr_import_job_on_progress; +- +- return import_job_begin(i->images_job); +-} +diff --git a/src/import/import-dkr.h b/src/import/import-dkr.h +deleted file mode 100644 +index 633c76796..000000000 +--- a/src/import/import-dkr.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 Lennart Poettering +- +- systemd is free software; you can redistribute it and/or modify it +- under the terms of the GNU Lesser General Public License as published by +- the Free Software Foundation; either version 2.1 of the License, or +- (at your option) any later version. +- +- systemd is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public License +- along with systemd; If not, see . +-***/ +- +-#pragma once +- +-#include "sd-event.h" +-#include "util.h" +- +-typedef struct DkrImport DkrImport; +- +-typedef void (*DkrImportFinished)(DkrImport *import, int error, void *userdata); +- +-int dkr_import_new(DkrImport **import, sd_event *event, const char *index_url, const char *image_root, DkrImportFinished on_finished, void *userdata); +-DkrImport* dkr_import_unref(DkrImport *import); +- +-DEFINE_TRIVIAL_CLEANUP_FUNC(DkrImport*, dkr_import_unref); +- +-int dkr_import_pull(DkrImport *import, const char *name, const char *tag, const char *local, bool force_local); +diff --git a/src/import/importd.c b/src/import/importd.c +index 1222bf3cd..9aaf991f8 100644 +--- a/src/import/importd.c ++++ b/src/import/importd.c +@@ -38,7 +38,6 @@ typedef struct Manager Manager; + typedef enum TransferType { + TRANSFER_TAR, + TRANSFER_RAW, +- TRANSFER_DKR, + _TRANSFER_TYPE_MAX, + _TRANSFER_TYPE_INVALID = -1, + } TransferType; +@@ -56,8 +55,6 @@ struct Transfer { + char *local; + bool force_local; + +- char *dkr_index_url; +- + pid_t pid; + + int log_fd; +@@ -91,7 +88,6 @@ struct Manager { + static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = { + [TRANSFER_TAR] = "tar", + [TRANSFER_RAW] = "raw", +- [TRANSFER_DKR] = "dkr", + }; + + DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType); +@@ -108,7 +104,6 @@ static Transfer *transfer_unref(Transfer *t) { + + free(t->remote); + free(t->local); +- free(t->dkr_index_url); + free(t->object_path); + + if (t->pid > 0) { +@@ -355,7 +350,6 @@ static int transfer_start(Transfer *t) { + "--verify", + NULL, /* verify argument */ + NULL, /* maybe --force */ +- NULL, /* maybe --dkr-index-url */ + NULL, /* the actual URL */ + NULL, /* remote */ + NULL, /* local */ +@@ -410,11 +404,6 @@ static int transfer_start(Transfer *t) { + if (t->force_local) + cmd[k++] = "--force"; + +- if (t->dkr_index_url) { +- cmd[k++] = "--dkr-index-url"; +- cmd[k++] = t->dkr_index_url; +- } +- + cmd[k++] = t->remote; + if (t->local) + cmd[k++] = t->local; +@@ -624,7 +613,7 @@ static int manager_new(Manager **ret) { + return 0; + } + +-static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_index_url, const char *remote) { ++static Transfer *manager_find(Manager *m, TransferType type, const char *remote) { + Transfer *t; + Iterator i; + +@@ -635,8 +624,7 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_ind + HASHMAP_FOREACH(t, m->transfers, i) { + + if (t->type == type && +- streq_ptr(t->remote, remote) && +- streq_ptr(t->dkr_index_url, dkr_index_url)) ++ streq_ptr(t->remote, remote)) + return t; + } + +@@ -689,7 +677,7 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda + + type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_TAR : TRANSFER_RAW; + +- if (manager_find(m, type, NULL, remote)) ++ if (manager_find(m, type, remote)) + return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote); + + r = transfer_new(m, &t); +@@ -719,98 +707,6 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda + return sd_bus_reply_method_return(msg, "uo", id, object); + } + +-static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) { +- _cleanup_(transfer_unrefp) Transfer *t = NULL; +- const char *index_url, *remote, *tag, *local, *verify, *object; +- Manager *m = userdata; +- ImportVerify v; +- int force, r; +- uint32_t id; +- +- assert(bus); +- assert(msg); +- assert(m); +- +- r = bus_verify_polkit_async( +- msg, +- CAP_SYS_ADMIN, +- "org.freedesktop.import1.pull", +- false, +- &m->polkit_registry, +- error); +- if (r < 0) +- return r; +- if (r == 0) +- return 1; /* Will call us back */ +- +- r = sd_bus_message_read(msg, "sssssb", &index_url, &remote, &tag, &local, &verify, &force); +- if (r < 0) +- return r; +- +- if (isempty(index_url)) +- index_url = DEFAULT_DKR_INDEX_URL; +- if (!index_url) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL must be specified."); +- if (!http_url_is_valid(index_url)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL %s is invalid", index_url); +- +- if (!dkr_name_is_valid(remote)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Remote name %s is not valid", remote); +- +- if (isempty(tag)) +- tag = "latest"; +- else if (!dkr_tag_is_valid(tag)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Tag %s is not valid", tag); +- +- if (isempty(local)) +- local = NULL; +- else if (!machine_name_is_valid(local)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); +- +- if (isempty(verify)) +- v = IMPORT_VERIFY_SIGNATURE; +- else +- v = import_verify_from_string(verify); +- if (v < 0) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify); +- +- if (v != IMPORT_VERIFY_NO) +- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "DKR does not support verification."); +- +- if (manager_find(m, TRANSFER_DKR, index_url, remote)) +- return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote); +- +- r = transfer_new(m, &t); +- if (r < 0) +- return r; +- +- t->type = TRANSFER_DKR; +- t->verify = v; +- t->force_local = force; +- +- t->dkr_index_url = strdup(index_url); +- if (!t->dkr_index_url) +- return -ENOMEM; +- +- t->remote = strjoin(remote, ":", tag, NULL); +- if (!t->remote) +- return -ENOMEM; +- +- t->local = strdup(local); +- if (!t->local) +- return -ENOMEM; +- +- r = transfer_start(t); +- if (r < 0) +- return r; +- +- object = t->object_path; +- id = t->id; +- t = NULL; +- +- return sd_bus_reply_method_return(msg, "uo", id, object); +-} +- + static int method_list_transfers(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; +@@ -956,7 +852,6 @@ static const sd_bus_vtable manager_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("PullDkr", "sssssb", "uo", method_pull_dkr, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListTransfers", NULL, "a(usssdo)", method_list_transfers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CancelTransfer", "u", NULL, method_cancel_transfer, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_SIGNAL("TransferNew", "uo", 0), +diff --git a/src/import/org.freedesktop.import1.conf b/src/import/org.freedesktop.import1.conf +index ae36af422..ed2539a03 100644 +--- a/src/import/org.freedesktop.import1.conf ++++ b/src/import/org.freedesktop.import1.conf +@@ -52,10 +52,6 @@ + send_interface="org.freedesktop.import1.Manager" + send_member="PullRaw"/> + +- +- + +diff --git a/src/import/pull.c b/src/import/pull.c +index ee3ff6803..9cb10880f 100644 +--- a/src/import/pull.c ++++ b/src/import/pull.c +@@ -28,13 +28,11 @@ + #include "machine-image.h" + #include "import-tar.h" + #include "import-raw.h" +-#include "import-dkr.h" + #include "import-util.h" + + static bool arg_force = false; + static const char *arg_image_root = "/var/lib/machines"; + static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; +-static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL; + + static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + log_notice("Transfer aborted."); +@@ -214,107 +212,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) { + return -r; + } + +-static void on_dkr_finished(DkrImport *import, int error, void *userdata) { +- sd_event *event = userdata; +- assert(import); +- +- if (error == 0) +- log_info("Operation completed successfully."); +- +- sd_event_exit(event, abs(error)); +-} +- +-static int pull_dkr(int argc, char *argv[], void *userdata) { +- _cleanup_(dkr_import_unrefp) DkrImport *import = NULL; +- _cleanup_event_unref_ sd_event *event = NULL; +- const char *name, *tag, *local; +- int r; +- +- if (!arg_dkr_index_url) { +- log_error("Please specify an index URL with --dkr-index-url="); +- return -EINVAL; +- } +- +- if (arg_verify != IMPORT_VERIFY_NO) { +- log_error("Imports from dkr do not support image verification, please pass --verify=no."); +- return -EINVAL; +- } +- +- tag = strchr(argv[1], ':'); +- if (tag) { +- name = strndupa(argv[1], tag - argv[1]); +- tag++; +- } else { +- name = argv[1]; +- tag = "latest"; +- } +- +- if (!dkr_name_is_valid(name)) { +- log_error("Remote name '%s' is not valid.", name); +- return -EINVAL; +- } +- +- if (!dkr_tag_is_valid(tag)) { +- log_error("Tag name '%s' is not valid.", tag); +- return -EINVAL; +- } +- +- if (argc >= 3) +- local = argv[2]; +- else { +- local = strchr(name, '/'); +- if (local) +- local++; +- else +- local = name; +- } +- +- if (isempty(local) || streq(local, "-")) +- local = NULL; +- +- if (local) { +- if (!machine_name_is_valid(local)) { +- log_error("Local image name '%s' is not valid.", local); +- return -EINVAL; +- } +- +- if (!arg_force) { +- r = image_find(local, NULL); +- if (r < 0) +- return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); +- else if (r > 0) { +- log_error_errno(EEXIST, "Image '%s' already exists.", local); +- return -EEXIST; +- } +- } +- +- log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local); +- } else +- log_info("Pulling '%s' with tag '%s'.", name, tag); +- +- r = sd_event_default(&event); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate event loop: %m"); +- +- assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0); +- sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL); +- sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL); +- +- r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate importer: %m"); +- +- r = dkr_import_pull(import, name, tag, local, arg_force); +- if (r < 0) +- return log_error_errno(r, "Failed to pull image: %m"); +- +- r = sd_event_loop(event); +- if (r < 0) +- return log_error_errno(r, "Failed to run event loop: %m"); +- +- log_info("Exiting."); +- return -r; +-} + + static int help(int argc, char *argv[], void *userdata) { + +@@ -326,11 +223,9 @@ static int help(int argc, char *argv[], void *userdata) { + " --verify= Verify downloaded image, one of: 'no',\n" + " 'checksum', 'signature'.\n" + " --image-root= Image root directory\n" +- " --dkr-index-url=URL Specify index URL to use for downloads\n\n" + "Commands:\n" + " tar URL [NAME] Download a TAR image\n" +- " raw URL [NAME] Download a RAW image\n" +- " dkr REMOTE [NAME] Download a DKR image\n", ++ " raw URL [NAME] Download a RAW image\n", + program_invocation_short_name); + + return 0; +@@ -341,7 +236,6 @@ static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + ARG_FORCE, +- ARG_DKR_INDEX_URL, + ARG_IMAGE_ROOT, + ARG_VERIFY, + }; +@@ -350,7 +244,6 @@ static int parse_argv(int argc, char *argv[]) { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "force", no_argument, NULL, ARG_FORCE }, +- { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL }, + { "image-root", required_argument, NULL, ARG_IMAGE_ROOT }, + { "verify", required_argument, NULL, ARG_VERIFY }, + {} +@@ -377,15 +270,6 @@ static int parse_argv(int argc, char *argv[]) { + arg_force = true; + break; + +- case ARG_DKR_INDEX_URL: +- if (!http_url_is_valid(optarg)) { +- log_error("Index URL is not valid: %s", optarg); +- return -EINVAL; +- } +- +- arg_dkr_index_url = optarg; +- break; +- + case ARG_IMAGE_ROOT: + arg_image_root = optarg; + break; +@@ -415,7 +299,6 @@ static int import_main(int argc, char *argv[]) { + { "help", VERB_ANY, VERB_ANY, 0, help }, + { "tar", 2, 3, 0, pull_tar }, + { "raw", 2, 3, 0, pull_raw }, +- { "dkr", 2, 3, 0, pull_dkr }, + {} + }; + +diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c +index ef1214a66..cfd3162fb 100644 +--- a/src/machine/machinectl.c ++++ b/src/machine/machinectl.c +@@ -77,7 +77,6 @@ static unsigned arg_lines = 10; + static OutputMode arg_output = OUTPUT_SHORT; + static bool arg_force = false; + static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; +-static const char* arg_dkr_index_url = NULL; + + static void pager_open_if_enabled(void) { + +@@ -1998,78 +1997,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) { + return pull_image_common(bus, m); + } + +-static int pull_dkr(int argc, char *argv[], void *userdata) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; +- const char *local, *remote, *tag; +- sd_bus *bus = userdata; +- int r; +- +- if (arg_verify != IMPORT_VERIFY_NO) { +- log_error("Imports from DKR do not support image verification, please pass --verify=no."); +- return -EINVAL; +- } +- +- remote = argv[1]; +- tag = strchr(remote, ':'); +- if (tag) { +- remote = strndupa(remote, tag - remote); +- tag++; +- } +- +- if (!dkr_name_is_valid(remote)) { +- log_error("DKR name '%s' is invalid.", remote); +- return -EINVAL; +- } +- if (tag && !dkr_tag_is_valid(tag)) { +- log_error("DKR tag '%s' is invalid.", remote); +- return -EINVAL; +- } +- +- if (argc >= 3) +- local = argv[2]; +- else { +- local = strchr(remote, '/'); +- if (local) +- local++; +- else +- local = remote; +- } +- +- if (isempty(local) || streq(local, "-")) +- local = NULL; +- +- if (local) { +- if (!machine_name_is_valid(local)) { +- log_error("Local name %s is not a suitable machine name.", local); +- return -EINVAL; +- } +- } +- +- r = sd_bus_message_new_method_call( +- bus, +- &m, +- "org.freedesktop.import1", +- "/org/freedesktop/import1", +- "org.freedesktop.import1.Manager", +- "PullDkr"); +- if (r < 0) +- return bus_log_create_error(r); +- +- r = sd_bus_message_append( +- m, +- "sssssb", +- arg_dkr_index_url, +- remote, +- tag, +- local, +- import_verify_to_string(arg_verify), +- arg_force); +- if (r < 0) +- return bus_log_create_error(r); +- +- return pull_image_common(bus, m); +-} +- + typedef struct TransferInfo { + uint32_t id; + const char *type; +@@ -2237,8 +2164,6 @@ static int help(int argc, char *argv[], void *userdata) { + " --verify=MODE Verification mode for downloaded images (no,\n" + " checksum, signature)\n" + " --force Download image even if already exists\n" +- " --dkr-index-url=URL Specify the index URL to use for DKR image\n" +- " downloads\n\n" + "Machine Commands:\n" + " list List running VMs and containers\n" + " status NAME... Show VM/container details\n" +@@ -2265,7 +2190,6 @@ static int help(int argc, char *argv[], void *userdata) { + "Image Transfer Commands:\n" + " pull-tar URL [NAME] Download a TAR container image\n" + " pull-raw URL [NAME] Download a RAW container or VM image\n" +- " pull-dkr REMOTE [NAME] Download a DKR container image\n" + " list-transfers Show list of downloads in progress\n" + " cancel-transfer Cancel a download\n" + , program_invocation_short_name); +@@ -2284,8 +2208,7 @@ static int parse_argv(int argc, char *argv[]) { + ARG_MKDIR, + ARG_NO_ASK_PASSWORD, + ARG_VERIFY, +- ARG_FORCE, +- ARG_DKR_INDEX_URL, ++ ARG_FORCE + }; + + static const struct option options[] = { +@@ -2308,7 +2231,6 @@ static int parse_argv(int argc, char *argv[]) { + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "verify", required_argument, NULL, ARG_VERIFY }, + { "force", no_argument, NULL, ARG_FORCE }, +- { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL }, + {} + }; + +@@ -2421,15 +2343,6 @@ static int parse_argv(int argc, char *argv[]) { + arg_force = true; + break; + +- case ARG_DKR_INDEX_URL: +- if (!http_url_is_valid(optarg)) { +- log_error("Index URL is invalid: %s", optarg); +- return -EINVAL; +- } +- +- arg_dkr_index_url = optarg; +- break; +- + case '?': + return -EINVAL; + +@@ -2467,7 +2380,6 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { + { "disable", 2, VERB_ANY, 0, enable_machine }, + { "pull-tar", 2, 3, 0, pull_tar }, + { "pull-raw", 2, 3, 0, pull_raw }, +- { "pull-dkr", 2, 3, 0, pull_dkr }, + { "list-transfers", VERB_ANY, 1, 0, list_transfers }, + { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer }, + {} +diff --git a/src/shared/import-util.c b/src/shared/import-util.c +index 660d92ac5..c0aba30a9 100644 +--- a/src/shared/import-util.c ++++ b/src/shared/import-util.c +@@ -149,34 +149,3 @@ int raw_strip_suffixes(const char *p, char **ret) { + + return 0; + } +- +-bool dkr_name_is_valid(const char *name) { +- const char *slash, *p; +- +- if (isempty(name)) +- return false; +- +- slash = strchr(name, '/'); +- if (!slash) +- return false; +- +- if (!filename_is_valid(slash + 1)) +- return false; +- +- p = strndupa(name, slash - name); +- if (!filename_is_valid(p)) +- return false; +- +- return true; +-} +- +-bool dkr_id_is_valid(const char *id) { +- +- if (!filename_is_valid(id)) +- return false; +- +- if (!in_charset(id, "0123456789abcdef")) +- return false; +- +- return true; +-} +diff --git a/src/shared/import-util.h b/src/shared/import-util.h +index ff155b0ff..22773c58e 100644 +--- a/src/shared/import-util.h ++++ b/src/shared/import-util.h +@@ -41,7 +41,3 @@ ImportVerify import_verify_from_string(const char *s) _pure_; + + int tar_strip_suffixes(const char *name, char **ret); + int raw_strip_suffixes(const char *name, char **ret); +- +-bool dkr_name_is_valid(const char *name); +-bool dkr_id_is_valid(const char *id); +-#define dkr_tag_is_valid(tag) filename_is_valid(tag) diff --git a/SOURCES/0325-import-add-support-for-gpg2-for-verifying-imported-i.patch b/SOURCES/0325-import-add-support-for-gpg2-for-verifying-imported-i.patch new file mode 100644 index 00000000..3d13383f --- /dev/null +++ b/SOURCES/0325-import-add-support-for-gpg2-for-verifying-imported-i.patch @@ -0,0 +1,88 @@ +From 1b7d1234cd22bb0fd2677d54dc670a6d2c6f8089 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Mar 2015 20:24:11 +0100 +Subject: [PATCH] import: add support for gpg2 for verifying imported images + +gpg2 insists on created a trust db even if we tun off all trust db +support. Hence create a temporary home where the trust db is placed, and +remove it after use. + +Cherry-picked from: 0acfdffe9417b4218e97b6d981c99a1a85e633c9 +Resolves: #1284974 +--- + src/import/import-common.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/src/import/import-common.c b/src/import/import-common.c +index 2acf380f9..f10a453ee 100644 +--- a/src/import/import-common.c ++++ b/src/import/import-common.c +@@ -281,8 +281,9 @@ int import_verify( + _cleanup_free_ char *fn = NULL; + _cleanup_close_ int sig_file = -1; + const char *p, *line; +- char sig_file_path[] = "/tmp/sigXXXXXX"; ++ char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX"; + _cleanup_sigkill_wait_ pid_t pid = 0; ++ bool gpg_home_created = false; + int r; + + assert(main_job); +@@ -347,6 +348,13 @@ int import_verify( + goto finish; + } + ++ if (!mkdtemp(gpg_home)) { ++ r = log_error_errno(errno, "Failed to create tempory home for gpg: %m"); ++ goto finish; ++ } ++ ++ gpg_home_created = true; ++ + pid = fork(); + if (pid < 0) + return log_error_errno(errno, "Failed to fork off gpg: %m"); +@@ -359,13 +367,14 @@ int import_verify( + "--no-auto-check-trustdb", + "--batch", + "--trust-model=always", +- NULL, /* keyring to use */ ++ NULL, /* --homedir= */ ++ NULL, /* --keyring= */ + NULL, /* --verify */ + NULL, /* signature file */ + NULL, /* dash */ + NULL /* trailing NULL */ + }; +- unsigned k = ELEMENTSOF(cmd) - 5; ++ unsigned k = ELEMENTSOF(cmd) - 6; + int null_fd; + + /* Child */ +@@ -398,6 +407,8 @@ int import_verify( + if (null_fd != STDOUT_FILENO) + null_fd = safe_close(null_fd); + ++ cmd[k++] = strjoina("--homedir=", gpg_home); ++ + /* We add the user keyring only to the command line + * arguments, if it's around since gpg fails + * otherwise. */ +@@ -415,6 +426,7 @@ int import_verify( + fd_cloexec(STDOUT_FILENO, false); + fd_cloexec(STDERR_FILENO, false); + ++ execvp("gpg2", (char * const *) cmd); + execvp("gpg", (char * const *) cmd); + log_error_errno(errno, "Failed to execute gpg: %m"); + _exit(EXIT_FAILURE); +@@ -446,6 +458,9 @@ finish: + if (sig_file >= 0) + unlink(sig_file_path); + ++ if (gpg_home_created) ++ rm_rf_dangerous(gpg_home, false, true, false); ++ + return r; + } + diff --git a/SOURCES/0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch b/SOURCES/0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch new file mode 100644 index 00000000..0ac243ee --- /dev/null +++ b/SOURCES/0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch @@ -0,0 +1,293 @@ +From 98e5c02b1602eaaac5c63045fa7a06e40249445e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 18 Feb 2015 23:32:55 +0100 +Subject: [PATCH] nspawn: when connected to pipes for stdin/stdout, pass them + as-is to PID 1 + +Previously we always invoked the container PID 1 on /dev/console of the +container. With this change we do so only if nspawn was invoked +interactively (i.e. its stdin/stdout was connected to a TTY). In all other +cases we directly pass through the fds unmodified. + +This has the benefit that nspawn can be added into shell pipelines. + +https://bugs.freedesktop.org/show_bug.cgi?id=87732 + +Cherry-picked from: 9c857b9d160c10b4454fc9f83442c1878343422f +Resolves: #1307080 +--- + src/machine/machinectl.c | 2 +- + src/nspawn/nspawn.c | 48 +++++++++++++++++-------------- + src/run/run.c | 2 +- + src/shared/ptyfwd.c | 75 ++++++++++++++++++++++++++++-------------------- + src/shared/ptyfwd.h | 2 +- + 5 files changed, 74 insertions(+), 55 deletions(-) + +diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c +index cfd3162fb..1a58aeaf1 100644 +--- a/src/machine/machinectl.c ++++ b/src/machine/machinectl.c +@@ -1427,7 +1427,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { + sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); + sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); + +- r = pty_forward_new(event, master, true, &forward); ++ r = pty_forward_new(event, master, true, false, &forward); + if (r < 0) + return log_error_errno(r, "Failed to create PTY forwarder: %m"); + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 78bd58483..a37b64094 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -3581,6 +3581,7 @@ int main(int argc, char *argv[]) { + int ret = EXIT_SUCCESS; + union in_addr_union exposed = {}; + _cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT; ++ bool interactive; + + log_parse_environment(); + log_open(); +@@ -3754,6 +3755,8 @@ int main(int argc, char *argv[]) { + goto finish; + } + ++ interactive = isatty(STDIN_FILENO) > 0 && isatty(STDOUT_FILENO) > 0; ++ + master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY); + if (master < 0) { + r = log_error_errno(errno, "Failed to acquire pseudo tty: %m"); +@@ -3766,15 +3769,15 @@ int main(int argc, char *argv[]) { + goto finish; + } + +- if (!arg_quiet) +- log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.", +- arg_machine, arg_image ?: arg_directory); +- + if (unlockpt(master) < 0) { + r = log_error_errno(errno, "Failed to unlock tty: %m"); + goto finish; + } + ++ if (!arg_quiet) ++ log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.", ++ arg_machine, arg_image ?: arg_directory); ++ + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1); + assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); +@@ -3860,9 +3863,6 @@ int main(int argc, char *argv[]) { + + master = safe_close(master); + +- close_nointr(STDIN_FILENO); +- close_nointr(STDOUT_FILENO); +- close_nointr(STDERR_FILENO); + + kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); + rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); +@@ -3870,21 +3870,27 @@ int main(int argc, char *argv[]) { + reset_all_signal_handlers(); + reset_signal_mask(); + +- r = open_terminal(console, O_RDWR); +- if (r != STDIN_FILENO) { +- if (r >= 0) { +- safe_close(r); +- r = -EINVAL; +- } ++ if (interactive) { ++ close_nointr(STDIN_FILENO); ++ close_nointr(STDOUT_FILENO); ++ close_nointr(STDERR_FILENO); + +- log_error_errno(r, "Failed to open console: %m"); +- _exit(EXIT_FAILURE); +- } ++ r = open_terminal(console, O_RDWR); ++ if (r != STDIN_FILENO) { ++ if (r >= 0) { ++ safe_close(r); ++ r = -EINVAL; ++ } + +- if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO || +- dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) { +- log_error_errno(errno, "Failed to duplicate console: %m"); +- _exit(EXIT_FAILURE); ++ log_error_errno(r, "Failed to open console: %m"); ++ _exit(EXIT_FAILURE); ++ } ++ ++ if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO || ++ dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) { ++ log_error_errno(errno, "Failed to duplicate console: %m"); ++ _exit(EXIT_FAILURE); ++ } + } + + if (setsid() < 0) { +@@ -4227,7 +4233,7 @@ int main(int argc, char *argv[]) { + + rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); + +- r = pty_forward_new(event, master, true, &forward); ++ r = pty_forward_new(event, master, true, !interactive, &forward); + if (r < 0) { + log_error_errno(r, "Failed to create PTY forwarder: %m"); + goto finish; +diff --git a/src/run/run.c b/src/run/run.c +index dd1338f3b..468034284 100644 +--- a/src/run/run.c ++++ b/src/run/run.c +@@ -780,7 +780,7 @@ static int start_transient_service( + if (!arg_quiet) + log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service); + +- r = pty_forward_new(event, master, false, &forward); ++ r = pty_forward_new(event, master, false, false, &forward); + if (r < 0) + return log_error_errno(r, "Failed to create PTY forwarder: %m"); + +diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c +index 88b3f4e3c..4402af123 100644 +--- a/src/shared/ptyfwd.c ++++ b/src/shared/ptyfwd.c +@@ -42,6 +42,8 @@ struct PTYForward { + struct termios saved_stdin_attr; + struct termios saved_stdout_attr; + ++ bool read_only:1; ++ + bool saved_stdin:1; + bool saved_stdout:1; + +@@ -298,7 +300,13 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo * + return 0; + } + +-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward **ret) { ++int pty_forward_new( ++ sd_event *event, ++ int master, ++ bool ignore_vhangup, ++ bool read_only, ++ PTYForward **ret) { ++ + _cleanup_(pty_forward_freep) PTYForward *f = NULL; + struct winsize ws; + int r; +@@ -307,6 +315,7 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + if (!f) + return -ENOMEM; + ++ f->read_only = read_only; + f->ignore_vhangup = ignore_vhangup; + + if (event) +@@ -317,13 +326,15 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + return r; + } + +- r = fd_nonblock(STDIN_FILENO, true); +- if (r < 0) +- return r; ++ if (!read_only) { ++ r = fd_nonblock(STDIN_FILENO, true); ++ if (r < 0) ++ return r; + +- r = fd_nonblock(STDOUT_FILENO, true); +- if (r < 0) +- return r; ++ r = fd_nonblock(STDOUT_FILENO, true); ++ if (r < 0) ++ return r; ++ } + + r = fd_nonblock(master, true); + if (r < 0) +@@ -334,36 +345,34 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0) + (void)ioctl(master, TIOCSWINSZ, &ws); + +- if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) { +- struct termios raw_stdin_attr; +- +- f->saved_stdin = true; ++ if (!read_only) { ++ if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) { ++ struct termios raw_stdin_attr; + +- raw_stdin_attr = f->saved_stdin_attr; +- cfmakeraw(&raw_stdin_attr); +- raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag; +- tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr); +- } ++ f->saved_stdin = true; + +- if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) { +- struct termios raw_stdout_attr; ++ raw_stdin_attr = f->saved_stdin_attr; ++ cfmakeraw(&raw_stdin_attr); ++ raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag; ++ tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr); ++ } + +- f->saved_stdout = true; ++ if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) { ++ struct termios raw_stdout_attr; + +- raw_stdout_attr = f->saved_stdout_attr; +- cfmakeraw(&raw_stdout_attr); +- raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag; +- raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag; +- tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr); +- } ++ f->saved_stdout = true; + +- r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f); +- if (r < 0) +- return r; ++ raw_stdout_attr = f->saved_stdout_attr; ++ cfmakeraw(&raw_stdout_attr); ++ raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag; ++ raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag; ++ tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr); ++ } + +- r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f); +- if (r < 0 && r != -EPERM) +- return r; ++ r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f); ++ if (r < 0 && r != -EPERM) ++ return r; ++ } + + r = sd_event_add_io(f->event, &f->stdout_event_source, STDOUT_FILENO, EPOLLOUT|EPOLLET, on_stdout_event, f); + if (r == -EPERM) +@@ -372,6 +381,10 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + else if (r < 0) + return r; + ++ r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f); ++ if (r < 0) ++ return r; ++ + r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f); + if (r < 0) + return r; +diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h +index d3e229bd7..6208a543d 100644 +--- a/src/shared/ptyfwd.h ++++ b/src/shared/ptyfwd.h +@@ -30,7 +30,7 @@ + + typedef struct PTYForward PTYForward; + +-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward **f); ++int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, bool read_only, PTYForward **f); + PTYForward *pty_forward_free(PTYForward *f); + + int pty_forward_get_last_char(PTYForward *f, char *ch); diff --git a/SOURCES/0327-mount-remove-obsolete-n.patch b/SOURCES/0327-mount-remove-obsolete-n.patch new file mode 100644 index 00000000..829dbc63 --- /dev/null +++ b/SOURCES/0327-mount-remove-obsolete-n.patch @@ -0,0 +1,55 @@ +From 9592604df60795ad8b58aa11311a26f267385bae Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 28 Jul 2015 11:31:45 +0200 +Subject: [PATCH] mount: remove obsolete -n + +It seems that systemd still uses legacy -n option. The option has been +originally designed to avoid write to /etc/mtab during boot when root +FS is not ready or read-only. + +This is not necessary for long time, because /etc/mtab is not a real +file (it's symlink) and write to the file is impossible. All utils +should be able to detect the symlink and ignore mtab. This concept is +supported for very long time before systemd. + +The userspase mount options are currently maintained by libmount +(mount(8) and mount.nfs) in /run/mount) which is tmpfs initialized +during early boot. + +(cherry picked from commit 6f20f850f79df365c2533195214127142013d317) +Resolves: #1339721 +--- + src/core/mount.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 23f63ce32..fe967bc03 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -881,8 +881,6 @@ static void mount_enter_unmounting(Mount *m) { + m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT; + + r = exec_command_set(m->control_command, "/bin/umount", m->where, NULL); +- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) +- r = exec_command_append(m->control_command, "-n", NULL); + if (r < 0) + goto fail; + +@@ -935,8 +933,6 @@ static void mount_enter_mounting(Mount *m) { + + r = exec_command_set(m->control_command, "/bin/mount", + m->parameters_fragment.what, m->where, NULL); +- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) +- r = exec_command_append(m->control_command, "-n", NULL); + if (r >= 0 && m->sloppy_options) + r = exec_command_append(m->control_command, "-s", NULL); + if (r >= 0 && m->parameters_fragment.fstype) +@@ -985,8 +981,6 @@ static void mount_enter_remounting(Mount *m) { + r = exec_command_set(m->control_command, "/bin/mount", + m->parameters_fragment.what, m->where, + "-o", o, NULL); +- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) +- r = exec_command_append(m->control_command, "-n", NULL); + if (r >= 0 && m->sloppy_options) + r = exec_command_append(m->control_command, "-s", NULL); + if (r >= 0 && m->parameters_fragment.fstype) diff --git a/SOURCES/0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch b/SOURCES/0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch new file mode 100644 index 00000000..d00d16d5 --- /dev/null +++ b/SOURCES/0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch @@ -0,0 +1,244 @@ +From a7ec486dede56ab2ec28132133becf11e5685884 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 16 May 2016 17:24:51 +0200 +Subject: [PATCH] core: don't log job status message in case job was + effectively NOP (#3199) + +We currently generate log message about unit being started even when +unit was started already and job didn't do anything. This is because job +was requested explicitly and hence became anchor job of the transaction +thus we could not eliminate it. That is fine but, let's not pollute +journal with useless log messages. + +$ systemctl start systemd-resolved +$ systemctl start systemd-resolved +$ systemctl start systemd-resolved + +Current state: +$ journalctl -u systemd-resolved | grep Started + +May 05 15:31:42 rawhide systemd[1]: Started Network Name Resolution. +May 05 15:31:59 rawhide systemd[1]: Started Network Name Resolution. +May 05 15:32:01 rawhide systemd[1]: Started Network Name Resolution. + +After patch applied: +$ journalctl -u systemd-resolved | grep Started + +May 05 16:42:12 rawhide systemd[1]: Started Network Name Resolution. + +Fixes #1723 + +Cherry-picked from: 833f92ad39beca0e954e91e5764ffc83f8d0c1cf +Resolves: #1280014 +--- + src/core/dbus-job.c | 2 +- + src/core/job.c | 33 ++++++++++++++++++--------------- + src/core/job.h | 2 +- + src/core/manager.c | 2 +- + src/core/transaction.c | 2 +- + src/core/unit.c | 12 ++++++------ + 6 files changed, 28 insertions(+), 25 deletions(-) + +diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c +index 8b5ea2566..7ce5d5772 100644 +--- a/src/core/dbus-job.c ++++ b/src/core/dbus-job.c +@@ -84,7 +84,7 @@ int bus_job_method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata, + if (r < 0) + return r; + +- job_finish_and_invalidate(j, JOB_CANCELED, true); ++ job_finish_and_invalidate(j, JOB_CANCELED, true, false); + + return sd_bus_reply_method_return(message, NULL); + } +diff --git a/src/core/job.c b/src/core/job.c +index 7416386a1..c2876dec1 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -190,7 +190,7 @@ Job* job_install(Job *j) { + + if (uj) { + if (job_type_is_conflicting(uj->type, j->type)) +- job_finish_and_invalidate(uj, JOB_CANCELED, false); ++ job_finish_and_invalidate(uj, JOB_CANCELED, false, false); + else { + /* not conflicting, i.e. mergeable */ + +@@ -571,19 +571,19 @@ int job_run_and_invalidate(Job *j) { + j = manager_get_job(m, id); + if (j) { + if (r == -EALREADY) +- r = job_finish_and_invalidate(j, JOB_DONE, true); ++ r = job_finish_and_invalidate(j, JOB_DONE, true, true); + else if (r == -EBADR) +- r = job_finish_and_invalidate(j, JOB_SKIPPED, true); ++ r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false); + else if (r == -ENOEXEC) +- r = job_finish_and_invalidate(j, JOB_INVALID, true); ++ r = job_finish_and_invalidate(j, JOB_INVALID, true, false); + else if (r == -EPROTO) +- r = job_finish_and_invalidate(j, JOB_ASSERT, true); ++ r = job_finish_and_invalidate(j, JOB_ASSERT, true, false); + else if (r == -ENOTSUP) +- r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true); ++ r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false); + else if (r == -EAGAIN) + job_set_state(j, JOB_WAITING); + else if (r < 0) +- r = job_finish_and_invalidate(j, JOB_FAILED, true); ++ r = job_finish_and_invalidate(j, JOB_FAILED, true, false); + } + + return r; +@@ -792,7 +792,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { + NULL); + } + +-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { ++int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) { + Unit *u; + Unit *other; + JobType t; +@@ -810,8 +810,11 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { + log_unit_debug(u->id, "Job %s/%s finished, result=%s", + u->id, job_type_to_string(t), job_result_to_string(result)); + +- job_print_status_message(u, t, result); +- job_log_status_message(u, t, result); ++ /* If this job did nothing to respective unit we don't log the status message */ ++ if (!already) { ++ job_print_status_message(u, t, result); ++ job_log_status_message(u, t, result); ++ } + + job_add_to_dbus_queue(j); + +@@ -842,20 +845,20 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + + SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) + if (other->job && + !other->job->override && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + + } else if (t == JOB_STOP) { + +@@ -863,7 +866,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + } + } + +@@ -911,7 +914,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user + log_unit_warning(j->unit->id, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type)); + + u = j->unit; +- job_finish_and_invalidate(j, JOB_TIMEOUT, true); ++ job_finish_and_invalidate(j, JOB_TIMEOUT, true, false); + + failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg); + +diff --git a/src/core/job.h b/src/core/job.h +index d967b68a3..e4191ee77 100644 +--- a/src/core/job.h ++++ b/src/core/job.h +@@ -220,7 +220,7 @@ void job_add_to_dbus_queue(Job *j); + int job_start_timer(Job *j); + + int job_run_and_invalidate(Job *j); +-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive); ++int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already); + + char *job_dbus_path(Job *j); + +diff --git a/src/core/manager.c b/src/core/manager.c +index a1504bf17..ee456fb79 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1426,7 +1426,7 @@ void manager_clear_jobs(Manager *m) { + + while ((j = hashmap_first(m->jobs))) + /* No need to recurse. We're cancelling all jobs. */ +- job_finish_and_invalidate(j, JOB_CANCELED, false); ++ job_finish_and_invalidate(j, JOB_CANCELED, false, false); + } + + static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) { +diff --git a/src/core/transaction.c b/src/core/transaction.c +index b0b3d6bd6..aed64fa41 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -592,7 +592,7 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { + /* Not invalidating recursively. Avoids triggering + * OnFailure= actions of dependent jobs. Also avoids + * invalidating our iterator. */ +- job_finish_and_invalidate(j, JOB_CANCELED, false); ++ job_finish_and_invalidate(j, JOB_CANCELED, false, false); + } + } + +diff --git a/src/core/unit.c b/src/core/unit.c +index db5aa987e..d6ead7d67 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -1851,12 +1851,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + case JOB_VERIFY_ACTIVE: + + if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) +- job_finish_and_invalidate(u->job, JOB_DONE, true); ++ job_finish_and_invalidate(u->job, JOB_DONE, true, false); + else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) { + unexpected = true; + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) +- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); ++ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false); + } + + break; +@@ -1866,12 +1866,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + + if (u->job->state == JOB_RUNNING) { + if (ns == UNIT_ACTIVE) +- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true); ++ job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false); + else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) { + unexpected = true; + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) +- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); ++ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false); + } + } + +@@ -1882,10 +1882,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + case JOB_TRY_RESTART: + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) +- job_finish_and_invalidate(u->job, JOB_DONE, true); ++ job_finish_and_invalidate(u->job, JOB_DONE, true, false); + else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { + unexpected = true; +- job_finish_and_invalidate(u->job, JOB_FAILED, true); ++ job_finish_and_invalidate(u->job, JOB_FAILED, true, false); + } + + break; diff --git a/SOURCES/0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch b/SOURCES/0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch new file mode 100644 index 00000000..71272111 --- /dev/null +++ b/SOURCES/0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch @@ -0,0 +1,489 @@ +From 92b12c7dc013c95bd0d35bae99ff6df023ce0e1f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 4 May 2016 20:43:23 +0200 +Subject: [PATCH] core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent + notification + +dbus-daemon currently uses a backlog of 30 on its D-bus system bus socket. On +overloaded systems this means that only 30 connections may be queued without +dbus-daemon processing them before further connection attempts fail. Our +cgroups-agent binary so far used D-Bus for its messaging, and hitting this +limit hence may result in us losing cgroup empty messages. + +This patch adds a seperate cgroup agent socket of type AF_UNIX/SOCK_DGRAM. +Since sockets of these types need no connection set up, no listen() backlog +applies. Our cgroup-agent binary will hence simply block as long as it can't +enqueue its datagram message, so that we won't lose cgroup empty messages as +likely anymore. + +This also rearranges the ordering of the processing of SIGCHLD signals, service +notification messages (sd_notify()...) and the two types of cgroup +notifications (inotify for the unified hierarchy support, and agent for the +classic hierarchy support). We now always process events for these in the +following order: + + 1. service notification messages (SD_EVENT_PRIORITY_NORMAL-7) + 2. SIGCHLD signals (SD_EVENT_PRIORITY_NORMAL-6) + 3. cgroup inotify and cgroup agent (SD_EVENT_PRIORITY_NORMAL-5) + +This is because when receiving SIGCHLD we invalidate PID information, which we +need to process the service notification messages which are bound to PIDs. +Hence the order between the first two items. And we want to process SIGCHLD +metadata to detect whether a service is gone, before using cgroup +notifications, to decide when a service is gone, since the former carries more +useful metadata. + +Related to this: +https://bugs.freedesktop.org/show_bug.cgi?id=95264 +https://github.com/systemd/systemd/issues/1961 + +Cherry-picked from: d8fdc62037b5b0a9fd603ad5efd6b49f956f86b5 +Resolves: #1305608 +--- + src/cgroups-agent/cgroups-agent.c | 48 ++++++------ + src/core/cgroup.c | 2 + + src/core/dbus.c | 56 +++++++------- + src/core/dbus.h | 2 + + src/core/manager.c | 149 ++++++++++++++++++++++++++++++++++++-- + src/core/manager.h | 3 + + 6 files changed, 198 insertions(+), 62 deletions(-) + +diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c +index 529e84303..2fe65830e 100644 +--- a/src/cgroups-agent/cgroups-agent.c ++++ b/src/cgroups-agent/cgroups-agent.c +@@ -1,5 +1,3 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- + /*** + This file is part of systemd. + +@@ -20,14 +18,21 @@ + ***/ + + #include ++#include + +-#include "sd-bus.h" + #include "log.h" +-#include "bus-util.h" ++#include "socket-util.h" + + int main(int argc, char *argv[]) { +- _cleanup_bus_close_unref_ sd_bus *bus = NULL; +- int r; ++ ++ static const union sockaddr_union sa = { ++ .un.sun_family = AF_UNIX, ++ .un.sun_path = "/run/systemd/cgroups-agent", ++ }; ++ ++ _cleanup_close_ int fd = -1; ++ ssize_t n; ++ size_t l; + + if (argc != 2) { + log_error("Incorrect number of arguments."); +@@ -38,27 +43,22 @@ int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + +- /* We send this event to the private D-Bus socket and then the +- * system instance will forward this to the system bus. We do +- * this to avoid an activation loop when we start dbus when we +- * are called when the dbus service is shut down. */ +- +- r = bus_open_system_systemd(&bus); +- if (r < 0) { +- /* If we couldn't connect we assume this was triggered +- * while systemd got restarted/transitioned from +- * initrd to the system, so let's ignore this */ +- log_debug_errno(r, "Failed to get D-Bus connection: %m"); ++ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); ++ if (fd < 0) { ++ log_debug_errno(errno, "Failed to allocate socket: %m"); ++ return EXIT_FAILURE; ++ } ++ ++ l = strlen(argv[1]); ++ ++ n = sendto(fd, argv[1], l, 0, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); ++ if (n < 0) { ++ log_debug_errno(errno, "Failed to send cgroups agent message: %m"); + return EXIT_FAILURE; + } + +- r = sd_bus_emit_signal(bus, +- "/org/freedesktop/systemd1/agent", +- "org.freedesktop.systemd1.Agent", +- "Released", +- "s", argv[1]); +- if (r < 0) { +- log_debug_errno(r, "Failed to send signal message on private connection: %m"); ++ if ((size_t) n != l) { ++ log_debug("Datagram size mismatch"); + return EXIT_FAILURE; + } + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 10fdcc998..b7f08fb42 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -1028,6 +1028,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { + assert(m); + assert(cgroup); + ++ log_debug("Got cgroup empty notification for: %s", cgroup); ++ + u = manager_get_unit_by_cgroup(m, cgroup); + if (u) { + r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true); +diff --git a/src/core/dbus.c b/src/core/dbus.c +index 85b517486..29524d49a 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -72,12 +72,37 @@ int bus_send_queued_message(Manager *m) { + return 0; + } + ++int bus_forward_agent_released(Manager *m, const char *path) { ++ int r; ++ ++ assert(m); ++ assert(path); ++ ++ if (!m->running_as == SYSTEMD_SYSTEM) ++ return 0; ++ ++ if (!m->system_bus) ++ return 0; ++ ++ /* If we are running a system instance we forward the agent message on the system bus, so that the user ++ * instances get notified about this, too */ ++ ++ r = sd_bus_emit_signal(m->system_bus, ++ "/org/freedesktop/systemd1/agent", ++ "org.freedesktop.systemd1.Agent", ++ "Released", ++ "s", path); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to propagate agent release message: %m"); ++ ++ return 1; ++} ++ + static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *cgroup; + int r; + +- assert(bus); + assert(message); + assert(m); + +@@ -88,16 +113,6 @@ static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *use + } + + manager_notify_cgroup_empty(m, cgroup); +- +- if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) { +- /* If we are running as system manager, forward the +- * message to the system bus */ +- +- r = sd_bus_send(m->system_bus, message, NULL); +- if (r < 0) +- log_warning_errno(r, "Failed to forward Released message: %m"); +- } +- + return 0; + } + +@@ -679,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void + return 0; + } + +- if (m->running_as == SYSTEMD_SYSTEM) { +- /* When we run as system instance we get the Released +- * signal via a direct connection */ +- +- r = sd_bus_add_match( +- bus, +- NULL, +- "type='signal'," +- "interface='org.freedesktop.systemd1.Agent'," +- "member='Released'," +- "path='/org/freedesktop/systemd1/agent'", +- signal_agent_released, m); +- +- if (r < 0) { +- log_warning_errno(r, "Failed to register Released match on new connection bus: %m"); +- return 0; +- } +- } +- + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return 0; +diff --git a/src/core/dbus.h b/src/core/dbus.h +index d04f5326c..c27d136e3 100644 +--- a/src/core/dbus.h ++++ b/src/core/dbus.h +@@ -40,3 +40,5 @@ int bus_verify_manage_unit_async(Manager *m, sd_bus_message *call, sd_bus_error + int bus_verify_manage_unit_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error); + int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error); + int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error); ++ ++int bus_forward_agent_released(Manager *m, const char *path); +diff --git a/src/core/manager.c b/src/core/manager.c +index ee456fb79..370c8cbbe 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -83,8 +83,10 @@ + #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) + #define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3) + #define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3 ++#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024) + + static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); ++static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +@@ -456,11 +458,11 @@ static int manager_setup_signals(Manager *m) { + if (r < 0) + return r; + +- /* Process signals a bit earlier than the rest of things, but +- * later than notify_fd processing, so that the notify +- * processing can still figure out to which process/service a +- * message belongs, before we reap the process. */ +- r = sd_event_source_set_priority(m->signal_event_source, -5); ++ /* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the ++ * notify processing can still figure out to which process/service a message belongs, before we reap the ++ * process. Also, process this before handling cgroup notifications, so that we always collect child exit ++ * status information before detecting that there's no process in a cgroup. */ ++ r = sd_event_source_set_priority(m->signal_event_source, -6); + if (r < 0) + return r; + +@@ -541,7 +543,7 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) { + + m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; + +- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1; ++ m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1; + m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ + + m->ask_password_inotify_fd = -1; +@@ -689,8 +691,8 @@ static int manager_setup_notify(Manager *m) { + if (r < 0) + return log_error_errno(r, "Failed to allocate notify event source: %m"); + +- /* Process signals a bit earlier than SIGCHLD, so that we can +- * still identify to which service an exit message belongs */ ++ /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which ++ * service an exit message belongs. */ + r = sd_event_source_set_priority(m->notify_event_source, -7); + if (r < 0) + return log_error_errno(r, "Failed to set priority of notify event source: %m"); +@@ -699,6 +701,77 @@ static int manager_setup_notify(Manager *m) { + return 0; + } + ++static int manager_setup_cgroups_agent(Manager *m) { ++ ++ static const union sockaddr_union sa = { ++ .un.sun_family = AF_UNIX, ++ .un.sun_path = "/run/systemd/cgroups-agent", ++ }; ++ int r; ++ ++ /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering ++ * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and ++ * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on ++ * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number ++ * of D-Bus connections may be queued until the kernel will start dropping further incoming connections, ++ * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX ++ * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and ++ * we thus won't lose messages. ++ * ++ * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen ++ * to it. The system instance hence listens on this special socket, but the user instances listen on the system ++ * bus for these messages. */ ++ ++ if (m->test_run) ++ return 0; ++ ++ if (!m->running_as == SYSTEMD_SYSTEM) ++ return 0; ++ ++ if (m->cgroups_agent_fd < 0) { ++ _cleanup_close_ int fd = -1; ++ ++ /* First free all secondary fields */ ++ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); ++ ++ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); ++ if (fd < 0) ++ return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m"); ++ ++ fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE); ++ ++ (void) unlink(sa.un.sun_path); ++ ++ /* Only allow root to connect to this socket */ ++ RUN_WITH_UMASK(0077) ++ r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); ++ if (r < 0) ++ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); ++ ++ m->cgroups_agent_fd = fd; ++ fd = -1; ++ } ++ ++ if (!m->cgroups_agent_event_source) { ++ r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m); ++ if (r < 0) ++ return log_error_errno(r, "Failed to allocate cgroups agent event source: %m"); ++ ++ /* Process cgroups notifications early, but after having processed service notification messages or ++ * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification, ++ * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of ++ * cgroup inotify for the unified cgroup stuff. */ ++ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5); ++ if (r < 0) ++ return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m"); ++ ++ (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent"); ++ } ++ ++ return 0; ++} ++ ++ + static int manager_setup_kdbus(Manager *m) { + #ifdef ENABLE_KDBUS + _cleanup_free_ char *p = NULL; +@@ -912,6 +985,7 @@ Manager* manager_free(Manager *m) { + + sd_event_source_unref(m->signal_event_source); + sd_event_source_unref(m->notify_event_source); ++ sd_event_source_unref(m->cgroups_agent_event_source); + sd_event_source_unref(m->time_change_event_source); + sd_event_source_unref(m->jobs_in_progress_event_source); + sd_event_source_unref(m->idle_pipe_event_source); +@@ -919,6 +993,7 @@ Manager* manager_free(Manager *m) { + + safe_close(m->signal_fd); + safe_close(m->notify_fd); ++ safe_close(m->cgroups_agent_fd); + safe_close(m->time_change_fd); + safe_close(m->kdbus_fd); + +@@ -1167,6 +1242,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + if (q < 0 && r == 0) + r = q; + ++ q = manager_setup_cgroups_agent(m); ++ if (q < 0 && r == 0) ++ r = q; ++ + /* We might have deserialized the kdbus control fd, but if we + * didn't, then let's create the bus now. */ + manager_setup_kdbus(m); +@@ -1492,6 +1571,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { + return n; + } + ++static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++ Manager *m = userdata; ++ char buf[PATH_MAX+1]; ++ ssize_t n; ++ ++ n = recv(fd, buf, sizeof(buf), 0); ++ if (n < 0) ++ return log_error_errno(errno, "Failed to read cgroups agent message: %m"); ++ if (n == 0) { ++ log_error("Got zero-length cgroups agent message, ignoring."); ++ return 0; ++ } ++ if ((size_t) n >= sizeof(buf)) { ++ log_error("Got overly long cgroups agent message, ignoring."); ++ return 0; ++ } ++ ++ if (memchr(buf, 0, n)) { ++ log_error("Got cgroups agent message with embedded NUL byte, ignoring."); ++ return 0; ++ } ++ buf[n] = 0; ++ ++ manager_notify_cgroup_empty(m, buf); ++ bus_forward_agent_released(m, buf); ++ ++ return 0; ++} ++ + static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) { + _cleanup_strv_free_ char **tags = NULL; + +@@ -2304,6 +2412,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { + fprintf(f, "notify-socket=%s\n", m->notify_socket); + } + ++ if (m->cgroups_agent_fd >= 0) { ++ int copy; ++ ++ copy = fdset_put_dup(fds, m->cgroups_agent_fd); ++ if (copy < 0) ++ return copy; ++ ++ fprintf(f, "cgroups-agent-fd=%i\n", copy); ++ } ++ + if (m->kdbus_fd >= 0) { + int copy; + +@@ -2473,6 +2591,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + free(m->notify_socket); + m->notify_socket = n; + ++ } else if (startswith(l, "cgroups-agent-fd=")) { ++ int fd; ++ ++ if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) ++ log_debug("Failed to parse cgroups agent fd: %s", l + 10); ++ else { ++ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); ++ safe_close(m->cgroups_agent_fd); ++ m->cgroups_agent_fd = fdset_remove(fds, fd); ++ } ++ + } else if (startswith(l, "kdbus-fd=")) { + int fd; + +@@ -2599,6 +2728,10 @@ int manager_reload(Manager *m) { + if (q < 0 && r >= 0) + r = q; + ++ q = manager_setup_cgroups_agent(m); ++ if (q < 0 && r >= 0) ++ r = q; ++ + /* Third, fire things up! */ + q = manager_coldplug(m); + if (q < 0 && r >= 0) +diff --git a/src/core/manager.h b/src/core/manager.h +index d3971f168..3e855db46 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -137,6 +137,9 @@ struct Manager { + int notify_fd; + sd_event_source *notify_event_source; + ++ int cgroups_agent_fd; ++ sd_event_source *cgroups_agent_event_source; ++ + int signal_fd; + sd_event_source *signal_event_source; + diff --git a/SOURCES/0330-logind-process-session-inhibitor-fds-at-higher-prior.patch b/SOURCES/0330-logind-process-session-inhibitor-fds-at-higher-prior.patch new file mode 100644 index 00000000..c79ed3f6 --- /dev/null +++ b/SOURCES/0330-logind-process-session-inhibitor-fds-at-higher-prior.patch @@ -0,0 +1,59 @@ +From caca204d23babbdb0c688f543f3ee8d66a1a2001 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 4 May 2016 19:01:56 +0200 +Subject: [PATCH] logind: process session/inhibitor fds at higher priority + +Let's make sure we process session and inhibitor pipe fds (that signal +sessions/inhibtors going away) at a higher priority +than new bus calls that might create new sessions or inhibitors. This helps +ensuring that the number of open sessions stays minimal. + +Cherry-picked from: e11544a8305ab9dea097c74bb16e296150c9cc10 +Resolves: #1305608 +--- + src/login/logind-inhibit.c | 2 +- + src/login/logind-session.c | 4 +++- + src/login/logind.c | 2 +- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c +index 84fee0e77..bf96898f2 100644 +--- a/src/login/logind-inhibit.c ++++ b/src/login/logind-inhibit.c +@@ -303,7 +303,7 @@ int inhibitor_create_fifo(Inhibitor *i) { + if (r < 0) + return r; + +- r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE); ++ r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10); + if (r < 0) + return r; + } +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index dc24539f1..59f5a7ad5 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -905,7 +905,9 @@ int session_create_fifo(Session *s) { + if (r < 0) + return r; + +- r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); ++ /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new ++ * sessions). */ ++ r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10); + if (r < 0) + return r; + } +diff --git a/src/login/logind.c b/src/login/logind.c +index 3afbf34a1..e8d0669bb 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -685,7 +685,7 @@ static int manager_connect_bus(Manager *m) { + if (r < 0) + return log_error_errno(r, "Failed to register name: %m"); + +- r = sd_bus_attach_event(m->bus, m->event, 0); ++ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) + return log_error_errno(r, "Failed to attach bus to event loop: %m"); + diff --git a/SOURCES/0331-Teach-bus_append_unit_property_assignment-about-Dele.patch b/SOURCES/0331-Teach-bus_append_unit_property_assignment-about-Dele.patch new file mode 100644 index 00000000..c2794274 --- /dev/null +++ b/SOURCES/0331-Teach-bus_append_unit_property_assignment-about-Dele.patch @@ -0,0 +1,27 @@ +From f44296a5324dc84ff1b2a82bd1dd2d47160762b5 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 23 May 2016 14:51:12 +0200 +Subject: [PATCH] Teach bus_append_unit_property_assignment() about 'Delegate' + property + +"Cherry-picked" from ea1a971646d31b990190f473c5c7e3562f36d3c9. + +Resolves: #1337922 +--- + src/libsystemd/sd-bus/bus-util.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 3a918361b..9d70798cd 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1388,7 +1388,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + + if (STR_IN_SET(field, + "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", +- "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies")) { ++ "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", ++ "Delegate")) { + + r = parse_boolean(eq); + if (r < 0) { diff --git a/SOURCES/0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch b/SOURCES/0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch new file mode 100644 index 00000000..d7f683f1 --- /dev/null +++ b/SOURCES/0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch @@ -0,0 +1,47 @@ +From 164a98ea6b24fea3433516dcc0df496929674cdd Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 7 Jun 2016 12:43:38 +0200 +Subject: [PATCH] sd-netlink: fix deep recursion in message destruction + +On larger systems we might very well see messages with thousands of parts. +When we free them, we must avoid recursing into each part, otherwise we +very likely get stack overflows. + +Fix sd_netlink_message_unref() to use an iterative approach rather than +recursion (also avoid tail-recursion in case it is not optimized by the +compiler). + +(cherry picked from commit 82e4eda664d40ef60829e27d84b1610c2f4070cd) +Resolves: #1330593 +--- + src/libsystemd/sd-rtnl/rtnl-message.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c +index 276591f31..9276bbdeb 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-message.c ++++ b/src/libsystemd/sd-rtnl/rtnl-message.c +@@ -584,7 +584,9 @@ sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) { + } + + sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) { +- if (m && REFCNT_DEC(m->n_ref) == 0) { ++ sd_rtnl_message *t; ++ ++ while (m && REFCNT_DEC(m->n_ref) == 0) { + unsigned i; + + free(m->hdr); +@@ -592,9 +594,9 @@ sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) { + for (i = 0; i <= m->n_containers; i++) + free(m->rta_offset_tb[i]); + +- sd_rtnl_message_unref(m->next); +- +- free(m); ++ t = m; ++ m = m->next; ++ free(t); + } + + return NULL; diff --git a/SOURCES/0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch b/SOURCES/0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch new file mode 100644 index 00000000..0c698f50 --- /dev/null +++ b/SOURCES/0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch @@ -0,0 +1,281 @@ +From afa96dafde9d50f2b53ccf8136ead9ed79544877 Mon Sep 17 00:00:00 2001 +From: Shawn Landden +Date: Tue, 10 Mar 2015 04:41:59 -0700 +Subject: [PATCH] add REMOTE_ADDR and REMOTE_PORT for Accept=yes + +Cherry-picked from: 3b1c524154c876aecebc98787975cc2943100210 +Resolves: #1341154 +--- + TODO | 2 - + man/systemd.socket.xml | 7 ++- + src/core/service.c | 42 +++++++++++++++++- + src/libsystemd/sd-resolve/test-resolve.c | 2 +- + src/shared/socket-util.c | 76 +++++++++++++++++++++++--------- + src/shared/socket-util.h | 4 +- + src/timesync/timesyncd-server.h | 2 +- + 7 files changed, 107 insertions(+), 28 deletions(-) + +diff --git a/TODO b/TODO +index d96d2bf0e..498d82c21 100644 +--- a/TODO ++++ b/TODO +@@ -185,8 +185,6 @@ Features: + * as soon as we have kdbus, and sender timestamps, revisit coalescing multiple parallel daemon reloads: + http://lists.freedesktop.org/archives/systemd-devel/2014-December/025862.html + +-* set $REMOTE_IP (or $REMOTE_ADDR/$REMOTE_PORT) environment variable when doing per-connection socket activation. use format introduced by xinetd or CGI for this +- + * the install state probably shouldn't get confused by generated units, think dbus1/kdbus compat! + + * in systemctl list-unit-files: show the install value the presets would suggest for a service in a third column +diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml +index 2f541937f..350a95648 100644 +--- a/man/systemd.socket.xml ++++ b/man/systemd.socket.xml +@@ -357,7 +357,12 @@ + daemons designed for usage with + inetd8 + to work unmodified with systemd socket +- activation. ++ activation. ++ ++ For IPv4 and IPv6 connections the REMOTE_ADDR ++ environment variable will contain the remote IP, and REMOTE_PORT ++ will contain the remote port. This is the same as the format used by CGI. ++ For SOCK_RAW the port is the IP protocol. + + + +diff --git a/src/core/service.c b/src/core/service.c +index ae5e61000..c76713b1c 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -1094,7 +1094,7 @@ static int service_spawn( + if (r < 0) + goto fail; + +- our_env = new0(char*, 4); ++ our_env = new0(char*, 6); + if (!our_env) { + r = -ENOMEM; + goto fail; +@@ -1118,6 +1118,46 @@ static int service_spawn( + goto fail; + } + ++ if (UNIT_DEREF(s->accept_socket)) { ++ union sockaddr_union sa; ++ socklen_t salen = sizeof(sa); ++ ++ r = getpeername(s->socket_fd, &sa.sa, &salen); ++ if (r < 0) { ++ r = -errno; ++ goto fail; ++ } ++ ++ if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) { ++ _cleanup_free_ char *addr = NULL; ++ char *t; ++ int port; ++ ++ r = sockaddr_pretty(&sa.sa, salen, true, false, &addr); ++ if (r < 0) ++ goto fail; ++ ++ t = strappend("REMOTE_ADDR=", addr); ++ if (!t) { ++ r = -ENOMEM; ++ goto fail; ++ } ++ our_env[n_env++] = t; ++ ++ port = sockaddr_port(&sa.sa); ++ if (port < 0) { ++ r = port; ++ goto fail; ++ } ++ ++ if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) { ++ r = -ENOMEM; ++ goto fail; ++ } ++ our_env[n_env++] = t; ++ } ++ } ++ + final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL); + if (!final_env) { + r = -ENOMEM; +diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c +index d08e1b5a0..a14b6de19 100644 +--- a/src/libsystemd/sd-resolve/test-resolve.c ++++ b/src/libsystemd/sd-resolve/test-resolve.c +@@ -49,7 +49,7 @@ static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrin + for (i = ai; i; i = i->ai_next) { + _cleanup_free_ char *addr = NULL; + +- assert_se(sockaddr_pretty(i->ai_addr, i->ai_addrlen, false, &addr) == 0); ++ assert_se(sockaddr_pretty(i->ai_addr, i->ai_addrlen, false, true, &addr) == 0); + puts(addr); + } + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index 407d0afee..a21251014 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -302,7 +302,7 @@ int socket_address_print(const SocketAddress *a, char **ret) { + return 0; + } + +- return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret); ++ return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret); + } + + bool socket_address_can_accept(const SocketAddress *a) { +@@ -471,7 +471,20 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { + return socket_address_equal(a, &b); + } + +-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) { ++int sockaddr_port(const struct sockaddr *_sa) { ++ union sockaddr_union *sa = (union sockaddr_union*) _sa; ++ ++ assert(sa); ++ ++ if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6)) ++ return -EAFNOSUPPORT; ++ ++ return ntohs(sa->sa.sa_family == AF_INET6 ? ++ sa->in6.sin6_port : ++ sa->in.sin_port); ++} ++ ++int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) { + union sockaddr_union *sa = (union sockaddr_union*) _sa; + char *p; + +@@ -485,11 +498,18 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ + + a = ntohl(sa->in.sin_addr.s_addr); + +- if (asprintf(&p, +- "%u.%u.%u.%u:%u", +- a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, +- ntohs(sa->in.sin_port)) < 0) +- return -ENOMEM; ++ if (include_port) { ++ if (asprintf(&p, ++ "%u.%u.%u.%u:%u", ++ a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, ++ ntohs(sa->in.sin_port)) < 0) ++ return -ENOMEM; ++ } else { ++ if (asprintf(&p, ++ "%u.%u.%u.%u", ++ a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF) < 0) ++ return -ENOMEM; ++ } + + break; + } +@@ -501,20 +521,34 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ + + if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) { + const uint8_t *a = sa->in6.sin6_addr.s6_addr+12; +- +- if (asprintf(&p, +- "%u.%u.%u.%u:%u", +- a[0], a[1], a[2], a[3], +- ntohs(sa->in6.sin6_port)) < 0) +- return -ENOMEM; ++ if (include_port) { ++ if (asprintf(&p, ++ "%u.%u.%u.%u:%u", ++ a[0], a[1], a[2], a[3], ++ ntohs(sa->in6.sin6_port)) < 0) ++ return -ENOMEM; ++ } else { ++ if (asprintf(&p, ++ "%u.%u.%u.%u", ++ a[0], a[1], a[2], a[3]) < 0) ++ return -ENOMEM; ++ } + } else { + char a[INET6_ADDRSTRLEN]; + +- if (asprintf(&p, +- "[%s]:%u", +- inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)), +- ntohs(sa->in6.sin6_port)) < 0) +- return -ENOMEM; ++ inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)); ++ ++ if (include_port) { ++ if (asprintf(&p, ++ "[%s]:%u", ++ a, ++ ntohs(sa->in6.sin6_port)) < 0) ++ return -ENOMEM; ++ } else { ++ p = strdup(a); ++ if (!p) ++ return -ENOMEM; ++ } + } + + break; +@@ -589,7 +623,7 @@ int getpeername_pretty(int fd, char **ret) { + /* For remote sockets we translate IPv6 addresses back to IPv4 + * if applicable, since that's nicer. */ + +- return sockaddr_pretty(&sa.sa, salen, true, ret); ++ return sockaddr_pretty(&sa.sa, salen, true, true, ret); + } + + int getsockname_pretty(int fd, char **ret) { +@@ -607,7 +641,7 @@ int getsockname_pretty(int fd, char **ret) { + * listening sockets where the difference between IPv4 and + * IPv6 matters. */ + +- return sockaddr_pretty(&sa.sa, salen, false, ret); ++ return sockaddr_pretty(&sa.sa, salen, false, true, ret); + } + + int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) { +@@ -621,7 +655,7 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) + if (r != 0) { + int saved_errno = errno; + +- r = sockaddr_pretty(&sa->sa, salen, true, &ret); ++ r = sockaddr_pretty(&sa->sa, salen, true, true, &ret); + if (r < 0) + return log_error_errno(r, "sockadd_pretty() failed: %m"); + +diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h +index 07d0aff72..6bfb677fb 100644 +--- a/src/shared/socket-util.h ++++ b/src/shared/socket-util.h +@@ -98,7 +98,9 @@ const char* socket_address_get_path(const SocketAddress *a); + + bool socket_ipv6_is_supported(void); + +-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret); ++int sockaddr_port(const struct sockaddr *_sa) _pure_; ++ ++int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); + int getpeername_pretty(int fd, char **ret); + int getsockname_pretty(int fd, char **ret); + +diff --git a/src/timesync/timesyncd-server.h b/src/timesync/timesyncd-server.h +index 243b44a0e..18c44445e 100644 +--- a/src/timesync/timesyncd-server.h ++++ b/src/timesync/timesyncd-server.h +@@ -59,7 +59,7 @@ struct ServerName { + int server_address_new(ServerName *n, ServerAddress **ret, const union sockaddr_union *sockaddr, socklen_t socklen); + ServerAddress* server_address_free(ServerAddress *a); + static inline int server_address_pretty(ServerAddress *a, char **pretty) { +- return sockaddr_pretty(&a->sockaddr.sa, a->socklen, true, pretty); ++ return sockaddr_pretty(&a->sockaddr.sa, a->socklen, true, true, pretty); + } + + int server_name_new(Manager *m, ServerName **ret, ServerType type,const char *string); diff --git a/SOURCES/0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch b/SOURCES/0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch new file mode 100644 index 00000000..8b31c8e2 --- /dev/null +++ b/SOURCES/0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch @@ -0,0 +1,37 @@ +From b3207925388c6423a7665b9363eea90f41a30576 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Apr 2016 17:30:08 +0200 +Subject: [PATCH] core: don't dispatch load queue when setting Slice= for + transient units + +Let's be more careful when setting up the Slice= property of transient units: +let's use manager_load_unit_prepare() instead of manager_load_unit(), so that +the load queue isn't dispatched right away, because our own transient unit is +in it, and we don#t want to have it loaded until we finished initializing it. + +(cherry picked from commit aea529e5b2c864d536941ee18220abcc1a9015a0) +Resolves: #1343904 +--- + src/core/dbus-unit.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 227915efc..49770bfda 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -930,10 +930,14 @@ static int bus_unit_set_transient_property( + } else { + Unit *slice; + +- r = manager_load_unit(u->manager, s, NULL, error, &slice); ++ /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be ++ * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare() ++ * instead of manager_load_unit() on purpose, here. */ ++ r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice); + if (r < 0) + return r; + ++ + if (slice->type != UNIT_SLICE) + return -EINVAL; + diff --git a/SOURCES/0335-run-make-slice-work-in-conjunction-with-scope.patch b/SOURCES/0335-run-make-slice-work-in-conjunction-with-scope.patch new file mode 100644 index 00000000..bc4def1a --- /dev/null +++ b/SOURCES/0335-run-make-slice-work-in-conjunction-with-scope.patch @@ -0,0 +1,27 @@ +From 735f6a0d81b4bbefd0cb57bbfd51f0f86e4a703e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Apr 2016 17:31:40 +0200 +Subject: [PATCH] run: make --slice= work in conjunction with --scope + +Fixes: #2991 +(cherry picked from commit 37e605f934892bf7458eecaeb01fc682e33cc2ad) +Resolves: #1343904 +--- + src/run/run.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/run/run.c b/src/run/run.c +index 468034284..bbb542b65 100644 +--- a/src/run/run.c ++++ b/src/run/run.c +@@ -595,6 +595,10 @@ static int transient_scope_set_properties(sd_bus_message *m) { + if (r < 0) + return r; + ++ r = transient_cgroup_set_properties(m); ++ if (r < 0) ++ return r; ++ + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid()); + if (r < 0) + return r; diff --git a/SOURCES/0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch b/SOURCES/0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch new file mode 100644 index 00000000..6db74bfa --- /dev/null +++ b/SOURCES/0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch @@ -0,0 +1,61 @@ +From 6e5117b83af5998359916f276a9b32f755c0e6f4 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 20 May 2016 12:33:48 +0200 +Subject: [PATCH] myhostname: fix timeout if ipv6 is disabled + +rhel-only +Resolves: #1330973 +--- + src/nss-myhostname/nss-myhostname.c | 9 +++++++-- + src/shared/socket-util.c | 10 ++++++++++ + 2 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c +index a939bb267..e197cc752 100644 +--- a/src/nss-myhostname/nss-myhostname.c ++++ b/src/nss-myhostname/nss-myhostname.c +@@ -33,6 +33,7 @@ + #include "local-addresses.h" + #include "macro.h" + #include "nss-util.h" ++#include "socket-util.h" + #include "util.h" + + /* We use 127.0.0.2 as IPv4 address. This has the advantage over +@@ -380,9 +381,13 @@ enum nss_status _nss_myhostname_gethostbyname3_r( + return NSS_STATUS_NOTFOUND; + } + +- n_addresses = local_addresses(NULL, 0, af, &addresses); +- if (n_addresses < 0) ++ if (af == AF_INET6 && !socket_ipv6_is_supported()) { + n_addresses = 0; ++ } else { ++ n_addresses = local_addresses(NULL, 0, af, &addresses); ++ if (n_addresses < 0) ++ n_addresses = 0; ++ } + + canonical = hn; + additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL; +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index a21251014..79d1582d4 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -435,6 +435,16 @@ bool socket_ipv6_is_supported(void) { + return true; + + /* If module was loaded with disable=1 no IPv6 available */ ++ if (l[0] == '1') ++ return false; ++ ++ free(l); ++ l = NULL; ++ ++ if (read_one_line_file("/proc/sys/net/ipv6/conf/all/disable_ipv6", &l) < 0) ++ return true; ++ ++ /* If IPv6 was disabled via sysctl during runtime */ + return l[0] == '0'; + } + diff --git a/SOURCES/0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch b/SOURCES/0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch new file mode 100644 index 00000000..e19cf07d --- /dev/null +++ b/SOURCES/0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch @@ -0,0 +1,124 @@ +From 997778e332e9f6d3d1c42e9a222fcab8d4732c40 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 27 May 2016 14:29:17 +0200 +Subject: [PATCH] readahead: do not increase nr_requests for root fs block + device + +Having nr_requests can cause system lockups. Arguably, this should get +fixed somehow in kernel. For now we just stop changing the +value. + +Note that not bumping a value may cause that posix_fadvise call +will block in case there is no room in a request queue. + +See: http://article.gmane.org/gmane.linux.kernel/1072356 + +RHEL-only +Resolves: #1314559 +--- + src/readahead/readahead-common.c | 64 ---------------------------------------- + src/readahead/readahead-common.h | 2 -- + src/readahead/readahead-replay.c | 2 -- + 3 files changed, 68 deletions(-) + +diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c +index 3ca48a725..6cf33f7cf 100644 +--- a/src/readahead/readahead-common.c ++++ b/src/readahead/readahead-common.c +@@ -253,70 +253,6 @@ ReadaheadShared *shared_get(void) { + return m; + } + +-/* We use 20K instead of the more human digestable 16K here. Why? +- Simply so that it is more unlikely that users end up picking this +- value too so that we can recognize better whether the user changed +- the value while we had it temporarily bumped. */ +-#define BUMP_REQUEST_NR (20*1024u) +- +-int block_bump_request_nr(const char *p) { +- struct stat st; +- uint64_t u; +- char *ap = NULL, *line = NULL; +- int r; +- dev_t d; +- +- assert(p); +- +- if (stat(p, &st) < 0) +- return -errno; +- +- if (major(st.st_dev) == 0) +- return 0; +- +- d = st.st_dev; +- block_get_whole_disk(d, &d); +- +- if (asprintf(&ap, "/sys/dev/block/%u:%u/queue/nr_requests", major(d), minor(d)) < 0) { +- r= -ENOMEM; +- goto finish; +- } +- +- r = read_one_line_file(ap, &line); +- if (r < 0) { +- if (r == -ENOENT) +- r = 0; +- goto finish; +- } +- +- r = safe_atou64(line, &u); +- if (r >= 0 && u >= BUMP_REQUEST_NR) { +- r = 0; +- goto finish; +- } +- +- free(line); +- line = NULL; +- +- if (asprintf(&line, "%u", BUMP_REQUEST_NR) < 0) { +- r = -ENOMEM; +- goto finish; +- } +- +- r = write_string_file(ap, line); +- if (r < 0) +- goto finish; +- +- log_info("Bumped block_nr parameter of %u:%u to %u. This is a temporary hack and should be removed one day.", major(d), minor(d), BUMP_REQUEST_NR); +- r = 1; +- +-finish: +- free(ap); +- free(line); +- +- return r; +-} +- + int block_get_readahead(const char *p, uint64_t *bytes) { + struct stat st; + char *ap = NULL, *line = NULL; +diff --git a/src/readahead/readahead-common.h b/src/readahead/readahead-common.h +index b34f3aadd..cc2ea81a9 100644 +--- a/src/readahead/readahead-common.h ++++ b/src/readahead/readahead-common.h +@@ -51,8 +51,6 @@ typedef struct ReadaheadShared { + + ReadaheadShared *shared_get(void); + +-int block_bump_request_nr(const char *p); +- + int block_get_readahead(const char *p, uint64_t *bytes); + int block_set_readahead(const char *p, uint64_t bytes); + +diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c +index f81e0fe55..c2e281687 100644 +--- a/src/readahead/readahead-replay.c ++++ b/src/readahead/readahead-replay.c +@@ -134,8 +134,6 @@ static int replay(const char *root) { + + assert(root); + +- block_bump_request_nr(root); +- + if (asprintf(&pack_fn, "%s/.readahead", root) < 0) + return log_oom(); + diff --git a/SOURCES/0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch b/SOURCES/0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch new file mode 100644 index 00000000..ccb64bb5 --- /dev/null +++ b/SOURCES/0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch @@ -0,0 +1,62 @@ +From 33ca0f1f0d4b9a91588c84067d2fb30968e41235 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Tue, 14 Jun 2016 14:20:56 +0200 +Subject: [PATCH] manager: reduce complexity of unit_gc_sweep (#3507) + +When unit is marked as UNSURE, we are trying to find if it state was +changed over and over again. So lets not go through the UNSURE states +again. Also when we find a GOOD unit lets propagate the GOOD state to +all units that this unit reference. + +This is a problem on machines with a lot of initscripts with different +starting priority, since those units will reference each other and the +original algorithm might get to n! complexity. + +Thanks HATAYAMA Daisuke for the expand_good_state code. +Cherry-picked from: 4892084f096c19da0e83f28f250ca187b58c22b2 +Resolves: #1344556 +--- + src/core/manager.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 370c8cbbe..e5226a8a6 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -838,6 +838,19 @@ enum { + _GC_OFFSET_MAX + }; + ++static void unit_gc_mark_good(Unit *u, unsigned gc_marker) ++{ ++ Iterator i; ++ Unit *other; ++ ++ u->gc_marker = gc_marker + GC_OFFSET_GOOD; ++ ++ /* Recursively mark referenced units as GOOD as well */ ++ SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i) ++ if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE) ++ unit_gc_mark_good(other, gc_marker); ++} ++ + static void unit_gc_sweep(Unit *u, unsigned gc_marker) { + Iterator i; + Unit *other; +@@ -847,6 +860,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { + + if (u->gc_marker == gc_marker + GC_OFFSET_GOOD || + u->gc_marker == gc_marker + GC_OFFSET_BAD || ++ u->gc_marker == gc_marker + GC_OFFSET_UNSURE || + u->gc_marker == gc_marker + GC_OFFSET_IN_PATH) + return; + +@@ -887,7 +901,7 @@ bad: + return; + + good: +- u->gc_marker = gc_marker + GC_OFFSET_GOOD; ++ unit_gc_mark_good(u, gc_marker); + } + + static unsigned manager_dispatch_gc_queue(Manager *m) { diff --git a/SOURCES/0339-hwdb-selinuxify-a-bit-3460.patch b/SOURCES/0339-hwdb-selinuxify-a-bit-3460.patch new file mode 100644 index 00000000..f83afeac --- /dev/null +++ b/SOURCES/0339-hwdb-selinuxify-a-bit-3460.patch @@ -0,0 +1,68 @@ +From ca82178b166ae5fb8efe4b09aadae802534cf6e3 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Tue, 7 Jun 2016 20:47:41 +0300 +Subject: [PATCH] hwdb: selinuxify a bit (#3460) + +-bash-4.3# rm /etc/udev/hwdb.bin +-bash-4.3# systemd-hwdb update +-bash-4.3# ls -Z /etc/udev/hwdb.bin +system_u:object_r:systemd_hwdb_etc_t:s0 /etc/udev/hwdb.bin + +Fixes: #3458 + +(cherry picked from commit ea683512f9b82f2257770f0ed56d819eea230fc2) +Resolves: #1343648 +--- + Makefile.am | 1 + + src/hwdb/hwdb.c | 8 ++++++-- + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index b0a34b212..3848338a2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3752,6 +3752,7 @@ systemd_hwdb_SOURCES = \ + src/hwdb/hwdb.c + + systemd_hwdb_LDADD = \ ++ libsystemd-label.la \ + libsystemd-shared.la \ + libsystemd-internal.la \ + libudev-internal.la +diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c +index 4539673ea..8e5d6cc86 100644 +--- a/src/hwdb/hwdb.c ++++ b/src/hwdb/hwdb.c +@@ -34,6 +34,8 @@ + + #include "hwdb-internal.h" + #include "hwdb-util.h" ++#include "label.h" ++#include "selinux-util.h" + + /* + * Generic udev properties, key/value database based on modalias strings. +@@ -642,12 +644,12 @@ static int hwdb_update(int argc, char *argv[], void *userdata) { + if (!hwdb_bin) + return -ENOMEM; + +- mkdir_parents(hwdb_bin, 0755); ++ mkdir_parents_label(hwdb_bin, 0755); + r = trie_store(trie, hwdb_bin); + if (r < 0) + return log_error_errno(r, "Failure writing database %s: %m", hwdb_bin); + +- return 0; ++ return label_fix(hwdb_bin, false, false); + } + + static void help(void) { +@@ -733,6 +735,8 @@ int main (int argc, char *argv[]) { + if (r <= 0) + goto finish; + ++ mac_selinux_init(NULL); ++ + r = hwdb_main(argc, argv); + + finish: diff --git a/SOURCES/0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch b/SOURCES/0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch new file mode 100644 index 00000000..05e841b3 --- /dev/null +++ b/SOURCES/0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch @@ -0,0 +1,55 @@ +From 0860805a09ce6c2c2136306bdf64d58621368291 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 8 Jul 2016 15:54:55 +0200 +Subject: [PATCH] udevadm: explicitly relabel /etc/udev/hwdb.bin after rename + +This is basically the same change as ea68351. + +Cherry-picked from: 4f43161e909cb420aafbc4bebce4361b17b80fdd +Related: #1350756 +--- + src/udev/udevadm-hwdb.c | 5 ++++- + src/udev/udevadm.c | 2 +- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c +index d65e40c01..201e2a0cd 100644 +--- a/src/udev/udevadm-hwdb.c ++++ b/src/udev/udevadm-hwdb.c +@@ -26,6 +26,8 @@ + #include "util.h" + #include "strbuf.h" + #include "conf-files.h" ++#include "label.h" ++#include "mkdir.h" + + #include "udev.h" + #include "hwdb-internal.h" +@@ -654,12 +656,13 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { + rc = EXIT_FAILURE; + goto out; + } +- mkdir_parents(hwdb_bin, 0755); ++ mkdir_parents_label(hwdb_bin, 0755); + err = trie_store(trie, hwdb_bin); + if (err < 0) { + log_error_errno(err, "Failure writing database %s: %m", hwdb_bin); + rc = EXIT_FAILURE; + } ++ label_fix(hwdb_bin, false, false); + } + + if (test) { +diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c +index 56cd0cd4e..d05a26e78 100644 +--- a/src/udev/udevadm.c ++++ b/src/udev/udevadm.c +@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) { + + log_parse_environment(); + log_open(); +- mac_selinux_init("/dev"); ++ mac_selinux_init(NULL); + + while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0) + switch (c) { diff --git a/SOURCES/0341-systemctl-return-diffrent-error-code-if-service-exis.patch b/SOURCES/0341-systemctl-return-diffrent-error-code-if-service-exis.patch new file mode 100644 index 00000000..ea4d7d0c --- /dev/null +++ b/SOURCES/0341-systemctl-return-diffrent-error-code-if-service-exis.patch @@ -0,0 +1,82 @@ +From 2eb2ddac8eaa258dd1ac0b2d4c1aefef9b66a989 Mon Sep 17 00:00:00 2001 +From: Susant Sahani +Date: Mon, 30 May 2016 20:23:15 +0530 +Subject: [PATCH] systemctl: return diffrent error code if service exist or not + (#3385) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before: +[sus@maximus bz-1256858]$ systemctl status rsyslog.service;echo $? +● rsyslog.service - System Logging Service + Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor +preset: enabled) + Drop-In: /etc/systemd/system/rsyslog.service.d + └─50-CPUShares.conf + Active: inactive (dead) since Mon 2016-05-30 11:54:25 IST; 2h 26min ago + Docs: man:rsyslogd(8) + http://www.rsyslog.com/doc/ + Process: 1159 ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS (code=exited, +status=0/SUCCESS) + Main PID: 1159 (code=exited, status=0/SUCCESS) + +May 30 11:07:50 maximus systemd[1]: Starting System Logging Service... +May 30 11:07:50 maximus systemd[1]: Started System Logging Service. +May 30 11:54:25 maximus systemd[1]: Stopping System Logging Service... +May 30 11:54:25 maximus systemd[1]: Stopped System Logging Service. +3 +[sus@maximus bz-1256858]$ systemctl status hello.service;echo $? +● hello.service + Loaded: not-found (Reason: No such file or directory) + Active: inactive (dead) +3 + +After: +$ ./systemctl status hello.service;echo $? +Failed to dump process list, ignoring: Access denied +● hello.service + Loaded: not-found (Reason: No such file or directory) + Active: inactive (dead) +4 +[sus@maximus bz-1256858]$ ./systemctl status rsyslog.service;echo $? +Failed to dump process list, ignoring: Access denied +● rsyslog.service - System Logging Service + Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor +preset: enabled) + Drop-In: /etc/systemd/system/rsyslog.service.d + └─50-CPUShares.conf + Active: inactive (dead) since Mon 2016-05-30 11:54:25 IST; 2h 24min ago + Docs: man:rsyslogd(8) + http://www.rsyslog.com/doc/ + Process: 1159 ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS (code=exited, +status=0/SUCCESS) + Main PID: 1159 (code=exited, status=0/SUCCESS) + +May 30 11:07:50 maximus systemd[1]: Starting System Logging Service... +May 30 11:07:50 maximus systemd[1]: Started System Logging Service. +May 30 11:54:25 maximus systemd[1]: Stopping System Logging Service... +May 30 11:54:25 maximus systemd[1]: Stopped System Logging Service. +3 + +Fixes: 1092 + +(cherry picked from commit ca473d572f0d2d8f547ff787ae67afd489a3f15e) +Resolves: #1047466 +--- + src/systemctl/systemctl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 95ddf3be7..6079d60db 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4295,6 +4295,8 @@ static int show_one( + */ + if (info.pid_file && access(info.pid_file, F_OK) == 0) + r = 1; ++ else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) ++ r = 4; + else + r = 3; + } diff --git a/SOURCES/0342-systemctl-Replace-init-script-error-codes-with-enum-.patch b/SOURCES/0342-systemctl-Replace-init-script-error-codes-with-enum-.patch new file mode 100644 index 00000000..2032b887 --- /dev/null +++ b/SOURCES/0342-systemctl-Replace-init-script-error-codes-with-enum-.patch @@ -0,0 +1,74 @@ +From 20a914f752898aae11708d7bf901e7dc1e81a28e Mon Sep 17 00:00:00 2001 +From: Susant Sahani +Date: Tue, 31 May 2016 19:06:58 +0530 +Subject: [PATCH] systemctl: Replace init script error codes with enum (#3400) + +Now we just using constants for the init script exit status codes. +Replace those error codes with enum so that it's more meaningful +and readable. + +(cherry picked from commit b613907ea988e2994c68be686b5e92cdc7d3fb68) +Related: #1047466 +--- + src/systemctl/systemctl.c | 29 ++++++++++++++++++++++++----- + 1 file changed, 24 insertions(+), 5 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 6079d60db..fdda174ae 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -75,6 +75,25 @@ + #include "mkdir.h" + #include "dropin.h" + ++/* The init script exit status codes ++ 0 program is running or service is OK ++ 1 program is dead and /var/run pid file exists ++ 2 program is dead and /var/lock lock file exists ++ 3 program is not running ++ 4 program or service status is unknown ++ 5-99 reserved for future LSB use ++ 100-149 reserved for distribution use ++ 150-199 reserved for application use ++ 200-254 reserved ++*/ ++enum { ++ EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0, ++ EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1, ++ EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2, ++ EXIT_PROGRAM_NOT_RUNNING = 3, ++ EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4, ++}; ++ + static char **arg_types = NULL; + static char **arg_states = NULL; + static char **arg_properties = NULL; +@@ -3028,11 +3047,11 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch + + static int check_unit_active(sd_bus *bus, char **args) { + /* According to LSB: 3, "program is not running" */ +- return check_unit_generic(bus, 3, "active\0reloading\0", args + 1); ++ return check_unit_generic(bus, EXIT_PROGRAM_NOT_RUNNING, "active\0reloading\0", args + 1); + } + + static int check_unit_failed(sd_bus *bus, char **args) { +- return check_unit_generic(bus, 1, "failed\0", args + 1); ++ return check_unit_generic(bus, EXIT_PROGRAM_DEAD_AND_PID_EXISTS, "failed\0", args + 1); + } + + static int kill_unit(sd_bus *bus, char **args) { +@@ -4294,11 +4313,11 @@ static int show_one( + * 4: program or service status is unknown + */ + if (info.pid_file && access(info.pid_file, F_OK) == 0) +- r = 1; ++ r = EXIT_PROGRAM_DEAD_AND_PID_EXISTS; + else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) +- r = 4; ++ r = EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + else +- r = 3; ++ r = EXIT_PROGRAM_NOT_RUNNING; + } + + while ((p = info.exec)) { diff --git a/SOURCES/0343-systemctl-rework-systemctl-status-a-bit.patch b/SOURCES/0343-systemctl-rework-systemctl-status-a-bit.patch new file mode 100644 index 00000000..ceb5b295 --- /dev/null +++ b/SOURCES/0343-systemctl-rework-systemctl-status-a-bit.patch @@ -0,0 +1,234 @@ +From 41bb37959c96b8fddc13b37384b3453393517f4f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 13 Jun 2016 19:11:26 +0200 +Subject: [PATCH] systemctl: rework "systemctl status" a bit + +This reworks "systemctl status" and "systemctl show" a bit. It removes the +definition of the `property_info` structure, because we can simply reuse the +existing UnitStatusInfo type for that. + +The "could not be found" message is now printed by show_one() itself (and not +its caller), so that it is shown regardless by who the function is called. +(This makes it necessary to pass the unit name to the function.) + +This also adds all properties found to a set, and then checks if any of the +properties passed via "--property=" is mising in it, if so, a proper error is +generated. + +Support for checking the PID file of a unit is removed, as this cannot be done +reasonably client side (since the systemd instance we are talking to might sit +on another host) + +Replaces: #3411 +Fixes: #3425 +Also see: #3504 + +(cherry picked from commit 3dced37b7c2c9a5c733817569d2bbbaa397adaf7) +Related: #1047466 +--- + src/systemctl/systemctl.c | 106 +++++++++++++++++++++++++++++----------------- + 1 file changed, 68 insertions(+), 38 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index fdda174ae..93b7a193b 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4211,12 +4211,19 @@ static int show_one( + const char *verb, + sd_bus *bus, + const char *path, ++ const char *unit, + bool show_properties, + bool *new_line, + bool *ellipsized) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ _cleanup_set_free_ Set *found_properties = NULL; ++ static const struct bus_properties_map property_map[] = { ++ { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) }, ++ { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) }, ++ {} ++ }; + UnitStatusInfo info = { + .memory_current = (uint64_t) -1, + .memory_limit = (uint64_t) -1, +@@ -4243,6 +4250,25 @@ static int show_one( + return r; + } + ++ if (unit) { ++ r = bus_message_map_all_properties(bus, reply, property_map, &info); ++ if (r < 0) ++ return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); ++ ++ if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) { ++ log_error("Unit %s could not be found.", unit); ++ ++ if (streq(verb, "status")) ++ return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; ++ ++ return -ENOENT; ++ } ++ ++ r = sd_bus_message_rewind(reply, true); ++ if (r < 0) ++ return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); ++ } ++ + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return bus_log_parse_error(r); +@@ -4267,9 +4293,17 @@ static int show_one( + if (r < 0) + return bus_log_parse_error(r); + +- if (show_properties) ++ if (show_properties) { ++ r = set_ensure_allocated(&found_properties, &string_hash_ops); ++ if (r < 0) ++ return log_oom(); ++ ++ r = set_put(found_properties, name); ++ if (r < 0 && r != EEXIST) ++ return log_oom(); ++ + r = print_property(name, reply, contents); +- else ++ } else + r = status_property(name, reply, &info, contents); + if (r < 0) + return r; +@@ -4291,35 +4325,30 @@ static int show_one( + + r = 0; + +- if (!show_properties) { +- if (streq(verb, "help")) +- show_unit_help(&info); ++ if (show_properties) { ++ char **pp; ++ ++ STRV_FOREACH(pp, arg_properties) { ++ if (!set_contains(found_properties, *pp)) { ++ log_warning("Property %s does not exist.", *pp); ++ r = -ENXIO; ++ } ++ } ++ } else if (streq(verb, "help")) ++ show_unit_help(&info); ++ else if (streq(verb, "status")) { ++ print_status_info(&info, ellipsized); ++ ++ if (info.active_state && STR_IN_SET(info.active_state, "inactive", "failed")) ++ r = EXIT_PROGRAM_NOT_RUNNING; + else +- print_status_info(&info, ellipsized); ++ r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK; + } + + strv_free(info.documentation); + strv_free(info.dropin_paths); + strv_free(info.listen); + +- if (!streq_ptr(info.active_state, "active") && +- !streq_ptr(info.active_state, "reloading") && +- streq(verb, "status")) { +- /* According to LSB: "program not running" */ +- /* 0: program is running or service is OK +- * 1: program is dead and /run PID file exists +- * 2: program is dead and /run/lock lock file exists +- * 3: program is not running +- * 4: program or service status is unknown +- */ +- if (info.pid_file && access(info.pid_file, F_OK) == 0) +- r = EXIT_PROGRAM_DEAD_AND_PID_EXISTS; +- else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) +- r = EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; +- else +- r = EXIT_PROGRAM_NOT_RUNNING; +- } +- + while ((p = info.exec)) { + LIST_REMOVE(exec, info.exec, p); + exec_status_info_free(p); +@@ -4394,7 +4423,7 @@ static int show_all( + if (!p) + return log_oom(); + +- r = show_one(verb, bus, p, show_properties, new_line, ellipsized); ++ r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized); + if (r < 0) + return r; + else if (r > 0 && ret == 0) +@@ -4481,9 +4510,8 @@ static int show(sd_bus *bus, char **args) { + setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); + + /* If no argument is specified inspect the manager itself */ +- + if (show_properties && strv_length(args) <= 1) +- return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); ++ return show_one(args[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized); + + if (show_status && strv_length(args) <= 1) { + +@@ -4498,7 +4526,7 @@ static int show(sd_bus *bus, char **args) { + char **name; + + STRV_FOREACH(name, args + 1) { +- _cleanup_free_ char *unit = NULL; ++ _cleanup_free_ char *path = NULL, *unit = NULL; + uint32_t id; + + if (safe_atou32(*name, &id) < 0) { +@@ -4508,20 +4536,23 @@ static int show(sd_bus *bus, char **args) { + continue; + } else if (show_properties) { + /* Interpret as job id */ +- if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0) ++ if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0) + return log_oom(); + + } else { + /* Interpret as PID */ +- r = get_unit_dbus_path_by_pid(bus, id, &unit); ++ r = get_unit_dbus_path_by_pid(bus, id, &path); + if (r < 0) { + ret = r; + continue; + } ++ ++ r = unit_name_from_dbus_path(path, &unit); ++ if (r < 0) ++ return log_oom(); + } + +- r = show_one(args[0], bus, unit, show_properties, +- &new_line, &ellipsized); ++ r = show_one(args[0], bus, path, unit, show_properties, &new_line, &ellipsized); + if (r < 0) + return r; + else if (r > 0 && ret == 0) +@@ -4536,17 +4567,16 @@ static int show(sd_bus *bus, char **args) { + log_error_errno(r, "Failed to expand names: %m"); + + STRV_FOREACH(name, names) { +- _cleanup_free_ char *unit; ++ _cleanup_free_ char *path; + +- unit = unit_dbus_path_from_name(*name); +- if (!unit) ++ path = unit_dbus_path_from_name(*name); ++ if (!path) + return log_oom(); + +- r = show_one(args[0], bus, unit, show_properties, +- &new_line, &ellipsized); ++ r = show_one(args[0], bus, path, *name, show_properties, &new_line, &ellipsized); + if (r < 0) + return r; +- else if (r > 0 && ret == 0) ++ if (r > 0 && ret == 0) + ret = r; + } + } diff --git a/SOURCES/0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch b/SOURCES/0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch new file mode 100644 index 00000000..6d8731af --- /dev/null +++ b/SOURCES/0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch @@ -0,0 +1,62 @@ +From 1466d84c159c1a9d1839c1b346906b722e6311a3 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 01:40:44 +0200 +Subject: [PATCH] journal-verify: don't hit SIGFPE when determining progress + +If we determine the progress based on a number of objects available, +don't blindly devide by the number of objects, given that it might be 0. + +Cherry-picked from: 45c047b227d96e98e7076c15ae774ff6390dc403 +Related: #1350232 +--- + src/journal/journal-verify.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index b03335ef3..983217c1b 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -69,6 +69,16 @@ static void draw_progress(uint64_t p, usec_t *last_usec) { + fflush(stdout); + } + ++static uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) { ++ ++ /* Calculates scale * p / m, but handles m == 0 safely, and saturates */ ++ ++ if (p >= m || m == 0) ++ return scale; ++ ++ return scale * p / m; ++} ++ + static void flush_progress(void) { + unsigned n, i; + +@@ -584,7 +594,7 @@ static int verify_hash_table( + uint64_t last = 0, p; + + if (show_progress) +- draw_progress(0xC000 + (0x3FFF * i / n), last_usec); ++ draw_progress(0xC000 + scale_progress(0x3FFF, i, n), last_usec); + + p = le64toh(f->data_hash_table[i].head_hash_offset); + while (p != 0) { +@@ -726,7 +736,7 @@ static int verify_entry_array( + Object *o; + + if (show_progress) +- draw_progress(0x8000 + (0x3FFF * i / n), last_usec); ++ draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec); + + if (a == 0) { + error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n); +@@ -863,7 +873,7 @@ int journal_file_verify( + p = le64toh(f->header->header_size); + while (p != 0) { + if (show_progress) +- draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec); ++ draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec); + + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); + if (r < 0) { diff --git a/SOURCES/0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch b/SOURCES/0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch new file mode 100644 index 00000000..429ca14e --- /dev/null +++ b/SOURCES/0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch @@ -0,0 +1,162 @@ +From 283df68dbc1d90cad21beec6563215c26c69ec2c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 01:55:45 +0200 +Subject: [PATCH] journal: avoid mapping empty data and field hash tables + +When a new journal file is created we write the header first, then sync +and only then create the data and field hash tables in them. That means +to other processes it might appear that the files have a valid header +but not data and field hash tables. Our reader code should be able to +deal with this. + +With this change we'll not map the two hash tables right-away after +opening a file for reading anymore (because that will of course fail if +the objects are missing), but delay this until the first time we access +them. On top of that, when we want to look something up in the hash +tables and we notice they aren't initialized yet, we consider them +empty. + +This improves handling of some journal files reported in #487. + +Cherry-picked from: dade37d403f1b8c1d7bb2efbe2361f2a3e999613 +Related: #1350232 +--- + src/journal/journal-file.c | 37 ++++++++++++++++++++++++++----------- + src/journal/journal-file.h | 3 +++ + src/journal/journal-verify.c | 14 ++++++++++++++ + 3 files changed, 43 insertions(+), 11 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 892fe4734..ef1849787 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -656,13 +656,16 @@ static int journal_file_setup_field_hash_table(JournalFile *f) { + return 0; + } + +-static int journal_file_map_data_hash_table(JournalFile *f) { ++int journal_file_map_data_hash_table(JournalFile *f) { + uint64_t s, p; + void *t; + int r; + + assert(f); + ++ if (f->data_hash_table) ++ return 0; ++ + p = le64toh(f->header->data_hash_table_offset); + s = le64toh(f->header->data_hash_table_size); + +@@ -678,13 +681,16 @@ static int journal_file_map_data_hash_table(JournalFile *f) { + return 0; + } + +-static int journal_file_map_field_hash_table(JournalFile *f) { ++int journal_file_map_field_hash_table(JournalFile *f) { + uint64_t s, p; + void *t; + int r; + + assert(f); + ++ if (f->field_hash_table) ++ return 0; ++ + p = le64toh(f->header->field_hash_table_offset); + s = le64toh(f->header->field_hash_table_size); + +@@ -803,10 +809,18 @@ int journal_file_find_field_object_with_hash( + assert(f); + assert(field && size > 0); + ++ /* If the field hash table is empty, we can't find anything */ ++ if (le64toh(f->header->field_hash_table_size) <= 0) ++ return 0; ++ ++ /* Map the field hash table, if it isn't mapped yet. */ ++ r = journal_file_map_field_hash_table(f); ++ if (r < 0) ++ return r; ++ + osize = offsetof(Object, field.payload) + size; + + m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem); +- + if (m <= 0) + return -EBADMSG; + +@@ -866,6 +880,15 @@ int journal_file_find_data_object_with_hash( + assert(f); + assert(data || size == 0); + ++ /* If there's no data hash table, then there's no entry. */ ++ if (le64toh(f->header->data_hash_table_size) <= 0) ++ return 0; ++ ++ /* Map the data hash table, if it isn't mapped yet. */ ++ r = journal_file_map_data_hash_table(f); ++ if (r < 0) ++ return r; ++ + osize = offsetof(Object, data.payload) + size; + + m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); +@@ -2707,14 +2730,6 @@ int journal_file_open( + #endif + } + +- r = journal_file_map_field_hash_table(f); +- if (r < 0) +- goto fail; +- +- r = journal_file_map_data_hash_table(f); +- if (r < 0) +- goto fail; +- + if (mmap_cache_got_sigbus(f->mmap, f->fd)) { + r = -EIO; + goto fail; +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index 0f29b092b..c74ad5fc5 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -234,3 +234,6 @@ static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) { + assert(f); + return f->compress_xz || f->compress_lz4; + } ++ ++int journal_file_map_data_hash_table(JournalFile *f); ++int journal_file_map_field_hash_table(JournalFile *f); +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 983217c1b..d2d5c400c 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -590,6 +590,13 @@ static int verify_hash_table( + assert(last_usec); + + n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); ++ if (n <= 0) ++ return 0; ++ ++ r = journal_file_map_data_hash_table(f); ++ if (r < 0) ++ return log_error_errno(r, "Failed to map data hash table: %m"); ++ + for (i = 0; i < n; i++) { + uint64_t last = 0, p; + +@@ -647,6 +654,13 @@ static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) + assert(f); + + n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); ++ if (n <= 0) ++ return 0; ++ ++ r = journal_file_map_data_hash_table(f); ++ if (r < 0) ++ return log_error_errno(r, "Failed to map data hash table: %m"); ++ + h = hash % n; + + q = le64toh(f->data_hash_table[h].head_hash_offset); diff --git a/SOURCES/0346-journal-when-verifying-journal-files-handle-empty-on.patch b/SOURCES/0346-journal-when-verifying-journal-files-handle-empty-on.patch new file mode 100644 index 00000000..a381dbcd --- /dev/null +++ b/SOURCES/0346-journal-when-verifying-journal-files-handle-empty-on.patch @@ -0,0 +1,84 @@ +From 0c2f52bb9b0bce392f14a38d6477e396d6fc987e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:00:43 +0200 +Subject: [PATCH] journal: when verifying journal files, handle empty ones + nicely + +A journal file that carries no objects should be considered valid. + +Cherry-picked from: 8dc37a85255f68d62f7af66696cbf6a66401fb2a +Resolves: #1350232 +--- + src/journal/journal-verify.c | 37 ++++++++++++++----------------------- + 1 file changed, 14 insertions(+), 23 deletions(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index d2d5c400c..53f0550da 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -885,7 +885,11 @@ int journal_file_verify( + * superficial structure, headers, hashes. */ + + p = le64toh(f->header->header_size); +- while (p != 0) { ++ for (;;) { ++ /* Early exit if there are no objects in the file, at all */ ++ if (le64toh(f->header->tail_object_offset) == 0) ++ break; ++ + if (show_progress) + draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec); + +@@ -901,9 +905,6 @@ int journal_file_verify( + goto fail; + } + +- if (p == le64toh(f->header->tail_object_offset)) +- found_last = true; +- + n_objects ++; + + r = journal_file_object_verify(f, p, o); +@@ -1148,13 +1149,15 @@ int journal_file_verify( + n_weird ++; + } + +- if (p == le64toh(f->header->tail_object_offset)) +- p = 0; +- else +- p = p + ALIGN64(le64toh(o->object.size)); +- } ++ if (p == le64toh(f->header->tail_object_offset)) { ++ found_last = true; ++ break; ++ } + +- if (!found_last) { ++ p = p + ALIGN64(le64toh(o->object.size)); ++ }; ++ ++ if (!found_last && le64toh(f->header->tail_object_offset) != 0) { + error(le64toh(f->header->tail_object_offset), "tail object pointer dead"); + r = -EBADMSG; + goto fail; +@@ -1200,19 +1203,7 @@ int journal_file_verify( + goto fail; + } + +- if (n_data_hash_tables != 1) { +- error(0, "missing data hash table"); +- r = -EBADMSG; +- goto fail; +- } +- +- if (n_field_hash_tables != 1) { +- error(0, "missing field hash table"); +- r = -EBADMSG; +- goto fail; +- } +- +- if (!found_main_entry_array) { ++ if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) { + error(0, "missing entry array"); + r = -EBADMSG; + goto fail; diff --git a/SOURCES/0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch b/SOURCES/0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch new file mode 100644 index 00000000..8d17eb93 --- /dev/null +++ b/SOURCES/0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch @@ -0,0 +1,31 @@ +From 8cfa250db93688a0796475cb911215e4edb252aa Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:02:07 +0200 +Subject: [PATCH] journal: explain the error when we find a non-DATA object + that is compressed + +Only objects of type DATA may be compressed, generate a message about +that, like we do for all other errros. + +Cherry-picked from: bca9e39dfadaefc4b02c0dd378adc3d6221071de +Related: #1350232 +--- + src/journal/journal-verify.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 53f0550da..77fb4090d 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -123,8 +123,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + * other objects. */ + + if ((o->object.flags & OBJECT_COMPRESSED_XZ) && +- o->object.type != OBJECT_DATA) ++ o->object.type != OBJECT_DATA) { ++ error(offset, "Found compressed object that isn't of type DATA, which is not allowed."); + return -EBADMSG; ++ } + + switch (o->object.type) { + diff --git a/SOURCES/0348-journalctl-properly-detect-empty-journal-files.patch b/SOURCES/0348-journalctl-properly-detect-empty-journal-files.patch new file mode 100644 index 00000000..ea9dbfa4 --- /dev/null +++ b/SOURCES/0348-journalctl-properly-detect-empty-journal-files.patch @@ -0,0 +1,31 @@ +From 8290b73eeb8da4f8f0076f3bb7e23990af734de0 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:10:32 +0200 +Subject: [PATCH] journalctl: properly detect empty journal files + +When we encounter a journal file with exactly zero entries, print a nice +message and exit, and don't print a weird error message. + +Cherry-picked from: 02ab86c732576a71179ce12e97d44c289833236d +Related: #1350232 +--- + src/journal/journalctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 6948ed689..904aae99e 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2141,6 +2141,12 @@ int main(int argc, char *argv[]) { + return EXIT_FAILURE; + } + ++ if (r == 0) { ++ printf("-- No entries --\n"); ++ return EXIT_SUCCESS; ++ } ++ ++ + if (!arg_follow) + pager_open_if_enabled(); + diff --git a/SOURCES/0349-journal-uppercase-first-character-in-verify-error-me.patch b/SOURCES/0349-journal-uppercase-first-character-in-verify-error-me.patch new file mode 100644 index 00000000..75092d2d --- /dev/null +++ b/SOURCES/0349-journal-uppercase-first-character-in-verify-error-me.patch @@ -0,0 +1,642 @@ +From 2a9dd5375b4f35a101d6ef3deb035d901d7a2392 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:18:13 +0200 +Subject: [PATCH] journal: uppercase first character in verify error messages + +In the english language the first character of a sentence is supposed to +be uppercase. Let's make sure this also applies to the journal +verification error messages. + +Cherry-picked from: e80acc51aeaf2d74cb4d6cecbcb6e18f74c22c05 +Related: #1350232 +--- + src/journal/journal-verify.c | 162 ++++++++++++++++++++----------------------- + 1 file changed, 75 insertions(+), 87 deletions(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 77fb4090d..8a66ac7f0 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -135,15 +135,15 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + int compression, r; + + if (le64toh(o->data.entry_offset) == 0) +- warning(offset, "unused data (entry_offset==0)"); ++ warning(offset, "Unused data (entry_offset==0)"); + + if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) { +- error(offset, "bad n_entries: %"PRIu64, o->data.n_entries); ++ error(offset, "Bad n_entries: %"PRIu64, o->data.n_entries); + return -EBADMSG; + } + + if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) { +- error(offset, "bad object size (<= %zu): %"PRIu64, ++ error(offset, "Bad object size (<= %zu): %"PRIu64, + offsetof(DataObject, payload), + le64toh(o->object.size)); + return -EBADMSG; +@@ -171,7 +171,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload)); + + if (h1 != h2) { +- error(offset, "invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2); ++ error(offset, "Invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2); + return -EBADMSG; + } + +@@ -179,7 +179,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + !VALID64(o->data.next_field_offset) || + !VALID64(o->data.entry_offset) || + !VALID64(o->data.entry_array_offset)) { +- error(offset, "invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt, ++ error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt, + o->data.next_hash_offset, + o->data.next_field_offset, + o->data.entry_offset, +@@ -193,7 +193,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + case OBJECT_FIELD: + if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) { + error(offset, +- "bad field size (<= %zu): %"PRIu64, ++ "Bad field size (<= %zu): %"PRIu64, + offsetof(FieldObject, payload), + le64toh(o->object.size)); + return -EBADMSG; +@@ -202,7 +202,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (!VALID64(o->field.next_hash_offset) || + !VALID64(o->field.head_data_offset)) { + error(offset, +- "invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt, ++ "Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt, + o->field.next_hash_offset, + o->field.head_data_offset); + return -EBADMSG; +@@ -212,7 +212,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + case OBJECT_ENTRY: + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) { + error(offset, +- "bad entry size (<= %zu): %"PRIu64, ++ "Bad entry size (<= %zu): %"PRIu64, + offsetof(EntryObject, items), + le64toh(o->object.size)); + return -EBADMSG; +@@ -220,28 +220,28 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) { + error(offset, +- "invalid number items in entry: %"PRIu64, ++ "Invalid number items in entry: %"PRIu64, + (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem)); + return -EBADMSG; + } + + if (le64toh(o->entry.seqnum) <= 0) { + error(offset, +- "invalid entry seqnum: %"PRIx64, ++ "Invalid entry seqnum: %"PRIx64, + le64toh(o->entry.seqnum)); + return -EBADMSG; + } + + if (!VALID_REALTIME(le64toh(o->entry.realtime))) { + error(offset, +- "invalid entry realtime timestamp: %"PRIu64, ++ "Invalid entry realtime timestamp: %"PRIu64, + le64toh(o->entry.realtime)); + return -EBADMSG; + } + + if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) { + error(offset, +- "invalid entry monotonic timestamp: %"PRIu64, ++ "Invalid entry monotonic timestamp: %"PRIu64, + le64toh(o->entry.monotonic)); + return -EBADMSG; + } +@@ -250,7 +250,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (o->entry.items[i].object_offset == 0 || + !VALID64(o->entry.items[i].object_offset)) { + error(offset, +- "invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt, ++ "Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt, + i, journal_file_entry_n_items(o), + o->entry.items[i].object_offset); + return -EBADMSG; +@@ -264,7 +264,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 || + (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) { + error(offset, +- "invalid %s hash table size: %"PRIu64, ++ "Invalid %s hash table size: %"PRIu64, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + le64toh(o->object.size)); + return -EBADMSG; +@@ -274,7 +274,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (o->hash_table.items[i].head_hash_offset != 0 && + !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) { + error(offset, +- "invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt, ++ "Invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].head_hash_offset)); +@@ -283,7 +283,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (o->hash_table.items[i].tail_hash_offset != 0 && + !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) { + error(offset, +- "invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt, ++ "Invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].tail_hash_offset)); +@@ -293,7 +293,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if ((o->hash_table.items[i].head_hash_offset != 0) != + (o->hash_table.items[i].tail_hash_offset != 0)) { + error(offset, +- "invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt, ++ "Invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].head_hash_offset), +@@ -308,14 +308,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 || + (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) { + error(offset, +- "invalid object entry array size: %"PRIu64, ++ "Invalid object entry array size: %"PRIu64, + le64toh(o->object.size)); + return -EBADMSG; + } + + if (!VALID64(o->entry_array.next_entry_array_offset)) { + error(offset, +- "invalid object entry array next_entry_array_offset: "OFSfmt, ++ "Invalid object entry array next_entry_array_offset: "OFSfmt, + o->entry_array.next_entry_array_offset); + return -EBADMSG; + } +@@ -324,7 +324,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (le64toh(o->entry_array.items[i]) != 0 && + !VALID64(le64toh(o->entry_array.items[i]))) { + error(offset, +- "invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt, ++ "Invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt, + i, journal_file_entry_array_n_items(o), + le64toh(o->entry_array.items[i])); + return -EBADMSG; +@@ -335,14 +335,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + case OBJECT_TAG: + if (le64toh(o->object.size) != sizeof(TagObject)) { + error(offset, +- "invalid object tag size: %"PRIu64, ++ "Invalid object tag size: %"PRIu64, + le64toh(o->object.size)); + return -EBADMSG; + } + + if (!VALID_EPOCH(o->tag.epoch)) { + error(offset, +- "invalid object tag epoch: %"PRIu64, ++ "Invalid object tag epoch: %"PRIu64, + o->tag.epoch); + return -EBADMSG; + } +@@ -415,8 +415,7 @@ static int entry_points_to_data( + assert(entry_fd >= 0); + + if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) { +- error(data_p, +- "data object references invalid entry at "OFSfmt, entry_p); ++ error(data_p, "Data object references invalid entry at "OFSfmt, entry_p); + return -EBADMSG; + } + +@@ -432,8 +431,7 @@ static int entry_points_to_data( + } + + if (!found) { +- error(entry_p, +- "data object at "OFSfmt" not referenced by linked entry", data_p); ++ error(entry_p, "Data object at "OFSfmt" not referenced by linked entry", data_p); + return -EBADMSG; + } + +@@ -476,7 +474,7 @@ static int entry_points_to_data( + x = z; + } + +- error(entry_p, "entry object doesn't exist in main entry array"); ++ error(entry_p, "Entry object doesn't exist in main entry array"); + return -EBADMSG; + } + +@@ -506,9 +504,7 @@ static int verify_data( + + /* Entry array means at least two objects */ + if (a && n < 2) { +- error(p, +- "entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", +- a, n); ++ error(p, "Entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", a, n); + return -EBADMSG; + } + +@@ -528,12 +524,12 @@ static int verify_data( + uint64_t next, m, j; + + if (a == 0) { +- error(p, "array chain too short"); ++ error(p, "Array chain too short"); + return -EBADMSG; + } + + if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { +- error(p, "invalid array offset "OFSfmt, a); ++ error(p, "Invalid array offset "OFSfmt, a); + return -EBADMSG; + } + +@@ -543,8 +539,7 @@ static int verify_data( + + next = le64toh(o->entry_array.next_entry_array_offset); + if (next != 0 && next <= a) { +- error(p, "array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", +- a, next); ++ error(p, "Array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", a, next); + return -EBADMSG; + } + +@@ -553,7 +548,7 @@ static int verify_data( + + q = le64toh(o->entry_array.items[j]); + if (q <= last) { +- error(p, "data object's entry array not sorted"); ++ error(p, "Data object's entry array not sorted"); + return -EBADMSG; + } + last = q; +@@ -611,8 +606,7 @@ static int verify_hash_table( + uint64_t next; + + if (!contains_uint64(f->mmap, data_fd, n_data, p)) { +- error(p, "invalid data object at hash entry %"PRIu64" of %"PRIu64, +- i, n); ++ error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -622,14 +616,12 @@ static int verify_hash_table( + + next = le64toh(o->data.next_hash_offset); + if (next != 0 && next <= p) { +- error(p, "hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, +- i, n); ++ error(p, "Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + + if (le64toh(o->data.hash) % n != i) { +- error(p, "hash value mismatch in hash entry %"PRIu64" of %"PRIu64, +- i, n); ++ error(p, "Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -642,7 +634,7 @@ static int verify_hash_table( + } + + if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) { +- error(p, "tail hash pointer mismatch in hash table"); ++ error(p, "Tail hash pointer mismatch in hash table"); + return -EBADMSG; + } + } +@@ -703,16 +695,16 @@ static int verify_entry( + h = le64toh(o->entry.items[i].hash); + + if (!contains_uint64(f->mmap, data_fd, n_data, q)) { +- error(p, "invalid data object of entry"); +- return -EBADMSG; +- } ++ error(p, "Invalid data object of entry"); ++ return -EBADMSG; ++ } + + r = journal_file_move_to_object(f, OBJECT_DATA, q, &u); + if (r < 0) + return r; + + if (le64toh(u->data.hash) != h) { +- error(p, "hash mismatch for data object of entry"); ++ error(p, "Hash mismatch for data object of entry"); + return -EBADMSG; + } + +@@ -720,7 +712,7 @@ static int verify_entry( + if (r < 0) + return r; + if (r == 0) { +- error(p, "data object missing from hash table"); ++ error(p, "Data object missing from hash table"); + return -EBADMSG; + } + } +@@ -755,12 +747,12 @@ static int verify_entry_array( + draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec); + + if (a == 0) { +- error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n); ++ error(a, "Array chain too short at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + + if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { +- error(a, "invalid array %"PRIu64" of %"PRIu64, i, n); ++ error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -770,9 +762,7 @@ static int verify_entry_array( + + next = le64toh(o->entry_array.next_entry_array_offset); + if (next != 0 && next <= a) { +- error(a, +- "array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", +- i, n, next); ++ error(a, "Array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", i, n, next); + return -EBADMSG; + } + +@@ -782,15 +772,13 @@ static int verify_entry_array( + + p = le64toh(o->entry_array.items[j]); + if (p <= last) { +- error(a, "entry array not sorted at %"PRIu64" of %"PRIu64, +- i, n); ++ error(a, "Entry array not sorted at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + last = p; + + if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) { +- error(a, "invalid array entry at %"PRIu64" of %"PRIu64, +- i, n); ++ error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -878,7 +866,7 @@ int journal_file_verify( + + for (i = 0; i < sizeof(f->header->reserved); i++) + if (f->header->reserved[i] != 0) { +- error(offsetof(Header, reserved[i]), "reserved field is non-zero"); ++ error(offsetof(Header, reserved[i]), "Reserved field is non-zero"); + r = -EBADMSG; + goto fail; + } +@@ -897,12 +885,12 @@ int journal_file_verify( + + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); + if (r < 0) { +- error(p, "invalid object"); ++ error(p, "Invalid object"); + goto fail; + } + + if (p > le64toh(f->header->tail_object_offset)) { +- error(offsetof(Header, tail_object_offset), "invalid tail object pointer"); ++ error(offsetof(Header, tail_object_offset), "Invalid tail object pointer"); + r = -EBADMSG; + goto fail; + } +@@ -911,13 +899,13 @@ int journal_file_verify( + + r = journal_file_object_verify(f, p, o); + if (r < 0) { +- error(p, "invalid object contents: %s", strerror(-r)); ++ error(p, "Envalid object contents: %s", strerror(-r)); + goto fail; + } + + if ((o->object.flags & OBJECT_COMPRESSED_XZ) && + (o->object.flags & OBJECT_COMPRESSED_LZ4)) { +- error(p, "objected with double compression"); ++ error(p, "Objected with double compression"); + r = -EINVAL; + goto fail; + } +@@ -950,7 +938,7 @@ int journal_file_verify( + + case OBJECT_ENTRY: + if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) { +- error(p, "first entry before first tag"); ++ error(p, "First entry before first tag"); + r = -EBADMSG; + goto fail; + } +@@ -960,21 +948,21 @@ int journal_file_verify( + goto fail; + + if (le64toh(o->entry.realtime) < last_tag_realtime) { +- error(p, "older entry after newer tag"); ++ error(p, "Older entry after newer tag"); + r = -EBADMSG; + goto fail; + } + + if (!entry_seqnum_set && + le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) { +- error(p, "head entry sequence number incorrect"); ++ error(p, "Head entry sequence number incorrect"); + r = -EBADMSG; + goto fail; + } + + if (entry_seqnum_set && + entry_seqnum >= le64toh(o->entry.seqnum)) { +- error(p, "entry sequence number out of synchronization"); ++ error(p, "Entry sequence number out of synchronization"); + r = -EBADMSG; + goto fail; + } +@@ -985,7 +973,7 @@ int journal_file_verify( + if (entry_monotonic_set && + sd_id128_equal(entry_boot_id, o->entry.boot_id) && + entry_monotonic > le64toh(o->entry.monotonic)) { +- error(p, "entry timestamp out of synchronization"); ++ error(p, "Entry timestamp out of synchronization"); + r = -EBADMSG; + goto fail; + } +@@ -996,7 +984,7 @@ int journal_file_verify( + + if (!entry_realtime_set && + le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) { +- error(p, "head entry realtime timestamp incorrect"); ++ error(p, "Head entry realtime timestamp incorrect"); + r = -EBADMSG; + goto fail; + } +@@ -1009,7 +997,7 @@ int journal_file_verify( + + case OBJECT_DATA_HASH_TABLE: + if (n_data_hash_tables > 1) { +- error(p, "more than one data hash table"); ++ error(p, "More than one data hash table"); + r = -EBADMSG; + goto fail; + } +@@ -1026,14 +1014,14 @@ int journal_file_verify( + + case OBJECT_FIELD_HASH_TABLE: + if (n_field_hash_tables > 1) { +- error(p, "more than one field hash table"); ++ error(p, "More than one field hash table"); + r = -EBADMSG; + goto fail; + } + + if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) || + le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) { +- error(p, "header fields for field hash table invalid"); ++ error(p, "Header fields for field hash table invalid"); + r = -EBADMSG; + goto fail; + } +@@ -1048,7 +1036,7 @@ int journal_file_verify( + + if (p == le64toh(f->header->entry_array_offset)) { + if (found_main_entry_array) { +- error(p, "more than one main entry array"); ++ error(p, "More than one main entry array"); + r = -EBADMSG; + goto fail; + } +@@ -1061,19 +1049,19 @@ int journal_file_verify( + + case OBJECT_TAG: + if (!JOURNAL_HEADER_SEALED(f->header)) { +- error(p, "tag object in file without sealing"); ++ error(p, "Tag object in file without sealing"); + r = -EBADMSG; + goto fail; + } + + if (le64toh(o->tag.seqnum) != n_tags + 1) { +- error(p, "tag sequence number out of synchronization"); ++ error(p, "Tag sequence number out of synchronization"); + r = -EBADMSG; + goto fail; + } + + if (le64toh(o->tag.epoch) < last_epoch) { +- error(p, "epoch sequence out of synchronization"); ++ error(p, "Epoch sequence out of synchronization"); + r = -EBADMSG; + goto fail; + } +@@ -1082,7 +1070,7 @@ int journal_file_verify( + if (f->seal) { + uint64_t q, rt; + +- debug(p, "checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); ++ debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); + + rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec; + if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) { +@@ -1129,7 +1117,7 @@ int journal_file_verify( + goto fail; + + if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) { +- error(p, "tag failed verification"); ++ error(p, "Tag failed verification"); + r = -EBADMSG; + goto fail; + } +@@ -1160,60 +1148,60 @@ int journal_file_verify( + }; + + if (!found_last && le64toh(f->header->tail_object_offset) != 0) { +- error(le64toh(f->header->tail_object_offset), "tail object pointer dead"); ++ error(le64toh(f->header->tail_object_offset), "Tail object pointer dead"); + r = -EBADMSG; + goto fail; + } + + if (n_objects != le64toh(f->header->n_objects)) { +- error(offsetof(Header, n_objects), "object number mismatch"); ++ error(offsetof(Header, n_objects), "Object number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (n_entries != le64toh(f->header->n_entries)) { +- error(offsetof(Header, n_entries), "entry number mismatch"); ++ error(offsetof(Header, n_entries), "Entry number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_data) && + n_data != le64toh(f->header->n_data)) { +- error(offsetof(Header, n_data), "data number mismatch"); ++ error(offsetof(Header, n_data), "Data number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) && + n_fields != le64toh(f->header->n_fields)) { +- error(offsetof(Header, n_fields), "field number mismatch"); ++ error(offsetof(Header, n_fields), "Field number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) && + n_tags != le64toh(f->header->n_tags)) { +- error(offsetof(Header, n_tags), "tag number mismatch"); ++ error(offsetof(Header, n_tags), "Tag number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) && + n_entry_arrays != le64toh(f->header->n_entry_arrays)) { +- error(offsetof(Header, n_entry_arrays), "entry array number mismatch"); ++ error(offsetof(Header, n_entry_arrays), "Entry array number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) { +- error(0, "missing entry array"); ++ error(0, "Missing entry array"); + r = -EBADMSG; + goto fail; + } + + if (entry_seqnum_set && + entry_seqnum != le64toh(f->header->tail_entry_seqnum)) { +- error(offsetof(Header, tail_entry_seqnum), "invalid tail seqnum"); ++ error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum"); + r = -EBADMSG; + goto fail; + } +@@ -1221,13 +1209,13 @@ int journal_file_verify( + if (entry_monotonic_set && + (!sd_id128_equal(entry_boot_id, f->header->boot_id) || + entry_monotonic != le64toh(f->header->tail_entry_monotonic))) { +- error(0, "invalid tail monotonic timestamp"); ++ error(0, "Invalid tail monotonic timestamp"); + r = -EBADMSG; + goto fail; + } + + if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) { +- error(0, "invalid tail realtime timestamp"); ++ error(0, "Invalid tail realtime timestamp"); + r = -EBADMSG; + goto fail; + } diff --git a/SOURCES/0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch b/SOURCES/0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch new file mode 100644 index 00000000..40f3408c --- /dev/null +++ b/SOURCES/0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch @@ -0,0 +1,48 @@ +From 3045db86f9185f6de78f85099159330dfc1a0e9e Mon Sep 17 00:00:00 2001 +From: Stef Walter +Date: Fri, 14 Aug 2015 16:38:41 +0200 +Subject: [PATCH] journalctl: make sure 'journalctl -f -t unmatched' blocks + +Previously the following command: + +$ journalctl -f -t unmatchedtag12345 + +... would block when called with criteria that did not match any +journal lines. Once log lines appeared that matched the criteria +they were displayed. + +Commit 02ab86c732576a71179ce12e97d44c289833236d broke this +behavior and the journal was not followed, but the command +exits with '-- No entries --' displayed. + +This commit fixes the issue. + +More information downstream: + +https://bugzilla.redhat.com/show_bug.cgi?id=1253649 + +Cherry-picked from: c51e1a96359b3f4d374345593b11273df2132b93 +Related: #1350232 +--- + src/journal/journalctl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 904aae99e..2688d8b2e 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2142,8 +2142,12 @@ int main(int argc, char *argv[]) { + } + + if (r == 0) { +- printf("-- No entries --\n"); +- return EXIT_SUCCESS; ++ if (arg_follow) ++ need_seek = true; ++ else { ++ printf("-- No entries --\n"); ++ return EXIT_SUCCESS; ++ } + } + + diff --git a/SOURCES/0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch b/SOURCES/0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch new file mode 100644 index 00000000..2ecd6fea --- /dev/null +++ b/SOURCES/0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch @@ -0,0 +1,25 @@ +From 13f24902c7c1ba91d41bf4e8dd694cf01f876938 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Tue, 17 Nov 2015 06:06:52 +0000 +Subject: [PATCH] journalctl: don't print -- No entries -- in quiet mode + +Cherry-picked from: bfcb7c5f5333f9c3523b7027c2ad4c99e4494fb5 +Related: #1350232 +--- + src/journal/journalctl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 2688d8b2e..a38ce4b8f 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2145,7 +2145,8 @@ int main(int argc, char *argv[]) { + if (arg_follow) + need_seek = true; + else { +- printf("-- No entries --\n"); ++ if (!arg_quiet) ++ printf("-- No entries --\n"); + return EXIT_SUCCESS; + } + } diff --git a/SOURCES/0352-sd-event-expose-the-event-loop-iteration-counter-via.patch b/SOURCES/0352-sd-event-expose-the-event-loop-iteration-counter-via.patch new file mode 100644 index 00000000..92d3be42 --- /dev/null +++ b/SOURCES/0352-sd-event-expose-the-event-loop-iteration-counter-via.patch @@ -0,0 +1,69 @@ +From 8fe5d9138039aafd314340b12d6d586d657d53a7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 29 Jun 2016 19:03:26 -0700 +Subject: [PATCH] sd-event: expose the event loop iteration counter via + sd_event_get_iteration() + +This extends the existing event loop iteration counter to 64bit, and exposes it +via a new function sd_event_get_iteration(). This is helpful for cases like +issue #3612. After all, since we maintain the counter anyway, we might as well +expose it. + +(This also fixes an unrelated issue in the man page for sd_event_wait() where +micro and milliseconds got mixed up) + +Cherry-picked from: 7486322b99da5b4d2d00d35b310b035f936f7964 +Related: #1342173 +--- + src/libsystemd/sd-event/sd-event.c | 14 +++++++++++--- + src/systemd/sd-event.h | 1 + + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 1f1e6fe91..9d48e5a49 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -76,8 +76,8 @@ struct sd_event_source { + int64_t priority; + unsigned pending_index; + unsigned prepare_index; +- unsigned pending_iteration; +- unsigned prepare_iteration; ++ uint64_t pending_iteration; ++ uint64_t prepare_iteration; + + LIST_FIELDS(sd_event_source, sources); + +@@ -169,7 +169,7 @@ struct sd_event { + + pid_t original_pid; + +- unsigned iteration; ++ uint64_t iteration; + dual_timestamp timestamp; + usec_t timestamp_boottime; + int state; +@@ -2689,3 +2689,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) { + + return e->watchdog; + } ++ ++_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { ++ assert_return(e, -EINVAL); ++ assert_return(!event_pid_changed(e), -ECHILD); ++ ++ *ret = e->iteration; ++ return 0; ++} +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index 25a10f99a..4957f3a32 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -101,6 +101,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid); + int sd_event_get_exit_code(sd_event *e, int *code); + int sd_event_set_watchdog(sd_event *e, int b); + int sd_event_get_watchdog(sd_event *e); ++int sd_event_get_iteration(sd_event *e, uint64_t *ret); + + sd_event_source* sd_event_source_ref(sd_event_source *s); + sd_event_source* sd_event_source_unref(sd_event_source *s); diff --git a/SOURCES/0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch b/SOURCES/0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch new file mode 100644 index 00000000..745316b8 --- /dev/null +++ b/SOURCES/0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch @@ -0,0 +1,85 @@ +From 2a0feeb4252cbf1207f45e978fe7eb02bb0182ec Mon Sep 17 00:00:00 2001 +From: Kyle Walker +Date: Thu, 30 Jun 2016 15:12:18 -0400 +Subject: [PATCH] manager: Only invoke a single sigchld per unit within a + cleanup cycle + +By default, each iteration of manager_dispatch_sigchld() results in a unit level +sigchld event being invoked. For scope units, this results in a scope_sigchld_event() +which can seemingly stall for workloads that have a large number of PIDs within the +scope. The stall exhibits itself as a SIG_0 being initiated for each u->pids entry +as a result of pid_is_unwaited(). + +v2: +This patch resolves this condition by only paying to cost of a sigchld in the underlying +scope unit once per sigchld iteration. A new "sigchldgen" member resides within the +Unit struct. The Manager is incremented via the sd event loop, accessed via +sd_event_get_iteration, and the Unit member is set to the same value as the manager each +time that a sigchld event is invoked. If the Manager iteration value and Unit member +match, the sigchld event is not invoked for that iteration. + +Cherry-picked from: 36f20ae3b2975e44b6ef17e453ae06a289e9a122 +Resolves: #1342173 +--- + src/core/manager.c | 13 ++++++++++++- + src/core/unit.c | 1 + + src/core/unit.h | 3 +++ + 3 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index e5226a8a6..63693b93a 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1747,14 +1747,25 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + } + + static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { ++ uint64_t iteration; ++ + assert(m); + assert(u); + assert(si); + ++ sd_event_get_iteration(m->event, &iteration); ++ + log_unit_debug(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id); + + unit_unwatch_pid(u, si->si_pid); +- UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); ++ ++ if (UNIT_VTABLE(u)->sigchld_event) { ++ if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { ++ UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); ++ u->sigchldgen = iteration; ++ } else ++ log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); ++ } + } + + static int manager_dispatch_sigchld(Manager *m) { +diff --git a/src/core/unit.c b/src/core/unit.c +index d6ead7d67..d62135d87 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -94,6 +94,7 @@ Unit *unit_new(Manager *m, size_t size) { + u->unit_file_state = _UNIT_FILE_STATE_INVALID; + u->unit_file_preset = -1; + u->on_failure_job_mode = JOB_REPLACE; ++ u->sigchldgen = 0; + + return u; + } +diff --git a/src/core/unit.h b/src/core/unit.h +index 0eebc0b89..d93645777 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -167,6 +167,9 @@ struct Unit { + * process SIGCHLD for */ + Set *pids; + ++ /* Used in sigchld event invocation to avoid repeat events being invoked */ ++ uint64_t sigchldgen; ++ + /* Used during GC sweeps */ + unsigned gc_marker; + diff --git a/SOURCES/0354-manager-Fixing-a-debug-printf-formatting-mistake.patch b/SOURCES/0354-manager-Fixing-a-debug-printf-formatting-mistake.patch new file mode 100644 index 00000000..a207f776 --- /dev/null +++ b/SOURCES/0354-manager-Fixing-a-debug-printf-formatting-mistake.patch @@ -0,0 +1,28 @@ +From 1a6aae42bb3c4e524ded2da53afa303dd479b877 Mon Sep 17 00:00:00 2001 +From: Kyle Walker +Date: Fri, 1 Jul 2016 10:04:40 -0400 +Subject: [PATCH] manager: Fixing a debug printf formatting mistake + +A 'llu' formatting statement was used in a debugging printf statement +instead of a 'PRIu64'. Correcting that mistake here. + +Cherry-picked from: 72b0c3f59695239c51b719576f625e789bd00a66 +Related: #1342173 +--- + src/core/manager.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 63693b93a..d168777d2 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1764,7 +1764,8 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); + u->sigchldgen = iteration; + } else +- log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); ++ log_debug("%s already issued a sigchld this iteration %" PRIu64 ", skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); ++ + } + } + diff --git a/SOURCES/0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch b/SOURCES/0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch new file mode 100644 index 00000000..51f96e2d --- /dev/null +++ b/SOURCES/0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch @@ -0,0 +1,191 @@ +From 99074eebc911728a41167c1962231e11b5e3cddd Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 6 Nov 2015 11:06:52 +0100 +Subject: [PATCH] core: support IEC suffixes for RLIMIT stuff + +Let's make things more user-friendly and support for example + + LimitAS=16G + +rather than force users to always use LimitAS=16106127360. + +The change is relevant for options: + + [Default]Limit{FSIZE,DATA,STACK,CORE,RSS,AS,MEMLOCK,MSGQUEUE} + +The patch introduces config_parse_bytes_limit(), it's the same as +config_parse_limit() but uses parse_size() tu support the suffixes. + +Addresses: https://github.com/systemd/systemd/issues/1772 + +Cherry-picked from: 412ea7a936ebaa5342a4c2abf48b9e408e6ba5dc +Related: #1351415 +--- + man/systemd-system.conf.xml | 6 +++-- + man/systemd.exec.xml | 4 +++- + src/core/load-fragment-gperf.gperf.m4 | 16 ++++++------- + src/core/load-fragment.c | 43 +++++++++++++++++++++++++++++++++++ + src/core/load-fragment.h | 1 + + src/core/main.c | 16 ++++++------- + 6 files changed, 67 insertions(+), 19 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index ca25c93a1..b7d9cdee0 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -327,8 +327,10 @@ + resource limits for units. See + setrlimit2 + for details. Use the string infinity to +- configure no limit on a specific resource. These settings may +- be overridden in individual units using the corresponding ++ configure no limit on a specific resource. The multiplicative suffixes ++ K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for ++ resource limits measured in bytes (e.g. DefaultLimitAS=16G). These ++ settings may be overridden in individual units using the corresponding + LimitXXX= directives. Note that these resource limits are only + defaults for units, they are not applied to PID 1 + itself. +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 6af7c7ae5..25aea1655 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -559,7 +559,9 @@ + of various resources for executed processes. See + setrlimit2 + for details. Use the string infinity to +- configure no limit on a specific resource. ++ configure no limit on a specific resource. The multiplicative suffixes ++ K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for ++ resource limits measured in bytes (e.g. LimitAS=16G). + + + Limit directives and their equivalent with ulimit +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 85d979751..c3461a0a6 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -59,18 +59,18 @@ $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CO + $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 + $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') + $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +-$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +-$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +-$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +-$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +-$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) ++$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) ++$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) ++$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) ++$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) ++$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) + $1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) +-$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) ++$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) + $1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) +-$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) ++$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) + $1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) + $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) +-$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) ++$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) + $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) + $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) + $1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index b188ec99d..dbb45b20f 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1119,6 +1119,49 @@ int config_parse_limit(const char *unit, + return 0; + } + ++int config_parse_bytes_limit(const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ struct rlimit **rl = data; ++ uint64_t bytes; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ rl += ltype; ++ ++ if (streq(rvalue, "infinity")) ++ bytes = (uint64_t) RLIM_INFINITY; ++ else { ++ int r; ++ ++ r = parse_size(rvalue, 1024, &bytes); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); ++ return 0; ++ } ++ } ++ ++ if (!*rl) { ++ *rl = new(struct rlimit, 1); ++ if (!*rl) ++ return log_oom(); ++ } ++ ++ (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes; ++ return 0; ++} ++ + #ifdef HAVE_SYSV_COMPAT + int config_parse_sysv_priority(const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index ce10d03c3..2d509d0cb 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -56,6 +56,7 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig + int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/core/main.c b/src/core/main.c +index 2aec40b0b..60ea36c3c 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -655,18 +655,18 @@ static int parse_config_file(void) { + { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, + { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, + { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] }, +- { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, +- { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, +- { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, +- { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, +- { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, ++ { "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, ++ { "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, ++ { "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, ++ { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, ++ { "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, + { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] }, +- { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, ++ { "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, + { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] }, +- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, ++ { "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, + { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] }, + { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] }, +- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, ++ { "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, + { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, + { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] }, + { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, diff --git a/SOURCES/0356-core-accept-time-units-for-time-based-resource-limit.patch b/SOURCES/0356-core-accept-time-units-for-time-based-resource-limit.patch new file mode 100644 index 00000000..3abafdcb --- /dev/null +++ b/SOURCES/0356-core-accept-time-units-for-time-based-resource-limit.patch @@ -0,0 +1,416 @@ +From 128ef85392f68fa32650deab12d6cd2e01ad52cf Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 10 Nov 2015 16:52:52 +0100 +Subject: [PATCH] core: accept time units for time-based resource limits + +Let's make sure "LimitCPU=30min" can be parsed properly, following the +usual logic how we parse time values. Similar for LimitRTTIME=. + +While we are at it, extend a bit on the man page section about resource +limits. + +Fixes: #1772 + +Cherry-picked from: a4c1800284e3546bbfab2dc19eb59bcb91c4a2ca +Related: #1351415 +--- + man/systemd.exec.xml | 86 ++++++++++++++++++++++------- + src/core/load-fragment-gperf.gperf.m4 | 4 +- + src/core/load-fragment.c | 101 ++++++++++++++++++++++++++++++++++ + src/core/load-fragment.h | 2 + + src/test/test-unit-file.c | 61 ++++++++++++++++++++ + 5 files changed, 231 insertions(+), 23 deletions(-) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 25aea1655..cfdcc3d17 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -559,90 +559,133 @@ + of various resources for executed processes. See + setrlimit2 + for details. Use the string infinity to +- configure no limit on a specific resource. The multiplicative suffixes +- K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for +- resource limits measured in bytes (e.g. LimitAS=16G). ++ configure no limit on a specific resource. The multiplicative ++ suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E ++ may be used for resource limits measured in bytes ++ (e.g. LimitAS=16G). For the limits referring to time values, ++ the usual time units ms, s, min, h and so on may be used (see ++ systemd.time7 ++ for details). Note that if no time unit is specified for ++ LimitCPU= the default unit of seconds is ++ implied, while for LimitRTTIME= the default ++ unit of microseconds is implied. Also, note that the effective ++ granularity of the limits might influence their ++ enforcement. For example, time limits specified for ++ LimitCPU= will be rounded up implicitly to ++ multiples of 1s. ++ ++ Note that most process resource limits configured with ++ these options are per-process, and processes may fork in order ++ to acquire a new set of resources that are accounted ++ independently of the original process, and may thus escape ++ limits set. Also note that LimitRSS= is not ++ implemented on Linux, and setting it has no effect. Often it ++ is advisable to prefer the resource controls listed in ++ systemd.resource-control5 ++ over these per-process limits, as they apply to services as a ++ whole, may be altered dynamically at runtime, and are ++ generally more expressive. For example, ++ MemoryLimit= is a more powerful (and ++ working) replacement for LimitRSS=. + +
+ Limit directives and their equivalent with ulimit + +- ++ + + ++ + + + Directive + ulimit equivalent ++ Unit + + + + +- LimitCPU ++ LimitCPU= + ulimit -t ++ Seconds + + +- LimitFSIZE ++ LimitFSIZE= + ulimit -f ++ Bytes + + +- LimitDATA ++ LimitDATA= + ulimit -d ++ Bytes + + +- LimitSTACK ++ LimitSTACK= + ulimit -s ++ Bytes + + +- LimitCORE ++ LimitCORE= + ulimit -c ++ Bytes + + +- LimitRSS ++ LimitRSS= + ulimit -m ++ Bytes + + +- LimitNOFILE ++ LimitNOFILE= + ulimit -n ++ Number of File Descriptors + + +- LimitAS ++ LimitAS= + ulimit -v ++ Bytes + + +- LimitNPROC ++ LimitNPROC= + ulimit -u ++ Number of Processes + + +- LimitMEMLOCK ++ LimitMEMLOCK= + ulimit -l ++ Bytes + + +- LimitLOCKS ++ LimitLOCKS= + ulimit -x ++ Number of Locks + + +- LimitSIGPENDING ++ LimitSIGPENDING= + ulimit -i ++ Number of Queued Signals + + +- LimitMSGQUEUE ++ LimitMSGQUEUE= + ulimit -q ++ Bytes + + +- LimitNICE ++ LimitNICE= + ulimit -e ++ Nice Level + + +- LimitRTPRIO ++ LimitRTPRIO= + ulimit -r ++ Realtime Priority + + +- LimitRTTIME ++ LimitRTTIME= + No equivalent ++ Microseconds + + + +-
++ +
+ + +@@ -1266,6 +1309,7 @@ + systemd.mount5, + systemd.kill5, + systemd.resource-control5, ++ systemd.time7, + systemd.directives7, + tmpfiles.d5, + exec3 +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index c3461a0a6..ce1397c7e 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -58,7 +58,7 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0, + $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 + $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 + $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') +-$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) ++$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) + $1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) + $1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) + $1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +@@ -73,7 +73,7 @@ $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGP + $1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) + $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) + $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) +-$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) ++$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) + $1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) + $1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs) + $1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index dbb45b20f..8afe9d7e8 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1162,6 +1162,107 @@ int config_parse_bytes_limit(const char *unit, + return 0; + } + ++int config_parse_sec_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ struct rlimit **rl = data; ++ rlim_t seconds; ++ int r; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ rl += ltype; ++ ++ if (streq(rvalue, "infinity")) ++ seconds = RLIM_INFINITY; ++ else { ++ usec_t t; ++ ++ r = parse_sec(rvalue, &t); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); ++ return 0; ++ } ++ ++ if (t == USEC_INFINITY) ++ seconds = RLIM_INFINITY; ++ else ++ seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); ++ } ++ ++ if (!*rl) { ++ *rl = new(struct rlimit, 1); ++ if (!*rl) ++ return log_oom(); ++ } ++ ++ (*rl)->rlim_cur = (*rl)->rlim_max = seconds; ++ return 0; ++} ++ ++ ++int config_parse_usec_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ struct rlimit **rl = data; ++ rlim_t useconds; ++ int r; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ rl += ltype; ++ ++ if (streq(rvalue, "infinity")) ++ useconds = RLIM_INFINITY; ++ else { ++ usec_t t; ++ ++ r = parse_time(rvalue, &t, 1); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); ++ return 0; ++ } ++ ++ if (t == USEC_INFINITY) ++ useconds = RLIM_INFINITY; ++ else ++ useconds = (rlim_t) t; ++ } ++ ++ if (!*rl) { ++ *rl = new(struct rlimit, 1); ++ if (!*rl) ++ return log_oom(); ++ } ++ ++ (*rl)->rlim_cur = (*rl)->rlim_max = useconds; ++ return 0; ++} ++ + #ifdef HAVE_SYSV_COMPAT + int config_parse_sysv_priority(const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 2d509d0cb..359794d0a 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -57,6 +57,8 @@ int config_parse_exec_secure_bits(const char *unit, const char *filename, unsign + int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 550098332..d15173796 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -545,6 +545,66 @@ static void test_install_printf(void) { + expect(i4, "%U", "0"); + } + ++ ++static void test_config_parse_rlimit(void) { ++ struct rlimit * rl[_RLIMIT_MAX] = {}; ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); ++ ++ rl[RLIMIT_NOFILE] = free(rl[RLIMIT_NOFILE]); ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ rl[RLIMIT_CPU] = free(rl[RLIMIT_CPU]); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ rl[RLIMIT_RTTIME] = free(rl[RLIMIT_RTTIME]); ++} ++ + int main(int argc, char *argv[]) { + int r; + +@@ -553,6 +613,7 @@ int main(int argc, char *argv[]) { + + r = test_unit_file_get_set(); + test_config_parse_exec(); ++ test_config_parse_rlimit(); + test_load_env_file_1(); + test_load_env_file_2(); + test_load_env_file_3(); diff --git a/SOURCES/0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch b/SOURCES/0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch new file mode 100644 index 00000000..c1a61311 --- /dev/null +++ b/SOURCES/0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch @@ -0,0 +1,214 @@ +From 8afe4259a8add0d042950015d34afc95a221ad96 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 6 Jul 2016 13:47:07 +0200 +Subject: [PATCH] time-util: add parse_time(), which is like parse_sec() but + allows specification of default time unit if none is specified +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is useful if we want to parse RLIMIT_RTTIME values where the common +UNIX syntax is without any units but refers to a non-second unit (µs in +this case), but where we want to allow specification of units. + +Cherry-picked from: 519cffec890510f817740d07355e911b10c203b7 +Related: #1351415 +--- + src/shared/calendarspec.c | 4 ++-- + src/shared/time-util.c | 34 ++++++++++++++++++++++------------ + src/shared/time-util.h | 1 + + src/test/test-time.c | 23 +++++++++++++++++++++++ + src/test/test-unit-file.c | 6 +++--- + 5 files changed, 51 insertions(+), 17 deletions(-) + +diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c +index 2fde3e107..abbf0261e 100644 +--- a/src/shared/calendarspec.c ++++ b/src/shared/calendarspec.c +@@ -556,7 +556,7 @@ static int parse_date(const char **p, CalendarSpec *c) { + return -EINVAL; + } + +-static int parse_time(const char **p, CalendarSpec *c) { ++static int parse_calendar_time(const char **p, CalendarSpec *c) { + CalendarComponent *h = NULL, *m = NULL, *s = NULL; + const char *t; + int r; +@@ -789,7 +789,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { + if (r < 0) + goto fail; + +- r = parse_time(&p, c); ++ r = parse_calendar_time(&p, c); + if (r < 0) + goto fail; + +diff --git a/src/shared/time-util.c b/src/shared/time-util.c +index 1c36c577c..c001f52de 100644 +--- a/src/shared/time-util.c ++++ b/src/shared/time-util.c +@@ -613,7 +613,8 @@ finish: + return 0; + } + +-int parse_sec(const char *t, usec_t *usec) { ++int parse_time(const char *t, usec_t *usec, usec_t default_unit) { ++ + static const struct { + const char *suffix; + usec_t usec; +@@ -645,7 +646,6 @@ int parse_sec(const char *t, usec_t *usec) { + { "y", USEC_PER_YEAR }, + { "usec", 1ULL }, + { "us", 1ULL }, +- { "", USEC_PER_SEC }, /* default is sec */ + }; + + const char *p, *s; +@@ -654,6 +654,7 @@ int parse_sec(const char *t, usec_t *usec) { + + assert(t); + assert(usec); ++ assert(default_unit > 0); + + p = t; + +@@ -672,6 +673,7 @@ int parse_sec(const char *t, usec_t *usec) { + long long l, z = 0; + char *e; + unsigned i, n = 0; ++ usec_t multiplier, k; + + p += strspn(p, WHITESPACE); + +@@ -714,21 +716,24 @@ int parse_sec(const char *t, usec_t *usec) { + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { +- usec_t k = (usec_t) z * table[i].usec; +- +- for (; n > 0; n--) +- k /= 10; +- +- r += (usec_t) l * table[i].usec + k; ++ multiplier = table[i].usec; + p = e + strlen(table[i].suffix); +- +- something = true; + break; + } + +- if (i >= ELEMENTSOF(table)) +- return -EINVAL; ++ if (i >= ELEMENTSOF(table)) { ++ multiplier = default_unit; ++ p = e; ++ } ++ ++ something = true; ++ ++ k = (usec_t) z * multiplier; ++ ++ for (; n > 0; n--) ++ k /= 10; + ++ r += (usec_t) l * multiplier + k; + } + + *usec = r; +@@ -736,6 +741,11 @@ int parse_sec(const char *t, usec_t *usec) { + return 0; + } + ++ ++int parse_sec(const char *t, usec_t *usec) { ++ return parse_time(t, usec, USEC_PER_SEC); ++} ++ + int parse_nsec(const char *t, nsec_t *nsec) { + static const struct { + const char *suffix; +diff --git a/src/shared/time-util.h b/src/shared/time-util.h +index fca8a4db9..f2789142f 100644 +--- a/src/shared/time-util.h ++++ b/src/shared/time-util.h +@@ -99,6 +99,7 @@ void dual_timestamp_deserialize(const char *value, dual_timestamp *t); + int parse_timestamp(const char *t, usec_t *usec); + + int parse_sec(const char *t, usec_t *usec); ++int parse_time(const char *t, usec_t *usec, usec_t default_unit); + int parse_nsec(const char *t, nsec_t *nsec); + + bool ntp_synced(void); +diff --git a/src/test/test-time.c b/src/test/test-time.c +index 3840fff06..820e4aaee 100644 +--- a/src/test/test-time.c ++++ b/src/test/test-time.c +@@ -57,6 +57,28 @@ static void test_parse_sec(void) { + assert_se(parse_sec(".3 infinity", &u) < 0); + } + ++static void test_parse_time(void) { ++ usec_t u; ++ ++ assert_se(parse_time("5", &u, 1) >= 0); ++ assert_se(u == 5); ++ ++ assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0); ++ assert_se(u == 5 * USEC_PER_MSEC); ++ ++ assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++ ++ assert_se(parse_time("5s", &u, 1) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++ ++ assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++ ++ assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++} ++ + static void test_parse_nsec(void) { + nsec_t u; + +@@ -161,6 +183,7 @@ static void test_get_timezones(void) { + + int main(int argc, char *argv[]) { + test_parse_sec(); ++ test_parse_time(); + test_parse_nsec(); + test_format_timespan(1); + test_format_timespan(USEC_PER_MSEC); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index d15173796..87c81ccd7 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -559,7 +559,7 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + +- rl[RLIMIT_NOFILE] = free(rl[RLIMIT_NOFILE]); ++ free(rl[RLIMIT_NOFILE]); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); +@@ -580,7 +580,7 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + +- rl[RLIMIT_CPU] = free(rl[RLIMIT_CPU]); ++ free(rl[RLIMIT_CPU]); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); +@@ -602,7 +602,7 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + +- rl[RLIMIT_RTTIME] = free(rl[RLIMIT_RTTIME]); ++ free(rl[RLIMIT_RTTIME]); + } + + int main(int argc, char *argv[]) { diff --git a/SOURCES/0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch b/SOURCES/0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch new file mode 100644 index 00000000..c941afea --- /dev/null +++ b/SOURCES/0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch @@ -0,0 +1,1003 @@ +From 81a95ec724b7b874f850cb0f32f1981ccc4fb062 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 20 Nov 2015 12:54:10 +0100 +Subject: [PATCH] core: support ranges for RLIMIT options + +The new parser supports: + + - specify both limits to the same value + - specify both limits + +the size or time specific suffixes are supported, for example + + LimitRTTIME=1sec + LimitAS=4G:16G + +The patch introduces parse_rlimit_range() and rlim type (size, sec, +usec, etc.) specific parsers. No code is duplicated now. + +The patch also sync docs for DefaultLimitXXX= and LimitXXX=. + +References: https://github.com/systemd/systemd/issues/1769 + +Cherry-picked from: 91518d20ddf0376808544576d0ef0883cedc67d4 +Resolves: #1351415 +--- + man/systemd-system.conf.xml | 27 ++- + man/systemd.exec.xml | 5 +- + src/core/load-fragment.c | 243 ++++++++++++----------- + src/shared/util.c | 467 ++++++++++++++++++++++++++++++++++++++++++++ + src/shared/util.h | 14 ++ + src/test/test-unit-file.c | 31 +++ + 6 files changed, 667 insertions(+), 120 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index b7d9cdee0..39d19bc71 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -326,13 +326,26 @@ + These settings control various default + resource limits for units. See + setrlimit2 +- for details. Use the string infinity to +- configure no limit on a specific resource. The multiplicative suffixes +- K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for +- resource limits measured in bytes (e.g. DefaultLimitAS=16G). These +- settings may be overridden in individual units using the corresponding +- LimitXXX= directives. Note that these resource limits are only +- defaults for units, they are not applied to PID 1 ++ for details. The resource limit is possible to specify in two formats, ++ to set soft and hard limits to the same value, ++ or to set both limits individually (e.g. DefaultLimitAS=4G:16G). ++ Use the string infinity to ++ configure no limit on a specific resource. The multiplicative ++ suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E ++ may be used for resource limits measured in bytes ++ (e.g. DefaultLimitAS=16G). For the limits referring to time values, ++ the usual time units ms, s, min, h and so on may be used (see ++ systemd.time7 ++ for details). Note that if no time unit is specified for ++ DefaultLimitCPU= the default unit of seconds is ++ implied, while for DefaultLimitRTTIME= the default ++ unit of microseconds is implied. Also, note that the effective ++ granularity of the limits might influence their ++ enforcement. For example, time limits specified for ++ DefaultLimitCPU= will be rounded up implicitly to ++ multiples of 1s. These settings may be overridden in individual units ++ using the corresponding LimitXXX= directives. Note that these resource ++ limits are only defaults for units, they are not applied to PID 1 + itself. + + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index cfdcc3d17..0cd469cd9 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -558,7 +558,10 @@ + These settings set both soft and hard limits + of various resources for executed processes. See + setrlimit2 +- for details. Use the string infinity to ++ for details. The resource limit is possible to specify in two formats, ++ to set soft and hard limits to the same value, ++ or to set both limits individually (e.g. LimitAS=4G:16G). ++ Use the string infinity to + configure no limit on a specific resource. The multiplicative + suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E + may be used for resource limits measured in bytes +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 8afe9d7e8..d307f1c74 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1075,81 +1075,108 @@ int config_parse_bounding_set(const char *unit, + return 0; + } + +-int config_parse_limit(const char *unit, +- const char *filename, +- unsigned line, +- const char *section, +- unsigned section_line, +- const char *lvalue, +- int ltype, +- const char *rvalue, +- void *data, +- void *userdata) { + +- struct rlimit **rl = data; +- unsigned long long u; ++static int rlim_parse_u64(const char *val, rlim_t *res) { ++ int r = 0; + +- assert(filename); +- assert(lvalue); +- assert(rvalue); +- assert(data); ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; ++ else { ++ uint64_t u; + +- rl += ltype; ++ /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */ ++ assert_cc(sizeof(rlim_t) == sizeof(uint64_t)); ++ ++ r = safe_atou64(val, &u); ++ if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) ++ r = -ERANGE; ++ if (r == 0) ++ *res = (rlim_t) u; ++ } ++ return r; ++} + +- if (streq(rvalue, "infinity")) +- u = (unsigned long long) RLIM_INFINITY; ++static int rlim_parse_size(const char *val, rlim_t *res) { ++ int r = 0; ++ ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; + else { +- int r; ++ off_t u; + +- r = safe_atollu(rvalue, &u); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, -r, +- "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++ r = parse_size(val, 1024, &u); ++ if (r >= 0 && u >= (off_t) RLIM_INFINITY) ++ r = -ERANGE; ++ if (r == 0) ++ *res = (rlim_t) u; + } ++ return r; ++} + +- if (!*rl) { +- *rl = new(struct rlimit, 1); +- if (!*rl) +- return log_oom(); +- } ++static int rlim_parse_sec(const char *val, rlim_t *res) { ++ int r = 0; + +- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u; +- return 0; ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; ++ else { ++ usec_t t; ++ ++ r = parse_sec(val, &t); ++ if (r < 0) ++ return r; ++ if (t == USEC_INFINITY) ++ *res = RLIM_INFINITY; ++ else ++ *res = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); ++ ++ } ++ return r; + } + +-int config_parse_bytes_limit(const char *unit, +- const char *filename, +- unsigned line, +- const char *section, +- unsigned section_line, +- const char *lvalue, +- int ltype, +- const char *rvalue, +- void *data, +- void *userdata) { ++static int rlim_parse_usec(const char *val, rlim_t *res) { ++ int r = 0; + +- struct rlimit **rl = data; +- uint64_t bytes; ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; ++ else { ++ usec_t t; + +- assert(filename); +- assert(lvalue); +- assert(rvalue); +- assert(data); ++ r = parse_time(val, &t, 1); ++ if (r < 0) ++ return r; ++ if (t == USEC_INFINITY) ++ *res = RLIM_INFINITY; ++ else ++ *res = (rlim_t) t; ++ } ++ return r; ++} + +- rl += ltype; ++static int parse_rlimit_range( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *value, ++ struct rlimit **rl, ++ int (*rlim_parser)(const char *, rlim_t *)) { + +- if (streq(rvalue, "infinity")) +- bytes = (uint64_t) RLIM_INFINITY; +- else { +- int r; ++ rlim_t soft, hard; ++ _cleanup_free_ char *sword = NULL, *hword = NULL; ++ int nwords, r; + +- r = parse_size(rvalue, 1024, &bytes); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++ assert(value); ++ ++ /* or */ ++ nwords = extract_many_words(&value, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &sword, &hword, NULL); ++ r = nwords < 0 ? nwords : nwords == 0 ? -EINVAL : 0; ++ ++ if (r == 0) ++ r = rlim_parser(sword, &soft); ++ if (r == 0 && nwords == 2) ++ r = rlim_parser(hword, &hard); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", value); ++ return 0; + } + + if (!*rl) { +@@ -1157,12 +1184,12 @@ int config_parse_bytes_limit(const char *unit, + if (!*rl) + return log_oom(); + } +- +- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes; ++ (*rl)->rlim_cur = soft; ++ (*rl)->rlim_max = nwords == 2 ? hard : soft; + return 0; + } + +-int config_parse_sec_limit( ++int config_parse_limit( + const char *unit, + const char *filename, + unsigned line, +@@ -1175,8 +1202,6 @@ int config_parse_sec_limit( + void *userdata) { + + struct rlimit **rl = data; +- rlim_t seconds; +- int r; + + assert(filename); + assert(lvalue); +@@ -1184,36 +1209,33 @@ int config_parse_sec_limit( + assert(data); + + rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_u64); ++} + +- if (streq(rvalue, "infinity")) +- seconds = RLIM_INFINITY; +- else { +- usec_t t; +- +- r = parse_sec(rvalue, &t); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++int config_parse_bytes_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { + +- if (t == USEC_INFINITY) +- seconds = RLIM_INFINITY; +- else +- seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); +- } ++ struct rlimit **rl = data; + +- if (!*rl) { +- *rl = new(struct rlimit, 1); +- if (!*rl) +- return log_oom(); +- } ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); + +- (*rl)->rlim_cur = (*rl)->rlim_max = seconds; +- return 0; ++ rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_size); + } + +- +-int config_parse_usec_limit( ++int config_parse_sec_limit( + const char *unit, + const char *filename, + unsigned line, +@@ -1226,8 +1248,6 @@ int config_parse_usec_limit( + void *userdata) { + + struct rlimit **rl = data; +- rlim_t useconds; +- int r; + + assert(filename); + assert(lvalue); +@@ -1235,34 +1255,33 @@ int config_parse_usec_limit( + assert(data); + + rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_sec); ++} + +- if (streq(rvalue, "infinity")) +- useconds = RLIM_INFINITY; +- else { +- usec_t t; +- +- r = parse_time(rvalue, &t, 1); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++int config_parse_usec_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { + +- if (t == USEC_INFINITY) +- useconds = RLIM_INFINITY; +- else +- useconds = (rlim_t) t; +- } ++ struct rlimit **rl = data; + +- if (!*rl) { +- *rl = new(struct rlimit, 1); +- if (!*rl) +- return log_oom(); +- } ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); + +- (*rl)->rlim_cur = (*rl)->rlim_max = useconds; +- return 0; ++ rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec); + } + ++ + #ifdef HAVE_SYSV_COMPAT + int config_parse_sysv_priority(const char *unit, + const char *filename, +diff --git a/src/shared/util.c b/src/shared/util.c +index 036677eb4..f75ed9dd4 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -93,6 +93,7 @@ + #include "virt.h" + #include "def.h" + #include "sparse-endian.h" ++#include "conf-parser.h" + + int saved_argc = 0; + char **saved_argv = NULL; +@@ -100,6 +101,8 @@ char **saved_argv = NULL; + static volatile unsigned cached_columns = 0; + static volatile unsigned cached_lines = 0; + ++bool unichar_is_valid(int32_t ch); ++ + size_t page_size(void) { + static thread_local size_t pgsz = 0; + long r; +@@ -1365,6 +1368,207 @@ char *cescape(const char *s) { + return r; + } + ++bool unichar_is_valid(int32_t ch) { ++ ++ if (ch >= 0x110000) /* End of unicode space */ ++ return false; ++ if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ ++ return false; ++ if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ ++ return false; ++ if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ ++ return false; ++ ++ return true; ++} ++ ++int cunescape_one(const char *p, size_t length, int32_t *ret, bool *eight_bit) { ++ int r = 1; ++ ++ assert(p); ++ assert(*p); ++ assert(ret); ++ ++ /* Unescapes C style. Returns the unescaped character in ret. ++ * Sets *eight_bit to true if the escaped sequence either fits in ++ * one byte in UTF-8 or is a non-unicode literal byte and should ++ * instead be copied directly. ++ */ ++ ++ if (length != (size_t) -1 && length < 1) ++ return -EINVAL; ++ ++ switch (p[0]) { ++ ++ case 'a': ++ *ret = '\a'; ++ break; ++ case 'b': ++ *ret = '\b'; ++ break; ++ case 'f': ++ *ret = '\f'; ++ break; ++ case 'n': ++ *ret = '\n'; ++ break; ++ case 'r': ++ *ret = '\r'; ++ break; ++ case 't': ++ *ret = '\t'; ++ break; ++ case 'v': ++ *ret = '\v'; ++ break; ++ case '\\': ++ *ret = '\\'; ++ break; ++ case '"': ++ *ret = '"'; ++ break; ++ case '\'': ++ *ret = '\''; ++ break; ++ ++ case 's': ++ /* This is an extension of the XDG syntax files */ ++ *ret = ' '; ++ break; ++ ++ case 'x': { ++ /* hexadecimal encoding */ ++ int a, b; ++ ++ if (length != (size_t) -1 && length < 3) ++ return -EINVAL; ++ ++ a = unhexchar(p[1]); ++ if (a < 0) ++ return -EINVAL; ++ ++ b = unhexchar(p[2]); ++ if (b < 0) ++ return -EINVAL; ++ ++ /* Don't allow NUL bytes */ ++ if (a == 0 && b == 0) ++ return -EINVAL; ++ ++ *ret = (a << 4U) | b; ++ *eight_bit = true; ++ r = 3; ++ break; ++ } ++ ++ case 'u': { ++ /* C++11 style 16bit unicode */ ++ ++ int a[4]; ++ unsigned i; ++ uint32_t c; ++ ++ if (length != (size_t) -1 && length < 5) ++ return -EINVAL; ++ ++ for (i = 0; i < 4; i++) { ++ a[i] = unhexchar(p[1 + i]); ++ if (a[i] < 0) ++ return a[i]; ++ } ++ ++ c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; ++ ++ /* Don't allow 0 chars */ ++ if (c == 0) ++ return -EINVAL; ++ ++ *ret = c; ++ r = 5; ++ break; ++ } ++ ++ case 'U': { ++ /* C++11 style 32bit unicode */ ++ ++ int a[8]; ++ unsigned i; ++ int32_t c; ++ ++ if (length != (size_t) -1 && length < 9) ++ return -EINVAL; ++ ++ for (i = 0; i < 8; i++) { ++ a[i] = unhexchar(p[1 + i]); ++ if (a[i] < 0) ++ return a[i]; ++ } ++ ++ c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | ++ ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; ++ ++ /* Don't allow 0 chars */ ++ if (c == 0) ++ return -EINVAL; ++ ++ /* Don't allow invalid code points */ ++ if (!unichar_is_valid(c)) ++ return -EINVAL; ++ ++ *ret = c; ++ r = 9; ++ break; ++ } ++ ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': { ++ /* octal encoding */ ++ int a, b, c; ++ int32_t m; ++ ++ if (length != (size_t) -1 && length < 3) ++ return -EINVAL; ++ ++ a = unoctchar(p[0]); ++ if (a < 0) ++ return -EINVAL; ++ ++ b = unoctchar(p[1]); ++ if (b < 0) ++ return -EINVAL; ++ ++ c = unoctchar(p[2]); ++ if (c < 0) ++ return -EINVAL; ++ ++ /* don't allow NUL bytes */ ++ if (a == 0 && b == 0 && c == 0) ++ return -EINVAL; ++ ++ /* Don't allow bytes above 255 */ ++ m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; ++ if (m > 255) ++ return -EINVAL; ++ ++ *ret = m; ++ *eight_bit = true; ++ r = 3; ++ break; ++ } ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return r; ++} ++ + char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) { + char *r, *t; + const char *f; +@@ -8207,3 +8411,266 @@ bool colors_enabled(void) { + + return parse_boolean(colors) != 0; + } ++ ++int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { ++ _cleanup_free_ char *s = NULL; ++ size_t allocated = 0, sz = 0; ++ char c; ++ int r; ++ ++ char quote = 0; /* 0 or ' or " */ ++ bool backslash = false; /* whether we've just seen a backslash */ ++ ++ assert(p); ++ assert(ret); ++ ++ /* Bail early if called after last value or with no input */ ++ if (!*p) ++ goto finish_force_terminate; ++ c = **p; ++ ++ if (!separators) ++ separators = WHITESPACE; ++ ++ /* Parses the first word of a string, and returns it in ++ * *ret. Removes all quotes in the process. When parsing fails ++ * (because of an uneven number of quotes or similar), leaves ++ * the pointer *p at the first invalid character. */ ++ ++ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) ++ if (!GREEDY_REALLOC(s, allocated, sz+1)) ++ return -ENOMEM; ++ ++ for (;; (*p)++, c = **p) { ++ if (c == 0) ++ goto finish_force_terminate; ++ else if (strchr(separators, c)) { ++ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { ++ (*p)++; ++ goto finish_force_next; ++ } ++ } else { ++ /* We found a non-blank character, so we will always ++ * want to return a string (even if it is empty), ++ * allocate it here. */ ++ if (!GREEDY_REALLOC(s, allocated, sz+1)) ++ return -ENOMEM; ++ break; ++ } ++ } ++ ++ for (;; (*p)++, c = **p) { ++ if (backslash) { ++ if (!GREEDY_REALLOC(s, allocated, sz+7)) ++ return -ENOMEM; ++ ++ if (c == 0) { ++ if ((flags & EXTRACT_CUNESCAPE_RELAX) && ++ (!quote || flags & EXTRACT_RELAX)) { ++ /* If we find an unquoted trailing backslash and we're in ++ * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the ++ * output. ++ * ++ * Unbalanced quotes will only be allowed in EXTRACT_RELAX ++ * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. ++ */ ++ s[sz++] = '\\'; ++ goto finish_force_terminate; ++ } ++ if (flags & EXTRACT_RELAX) ++ goto finish_force_terminate; ++ return -EINVAL; ++ } ++ ++ if (flags & EXTRACT_CUNESCAPE) { ++ bool eight_bit = false; ++ int32_t u; ++ ++ r = cunescape_one(*p, (size_t) -1, &u, &eight_bit); ++ if (r < 0) { ++ if (flags & EXTRACT_CUNESCAPE_RELAX) { ++ s[sz++] = '\\'; ++ s[sz++] = c; ++ } else ++ return -EINVAL; ++ } else { ++ (*p) += r - 1; ++ ++ if (eight_bit) ++ s[sz++] = u; ++ else ++ sz += utf8_encode_unichar(s + sz, u); ++ } ++ } else ++ s[sz++] = c; ++ ++ backslash = false; ++ ++ } else if (quote) { /* inside either single or double quotes */ ++ for (;; (*p)++, c = **p) { ++ if (c == 0) { ++ if (flags & EXTRACT_RELAX) ++ goto finish_force_terminate; ++ return -EINVAL; ++ } else if (c == quote) { /* found the end quote */ ++ quote = 0; ++ break; ++ } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { ++ backslash = true; ++ break; ++ } else { ++ if (!GREEDY_REALLOC(s, allocated, sz+2)) ++ return -ENOMEM; ++ ++ s[sz++] = c; ++ } ++ } ++ ++ } else { ++ for (;; (*p)++, c = **p) { ++ if (c == 0) ++ goto finish_force_terminate; ++ else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) { ++ quote = c; ++ break; ++ } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { ++ backslash = true; ++ break; ++ } else if (strchr(separators, c)) { ++ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { ++ (*p)++; ++ goto finish_force_next; ++ } ++ /* Skip additional coalesced separators. */ ++ for (;; (*p)++, c = **p) { ++ if (c == 0) ++ goto finish_force_terminate; ++ if (!strchr(separators, c)) ++ break; ++ } ++ goto finish; ++ ++ } else { ++ if (!GREEDY_REALLOC(s, allocated, sz+2)) ++ return -ENOMEM; ++ ++ s[sz++] = c; ++ } ++ } ++ } ++ } ++ ++finish_force_terminate: ++ *p = NULL; ++finish: ++ if (!s) { ++ *p = NULL; ++ *ret = NULL; ++ return 0; ++ } ++ ++finish_force_next: ++ s[sz] = 0; ++ *ret = s; ++ s = NULL; ++ ++ return 1; ++} ++ ++int extract_first_word_and_warn( ++ const char **p, ++ char **ret, ++ const char *separators, ++ ExtractFlags flags, ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *rvalue) { ++ ++ /* Try to unquote it, if it fails, warn about it and try again ++ * but this time using EXTRACT_CUNESCAPE_RELAX to keep the ++ * backslashes verbatim in invalid escape sequences. */ ++ ++ const char *save; ++ int r; ++ ++ save = *p; ++ r = extract_first_word(p, ret, separators, flags); ++ if (r >= 0) ++ return r; ++ ++ if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) { ++ ++ /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ ++ *p = save; ++ r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); ++ if (r >= 0) { ++ /* It worked this time, hence it must have been an invalid escape sequence we could correct. */ ++ log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue); ++ return r; ++ } ++ ++ /* If it's still EINVAL; then it must be unbalanced quoting, report this. */ ++ if (r == -EINVAL) ++ return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue); ++ } ++ ++ /* Can be any error, report it */ ++ return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue); ++} ++ ++int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { ++ va_list ap; ++ char **l; ++ int n = 0, i, c, r; ++ ++ /* Parses a number of words from a string, stripping any ++ * quotes if necessary. */ ++ ++ assert(p); ++ ++ /* Count how many words are expected */ ++ va_start(ap, flags); ++ for (;;) { ++ if (!va_arg(ap, char **)) ++ break; ++ n++; ++ } ++ va_end(ap); ++ ++ if (n <= 0) ++ return 0; ++ ++ /* Read all words into a temporary array */ ++ l = newa0(char*, n); ++ for (c = 0; c < n; c++) { ++ ++ r = extract_first_word(p, &l[c], separators, flags); ++ if (r < 0) { ++ int j; ++ ++ for (j = 0; j < c; j++) ++ free(l[j]); ++ ++ return r; ++ } ++ ++ if (r == 0) ++ break; ++ } ++ ++ /* If we managed to parse all words, return them in the passed ++ * in parameters */ ++ va_start(ap, flags); ++ for (i = 0; i < n; i++) { ++ char **v; ++ ++ v = va_arg(ap, char **); ++ assert(v); ++ ++ *v = l[i]; ++ } ++ va_end(ap); ++ ++ return c; ++} +diff --git a/src/shared/util.h b/src/shared/util.h +index a441e44ff..be04524cc 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -315,6 +315,7 @@ int undecchar(char c) _const_; + char *cescape(const char *s); + char *cunescape(const char *s); + char *cunescape_length(const char *s, size_t length); ++int cunescape_one(const char *p, size_t length, int32_t *ret, bool *eight_bit); + char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix); + + char *xescape(const char *s, const char *bad); +@@ -1082,3 +1083,16 @@ void sigkill_wait(pid_t *pid); + int syslog_parse_priority(const char **p, int *priority, bool with_facility); + + char *shell_maybe_quote(const char *s); ++ ++typedef enum ExtractFlags { ++ EXTRACT_RELAX = 1, ++ EXTRACT_CUNESCAPE = 2, ++ EXTRACT_CUNESCAPE_RELAX = 4, ++ EXTRACT_QUOTES = 8, ++ EXTRACT_DONT_COALESCE_SEPARATORS = 16, ++ EXTRACT_RETAIN_ESCAPE = 32, ++} ExtractFlags; ++ ++int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); ++int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); ++int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 87c81ccd7..931dfeda8 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -554,11 +554,22 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66); ++ + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); ++ + free(rl[RLIMIT_NOFILE]); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); +@@ -570,6 +581,11 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 40); ++ assert_se(rl[RLIMIT_CPU]->rlim_max == 60); ++ + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); +@@ -587,16 +603,31 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60); ++ + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC); ++ + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); diff --git a/SOURCES/0359-core-fix-rlimit-parsing.patch b/SOURCES/0359-core-fix-rlimit-parsing.patch new file mode 100644 index 00000000..ddcb86a5 --- /dev/null +++ b/SOURCES/0359-core-fix-rlimit-parsing.patch @@ -0,0 +1,74 @@ +From b53ec8d7dca8eba189c45ae29e4d5ff03e5e5556 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 27 Nov 2015 08:54:42 +0000 +Subject: [PATCH] core: fix rlimit parsing + +* refuse limits if soft > hard +* print an actual value instead of (null) + +see https://github.com/systemd/systemd/pull/1994#issuecomment-159999123 + +Cherry-picked from: 0316f2aeebde7569d24a93ab788ac4bc1657b11b +Related: #1351415 +--- + src/core/load-fragment.c | 5 ++++- + src/test/test-unit-file.c | 21 +++++++++++++++++++++ + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index d307f1c74..2f6209e05 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1160,6 +1160,7 @@ static int parse_rlimit_range( + struct rlimit **rl, + int (*rlim_parser)(const char *, rlim_t *)) { + ++ const char *whole_value = value; + rlim_t soft, hard; + _cleanup_free_ char *sword = NULL, *hword = NULL; + int nwords, r; +@@ -1175,9 +1176,11 @@ static int parse_rlimit_range( + if (r == 0 && nwords == 2) + r = rlim_parser(hword, &hard); + if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", value); ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", whole_value); + return 0; + } ++ if (nwords == 2 && soft > hard) ++ return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid resource value ("RLIM_FMT" > "RLIM_FMT"), ignoring: %s", soft, hard, whole_value); + + if (!*rl) { + *rl = new(struct rlimit, 1); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 931dfeda8..8acf071ff 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -570,6 +570,27 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ ++ /* Invalid values don't change rl */ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ + free(rl[RLIMIT_NOFILE]); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); diff --git a/SOURCES/0360-core-dump-rlim_cur-too.patch b/SOURCES/0360-core-dump-rlim_cur-too.patch new file mode 100644 index 00000000..8b669227 --- /dev/null +++ b/SOURCES/0360-core-dump-rlim_cur-too.patch @@ -0,0 +1,26 @@ +From 0c4a5153b14701ffdbff2f768548d4a657b1ca9f Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 27 Nov 2015 09:13:35 +0000 +Subject: [PATCH] core: dump rlim_cur too + +Cherry-picked from: fdbbadbd0d13d3296b9aa4273aaeecd9ba6b82d1 +Related: #1351415 +--- + src/core/execute.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 8172c8b44..e9b4359a7 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2254,8 +2254,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { + + for (i = 0; i < RLIM_NLIMITS; i++) + if (c->rlimit[i]) +- fprintf(f, "%s%s: "RLIM_FMT"\n", +- prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max); ++ fprintf(f, "%s%s: " RLIM_FMT " " RLIM_FMT "\n", ++ prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur, c->rlimit[i]->rlim_max); + + if (c->ioprio_set) { + _cleanup_free_ char *class_str = NULL; diff --git a/SOURCES/0361-install-fix-disable-via-unit-file-path.patch b/SOURCES/0361-install-fix-disable-via-unit-file-path.patch new file mode 100644 index 00000000..aa428cc4 --- /dev/null +++ b/SOURCES/0361-install-fix-disable-via-unit-file-path.patch @@ -0,0 +1,39 @@ +From 96df052a6a9d09cde2d437861727bf37fe6446b4 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 12 Jul 2016 09:40:02 +0200 +Subject: [PATCH] install: fix disable via unit file path + +Drop the check for unit file name validity. install_info_add does that +anyway. Also pass NULL in place of name argument to install_info_add if +we are dealing with path to a unit file. install_info_add will figure +out a name from a path and it will correctly populate +UnitFileInstallInfo with both name and path. Then in +unit_file_search called from install_info_traverse we can take a +shortcut and attempt to load unit file directly. + +Cherry-picked from: 4dfbf0b176ff0e8a352617eba5e79065ee477969 +Resolves: #1348208 +--- + src/shared/install.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 5288bb450..f190dbfab 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1910,10 +1910,12 @@ int unit_file_disable( + return r; + + STRV_FOREACH(i, files) { +- if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) +- return -EINVAL; + +- r = install_info_add(&c, *i, NULL, NULL); ++ if (!is_path(*i)) ++ r = install_info_add(&c, *i, NULL, NULL); ++ else ++ r = install_info_add(&c, NULL, *i, NULL); ++ + if (r < 0) + return r; + } diff --git a/SOURCES/0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch b/SOURCES/0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch new file mode 100644 index 00000000..d8319fe4 --- /dev/null +++ b/SOURCES/0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch @@ -0,0 +1,248 @@ +From fd8580a8f42b1e10d75f43229b203fb889260b71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Sat, 16 Jul 2016 21:04:13 +0200 +Subject: [PATCH] manager: don't skip sigchld handler for main and control pid + for services (#3738) + +During stop when service has one "regular" pid one main pid and one +control pid and the sighld for the regular one is processed first the +unit_tidy_watch_pids will skip the main and control pid and does not +remove them from u->pids(). But then we skip the sigchld event because we +already did one in the iteration and there are two pids in u->pids. + +v2: Use general unit_main_pid() and unit_control_pid() instead of +reaching directly to service structure. +Cherry-picked from: ccc2c98e1b0c06861577632440b996ca16cefd53 +Resolves: #1342173 +--- + src/core/busname.c | 10 ++++++++++ + src/core/manager.c | 5 ++++- + src/core/mount.c | 10 ++++++++++ + src/core/service.c | 19 +++++++++++++++++++ + src/core/socket.c | 10 ++++++++++ + src/core/swap.c | 10 ++++++++++ + src/core/unit.c | 18 ++++++++++++++++++ + src/core/unit.h | 9 +++++++++ + 8 files changed, 90 insertions(+), 1 deletion(-) + +diff --git a/src/core/busname.c b/src/core/busname.c +index 43d7607a3..f626ba96d 100644 +--- a/src/core/busname.c ++++ b/src/core/busname.c +@@ -997,6 +997,14 @@ static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); + ++static int busname_control_pid(Unit *u) { ++ BusName *n = BUSNAME(u); ++ ++ assert(n); ++ ++ return n->control_pid; ++} ++ + static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { + [BUSNAME_SUCCESS] = "success", + [BUSNAME_FAILURE_RESOURCES] = "resources", +@@ -1047,6 +1055,8 @@ const UnitVTable busname_vtable = { + + .supported = busname_supported, + ++ .control_pid = busname_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.BusName", + .bus_vtable = bus_busname_vtable, + +diff --git a/src/core/manager.c b/src/core/manager.c +index d168777d2..5da836593 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1760,7 +1760,10 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + unit_unwatch_pid(u, si->si_pid); + + if (UNIT_VTABLE(u)->sigchld_event) { +- if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { ++ if (set_size(u->pids) <= 1 || ++ iteration != u->sigchldgen || ++ unit_main_pid(u) == si->si_pid || ++ unit_control_pid(u) == si->si_pid) { + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); + u->sigchldgen = iteration; + } else +diff --git a/src/core/mount.c b/src/core/mount.c +index fe967bc03..3fbdb7daf 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1877,6 +1877,14 @@ static const char* const mount_state_table[_MOUNT_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); + ++static int mount_control_pid(Unit *u) { ++ Mount *m = MOUNT(u); ++ ++ assert(m); ++ ++ return m->control_pid; ++} ++ + static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { + [MOUNT_EXEC_MOUNT] = "ExecMount", + [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", +@@ -1938,6 +1946,8 @@ const UnitVTable mount_vtable = { + + .reset_failed = mount_reset_failed, + ++ .control_pid = mount_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.Mount", + .bus_vtable = bus_mount_vtable, + .bus_set_property = bus_mount_set_property, +diff --git a/src/core/service.c b/src/core/service.c +index c76713b1c..babd3c52a 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -3068,6 +3068,22 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); + ++static int service_main_pid(Unit *u) { ++ Service *s = SERVICE(u); ++ ++ assert(s); ++ ++ return s->main_pid; ++} ++ ++static int service_control_pid(Unit *u) { ++ Service *s = SERVICE(u); ++ ++ assert(s); ++ ++ return s->control_pid; ++} ++ + static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { + [SERVICE_RESTART_NO] = "no", + [SERVICE_RESTART_ON_SUCCESS] = "on-success", +@@ -3178,6 +3194,9 @@ const UnitVTable service_vtable = { + .notify_cgroup_empty = service_notify_cgroup_empty_event, + .notify_message = service_notify_message, + ++ .main_pid = service_main_pid, ++ .control_pid = service_control_pid, ++ + .bus_name_owner_change = service_bus_name_owner_change, + + .bus_interface = "org.freedesktop.systemd1.Service", +diff --git a/src/core/socket.c b/src/core/socket.c +index bc677a20f..771af0d24 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -2648,6 +2648,14 @@ static const char* const socket_state_table[_SOCKET_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + ++static int socket_control_pid(Unit *u) { ++ Socket *s = SOCKET(u); ++ ++ assert(s); ++ ++ return s->control_pid; ++} ++ + static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { + [SOCKET_EXEC_START_PRE] = "StartPre", + [SOCKET_EXEC_START_CHOWN] = "StartChown", +@@ -2713,6 +2721,8 @@ const UnitVTable socket_vtable = { + + .reset_failed = socket_reset_failed, + ++ .control_pid = socket_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.Socket", + .bus_vtable = bus_socket_vtable, + .bus_set_property = bus_socket_set_property, +diff --git a/src/core/swap.c b/src/core/swap.c +index 34a2c406d..42f995990 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -1426,6 +1426,14 @@ static const char* const swap_state_table[_SWAP_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + ++static int swap_control_pid(Unit *u) { ++ Swap *s = SWAP(u); ++ ++ assert(s); ++ ++ return s->control_pid; ++} ++ + static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { + [SWAP_EXEC_ACTIVATE] = "ExecActivate", + [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", +@@ -1487,6 +1495,8 @@ const UnitVTable swap_vtable = { + + .reset_failed = swap_reset_failed, + ++ .control_pid = swap_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.Swap", + .bus_vtable = bus_swap_vtable, + .bus_set_property = bus_swap_set_property, +diff --git a/src/core/unit.c b/src/core/unit.c +index d62135d87..0e90d130a 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3674,6 +3674,24 @@ int unit_setup_exec_runtime(Unit *u) { + return exec_runtime_make(rt, unit_get_exec_context(u), u->id); + } + ++pid_t unit_control_pid(Unit *u) { ++ assert(u); ++ ++ if (UNIT_VTABLE(u)->control_pid) ++ return UNIT_VTABLE(u)->control_pid(u); ++ ++ return 0; ++} ++ ++pid_t unit_main_pid(Unit *u) { ++ assert(u); ++ ++ if (UNIT_VTABLE(u)->main_pid) ++ return UNIT_VTABLE(u)->main_pid(u); ++ ++ return 0; ++} ++ + static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { + [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", +diff --git a/src/core/unit.h b/src/core/unit.h +index d93645777..35287a5b7 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -399,6 +399,12 @@ struct UnitVTable { + + int (*get_timeout)(Unit *u, uint64_t *timeout); + ++ /* Returns the main PID if there is any defined, or 0. */ ++ pid_t (*main_pid)(Unit *u); ++ ++ /* Returns the main PID if there is any defined, or 0. */ ++ pid_t (*control_pid)(Unit *u); ++ + /* This is called for each unit type and should be used to + * enumerate existing devices and load them. However, + * everything that is loaded here should still stay in +@@ -610,6 +616,9 @@ int unit_make_transient(Unit *u); + + int unit_require_mounts_for(Unit *u, const char *path); + ++pid_t unit_control_pid(Unit *u); ++pid_t unit_main_pid(Unit *u); ++ + const char *unit_active_state_to_string(UnitActiveState i) _const_; + UnitActiveState unit_active_state_from_string(const char *s) _pure_; + diff --git a/SOURCES/0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch b/SOURCES/0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch new file mode 100644 index 00000000..07199755 --- /dev/null +++ b/SOURCES/0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch @@ -0,0 +1,156 @@ +From 5be84b3ae46c0fd35c3e80d4f457bf5aedc8af8f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 23 Sep 2015 17:27:39 +0200 +Subject: [PATCH] units: increase watchdog timeout to 3min for all our services + +Apparently, disk IO issues are more frequent than we hope, and 1min +waiting for disk IO happens, so let's increase the watchdog timeout a +bit, for all our services. + +See #1353 for an example where this triggers. + +(cherry picked from commit c2fc2c2560f0ca0fab383753c065e45d76f465e5) +Resolves: #1267707 +--- + units/systemd-hostnamed.service.in | 2 +- + units/systemd-importd.service.in | 2 +- + units/systemd-journald.service.in | 2 +- + units/systemd-localed.service.in | 2 +- + units/systemd-logind.service.in | 2 +- + units/systemd-machined.service.in | 2 +- + units/systemd-networkd.service.in | 2 +- + units/systemd-resolved.service.m4.in | 2 +- + units/systemd-timedated.service.in | 2 +- + units/systemd-timesyncd.service.in | 2 +- + 10 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in +index cc88ecd0d..b7079e4a7 100644 +--- a/units/systemd-hostnamed.service.in ++++ b/units/systemd-hostnamed.service.in +@@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/hostnamed + ExecStart=@rootlibexecdir@/systemd-hostnamed + BusName=org.freedesktop.hostname1 + CapabilityBoundingSet=CAP_SYS_ADMIN +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + PrivateDevices=yes + PrivateNetwork=yes +diff --git a/units/systemd-importd.service.in b/units/systemd-importd.service.in +index 5534a49ed..60e8e9c85 100644 +--- a/units/systemd-importd.service.in ++++ b/units/systemd-importd.service.in +@@ -14,7 +14,7 @@ ExecStart=@rootlibexecdir@/systemd-importd + BusName=org.freedesktop.import1 + CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP + NoNewPrivileges=yes +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + ProtectSystem=full + ProtectHome=yes +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index 9d4462283..8575912bb 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -22,7 +22,7 @@ RestartSec=0 + NotifyAccess=all + StandardOutput=null + CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE +-WatchdogSec=1min ++WatchdogSec=3min + + # Increase the default a bit in order to allow many simultaneous + # services being run since we keep one fd open per service. Also, when +diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in +index bfa097844..9b13f901a 100644 +--- a/units/systemd-localed.service.in ++++ b/units/systemd-localed.service.in +@@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/localed + ExecStart=@rootlibexecdir@/systemd-localed + BusName=org.freedesktop.locale1 + CapabilityBoundingSet= +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + PrivateDevices=yes + PrivateNetwork=yes +diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in +index f087e99ce..ff049134e 100644 +--- a/units/systemd-logind.service.in ++++ b/units/systemd-logind.service.in +@@ -24,7 +24,7 @@ Restart=always + RestartSec=0 + BusName=org.freedesktop.login1 + CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG +-WatchdogSec=1min ++WatchdogSec=3min + + # Increase the default a bit in order to allow many simultaneous + # logins since we keep one fd open per session. +diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in +index 15f34d9db..35cde9869 100644 +--- a/units/systemd-machined.service.in ++++ b/units/systemd-machined.service.in +@@ -16,7 +16,7 @@ After=machine.slice + ExecStart=@rootlibexecdir@/systemd-machined + BusName=org.freedesktop.machine1 + CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + PrivateDevices=yes + PrivateNetwork=yes +diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in +index 5a91b8e49..d3808c430 100644 +--- a/units/systemd-networkd.service.in ++++ b/units/systemd-networkd.service.in +@@ -25,7 +25,7 @@ ExecStart=@rootlibexecdir@/systemd-networkd + CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER + ProtectSystem=full + ProtectHome=yes +-WatchdogSec=1min ++WatchdogSec=3min + + [Install] + WantedBy=multi-user.target +diff --git a/units/systemd-resolved.service.m4.in b/units/systemd-resolved.service.m4.in +index 98ae564af..46864e6a3 100644 +--- a/units/systemd-resolved.service.m4.in ++++ b/units/systemd-resolved.service.m4.in +@@ -25,7 +25,7 @@ ExecStart=@rootlibexecdir@/systemd-resolved + CapabilityBoundingSet=CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER + ProtectSystem=full + ProtectHome=yes +-WatchdogSec=1min ++WatchdogSec=3min + + [Install] + WantedBy=multi-user.target +diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in +index fe5ccb460..0c9599db2 100644 +--- a/units/systemd-timedated.service.in ++++ b/units/systemd-timedated.service.in +@@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/timedated + ExecStart=@rootlibexecdir@/systemd-timedated + BusName=org.freedesktop.timedate1 + CapabilityBoundingSet=CAP_SYS_TIME +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + ProtectSystem=yes + ProtectHome=yes +diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in +index 39edafc8d..c7d1d2b4f 100644 +--- a/units/systemd-timesyncd.service.in ++++ b/units/systemd-timesyncd.service.in +@@ -27,7 +27,7 @@ PrivateTmp=yes + PrivateDevices=yes + ProtectSystem=full + ProtectHome=yes +-WatchdogSec=1min ++WatchdogSec=3min + + [Install] + WantedBy=sysinit.target diff --git a/SOURCES/0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch b/SOURCES/0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch new file mode 100644 index 00000000..6f8e0057 --- /dev/null +++ b/SOURCES/0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch @@ -0,0 +1,90 @@ +From a3b8feb9320f745f960fe8f7006183137f4969b1 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Nov 2015 09:34:05 +0100 +Subject: [PATCH] core: bump net.unix.max_dgram_qlen really early during boot + +Only that way it actually has an effect on all our sockets, including +$NOTIFY_SOCKET. + +(cherry picked from commit 19854865a877a3a4fa3d04550c15a99c0e1187ff) +Related: #1267707 +--- + src/core/main.c | 36 ++++++++++++++++++++++++++++++++++++ + src/shared/def.h | 3 +++ + 2 files changed, 39 insertions(+) + +diff --git a/src/core/main.c b/src/core/main.c +index 60ea36c3c..c9d8ce4a4 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1198,6 +1198,7 @@ static int status_welcome(void) { + + static int write_container_id(void) { + const char *c; ++ int r; + + c = getenv("container"); + if (isempty(c)) +@@ -1206,6 +1207,40 @@ static int write_container_id(void) { + return write_string_file("/run/systemd/container", c); + } + ++static int bump_unix_max_dgram_qlen(void) { ++ _cleanup_free_ char *qlen = NULL; ++ unsigned long v; ++ int r; ++ ++ /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel ++ * default of 16 is simply too low. We set the value really ++ * really early during boot, so that it is actually applied to ++ * all our sockets, including the $NOTIFY_SOCKET one. */ ++ ++ r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m"); ++ ++ r = safe_atolu(qlen, &v); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m"); ++ ++ if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN) ++ return 0; ++ ++ free(qlen); ++ qlen = NULL; ++ if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0) ++ return log_oom(); ++ ++ r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen); ++ if (r < 0) ++ return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, ++ "Failed to bump AF_UNIX datagram queue length, ignoring: %m"); ++ ++ return 1; ++} ++ + int main(int argc, char *argv[]) { + Manager *m = NULL; + int r, retval = EXIT_FAILURE; +@@ -1571,6 +1606,7 @@ int main(int argc, char *argv[]) { + hostname_setup(); + machine_id_setup(NULL); + loopback_setup(); ++ bump_unix_max_dgram_qlen(); + + test_mtab(); + test_usr(); +diff --git a/src/shared/def.h b/src/shared/def.h +index a3d9fcf38..76daf012d 100644 +--- a/src/shared/def.h ++++ b/src/shared/def.h +@@ -35,6 +35,9 @@ + * the watchdog pings will keep the loop busy. */ + #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC) + ++/* The default value for the net.unix.max_dgram_qlen sysctl */ ++#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL ++ + #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" + + #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT diff --git a/SOURCES/0365-core-fix-priority-ordering-in-notify-handling.patch b/SOURCES/0365-core-fix-priority-ordering-in-notify-handling.patch new file mode 100644 index 00000000..d7bb2a2f --- /dev/null +++ b/SOURCES/0365-core-fix-priority-ordering-in-notify-handling.patch @@ -0,0 +1,228 @@ +From 64e21697bdefe0a37edc8557fd110daea2667771 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 28 Oct 2015 19:11:36 +0100 +Subject: [PATCH] core: fix priority ordering in notify-handling + +Currently, we dispatch NOTIFY messages in a tight loop. Regardless how +much data is incoming, we always dispatch everything that is queued. +This, however, completely breaks priority event-handling of sd-event. +When dispatching one NOTIFY event, another completely different event +might fire, or might be queued by the NOTIFY handling. However, this +event will not get dispatched until all other further NOTIFY messages are +handled. Those might even arrive _after_ the other event fired, and as +such completely break priority ordering of sd-event (which several code +paths rely on). + +Break this by never dispatching multiple messages. Just return after each +message that was read and let sd-event handle everything else. + +(The patch looks scarier that it is. It basically just drops the for(;;) + loop and re-indents the loop-content.) + +(cherry picked from commit b215b0ede11c0dda90009c8412609d2416150075) +Related: #1267707 +--- + src/core/manager.c | 158 ++++++++++++++++++++++++++--------------------------- + 1 file changed, 78 insertions(+), 80 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 5da836593..c5021993e 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1635,9 +1635,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char * + } + + static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++ _cleanup_fdset_free_ FDSet *fds = NULL; + Manager *m = userdata; ++ ++ char buf[NOTIFY_BUFFER_MAX+1]; ++ struct iovec iovec = { ++ .iov_base = buf, ++ .iov_len = sizeof(buf)-1, ++ }; ++ union { ++ struct cmsghdr cmsghdr; ++ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + ++ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; ++ } control = {}; ++ struct msghdr msghdr = { ++ .msg_iov = &iovec, ++ .msg_iovlen = 1, ++ .msg_control = &control, ++ .msg_controllen = sizeof(control), ++ }; ++ ++ struct cmsghdr *cmsg; ++ struct ucred *ucred = NULL; ++ bool found = false; ++ Unit *u1, *u2, *u3; ++ int r, *fd_array = NULL; ++ unsigned n_fds = 0; + ssize_t n; +- int r; + + assert(m); + assert(m->notify_fd == fd); +@@ -1647,108 +1671,82 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + return 0; + } + +- for (;;) { +- _cleanup_fdset_free_ FDSet *fds = NULL; +- char buf[NOTIFY_BUFFER_MAX+1]; +- struct iovec iovec = { +- .iov_base = buf, +- .iov_len = sizeof(buf)-1, +- }; +- union { +- struct cmsghdr cmsghdr; +- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + +- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; +- } control = {}; +- struct msghdr msghdr = { +- .msg_iov = &iovec, +- .msg_iovlen = 1, +- .msg_control = &control, +- .msg_controllen = sizeof(control), +- }; +- struct cmsghdr *cmsg; +- struct ucred *ucred = NULL; +- bool found = false; +- Unit *u1, *u2, *u3; +- int *fd_array = NULL; +- unsigned n_fds = 0; +- +- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); +- if (n < 0) { +- if (errno == EAGAIN || errno == EINTR) +- break; ++ n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); ++ if (n < 0) { ++ if (errno == EAGAIN || errno == EINTR) ++ return 0; + +- return -errno; +- } ++ return -errno; ++ } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { +- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { ++ for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + +- fd_array = (int*) CMSG_DATA(cmsg); +- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); ++ fd_array = (int*) CMSG_DATA(cmsg); ++ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_CREDENTIALS && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { ++ } else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_CREDENTIALS && ++ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + +- ucred = (struct ucred*) CMSG_DATA(cmsg); +- } ++ ucred = (struct ucred*) CMSG_DATA(cmsg); + } ++ } + +- if (n_fds > 0) { +- assert(fd_array); ++ if (n_fds > 0) { ++ assert(fd_array); + +- r = fdset_new_array(&fds, fd_array, n_fds); +- if (r < 0) { +- close_many(fd_array, n_fds); +- return log_oom(); +- } ++ r = fdset_new_array(&fds, fd_array, n_fds); ++ if (r < 0) { ++ close_many(fd_array, n_fds); ++ return log_oom(); + } ++ } + +- if (!ucred || ucred->pid <= 0) { +- log_warning("Received notify message without valid credentials. Ignoring."); +- continue; +- } ++ if (!ucred || ucred->pid <= 0) { ++ log_warning("Received notify message without valid credentials. Ignoring."); ++ return 0; ++ } + +- if ((size_t) n >= sizeof(buf)) { +- log_warning("Received notify message exceeded maximum size. Ignoring."); +- continue; +- } ++ if ((size_t) n >= sizeof(buf)) { ++ log_warning("Received notify message exceeded maximum size. Ignoring."); ++ return 0; ++ } + +- buf[n] = 0; ++ buf[n] = 0; + +- /* Notify every unit that might be interested, but try +- * to avoid notifying the same one multiple times. */ +- u1 = manager_get_unit_by_pid(m, ucred->pid); +- if (u1) { +- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); +- found = true; +- } ++ /* Notify every unit that might be interested, but try ++ * to avoid notifying the same one multiple times. */ ++ u1 = manager_get_unit_by_pid(m, ucred->pid); ++ if (u1) { ++ manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); ++ found = true; ++ } + +- u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); +- if (u2 && u2 != u1) { +- manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); +- found = true; +- } ++ u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); ++ if (u2 && u2 != u1) { ++ manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); ++ found = true; ++ } + +- u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); +- if (u3 && u3 != u2 && u3 != u1) { +- manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); +- found = true; +- } ++ u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); ++ if (u3 && u3 != u2 && u3 != u1) { ++ manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); ++ found = true; ++ } + +- if (!found) +- log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); ++ if (!found) ++ log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); + +- if (fdset_size(fds) > 0) +- log_warning("Got auxiliary fds with notification message, closing all."); +- } ++ if (fdset_size(fds) > 0) ++ log_warning("Got auxiliary fds with notification message, closing all."); + + return 0; + } + + static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + uint64_t iteration; +- ++ + assert(m); + assert(u); + assert(si); diff --git a/SOURCES/0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch b/SOURCES/0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch new file mode 100644 index 00000000..b33f4c91 --- /dev/null +++ b/SOURCES/0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch @@ -0,0 +1,85 @@ +From 89a7c7e55af18c4f18c0d83c244dbe20ddb85515 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 29 Jul 2016 15:03:02 +0200 +Subject: [PATCH] tests: fix personality tests on ppc64 and aarch64 + +Resolves: #1361049 +--- + src/shared/util.c | 16 ++++++++++++++++ + src/test/test-execute.c | 6 ++++++ + test/exec-personality-aarch64.service | 7 +++++++ + test/exec-personality-ppc64.service | 7 +++++++ + 4 files changed, 36 insertions(+) + create mode 100644 test/exec-personality-aarch64.service + create mode 100644 test/exec-personality-ppc64.service + +diff --git a/src/shared/util.c b/src/shared/util.c +index f75ed9dd4..303026152 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -6986,6 +6986,22 @@ unsigned long personality_from_string(const char *p) { + + if (streq(p, "s390")) + return PER_LINUX; ++ ++#elif defined(__powerpc64__) ++ ++# if defined(__BIG_ENDIAN__) ++ if (streq(p, "ppc64")) ++ return PER_LINUX; ++# else ++ if (streq(p, "ppc64le")) ++ return PER_LINUX; ++# endif ++ ++#elif defined(__aarch64__) ++ ++ if (streq(p, "aarch64")) ++ return PER_LINUX; ++ + #endif + + /* personality(7) documents that 0xffffffffUL is used for +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 38522a168..5a02960e7 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -83,6 +83,12 @@ static void test_exec_personality(Manager *m) { + #elif defined(__s390__) + test(m, "exec-personality-s390.service", 0, CLD_EXITED); + ++#elif defined(__powerpc64__) ++ test(m, "exec-personality-ppc64.service", 0, CLD_EXITED); ++ ++#elif defined(__aarch64__) ++ test(m, "exec-personality-aarch64.service", 0, CLD_EXITED); ++ + #else + test(m, "exec-personality-x86.service", 0, CLD_EXITED); + #endif +diff --git a/test/exec-personality-aarch64.service b/test/exec-personality-aarch64.service +new file mode 100644 +index 000000000..851117441 +--- /dev/null ++++ b/test/exec-personality-aarch64.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for Personality=aarch64 ++ ++[Service] ++ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "aarch64")' ++Type=oneshot ++Personality=aarch64 +diff --git a/test/exec-personality-ppc64.service b/test/exec-personality-ppc64.service +new file mode 100644 +index 000000000..4432074e6 +--- /dev/null ++++ b/test/exec-personality-ppc64.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for Personality=ppc64 ++ ++[Service] ++ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64" -o $(uname -m) = "ppc64le")' ++Type=oneshot ++Personality=ppc64 diff --git a/SOURCES/0367-systemctl-consider-service-running-only-when-it-is-i.patch b/SOURCES/0367-systemctl-consider-service-running-only-when-it-is-i.patch new file mode 100644 index 00000000..1eef6184 --- /dev/null +++ b/SOURCES/0367-systemctl-consider-service-running-only-when-it-is-i.patch @@ -0,0 +1,29 @@ +From 94fec84897ab40bf2bc92f0d395a93ecac1b45be Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Wed, 3 Aug 2016 17:08:37 +0200 +Subject: [PATCH] systemctl: consider service running only when it is in active + or reloading state (#3874) + +Otherwise for example services that are failing on start and have Restart=on-failure +and bigger RestartSec systemctl status will return 0. + +Fixes: #3864 +Cherry-picked from: 7f5da8bd4fb1ba49ba40195a74ca76bb5d4d1f81 +Resolves: #1362461 +--- + src/systemctl/systemctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 93b7a193b..b7496c006 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4339,7 +4339,7 @@ static int show_one( + else if (streq(verb, "status")) { + print_status_info(&info, ellipsized); + +- if (info.active_state && STR_IN_SET(info.active_state, "inactive", "failed")) ++ if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading")) + r = EXIT_PROGRAM_NOT_RUNNING; + else + r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK; diff --git a/SOURCES/0368-install-do-not-crash-when-processing-empty-masked-un.patch b/SOURCES/0368-install-do-not-crash-when-processing-empty-masked-un.patch new file mode 100644 index 00000000..5af2559d --- /dev/null +++ b/SOURCES/0368-install-do-not-crash-when-processing-empty-masked-un.patch @@ -0,0 +1,24 @@ +From 7d6f53ece9b0a397ee2f8bdaa1a52ef2f03bd81f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 9 Aug 2016 13:02:37 +0200 +Subject: [PATCH] install: do not crash when processing empty (masked) unit + file + +Related: #1159308 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index f190dbfab..f7f9866f4 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -996,7 +996,7 @@ static int unit_file_load( + if (fstat(fd, &st) < 0) + return -errno; + if (null_or_empty(&st)) { +- info->type = UNIT_FILE_MASKED; ++ info->type = UNIT_FILE_TYPE_MASKED; + return 0; + } + if (S_ISDIR(st.st_mode)) diff --git a/SOURCES/0369-Revert-install-fix-disable-via-unit-file-path.patch b/SOURCES/0369-Revert-install-fix-disable-via-unit-file-path.patch new file mode 100644 index 00000000..80cc1662 --- /dev/null +++ b/SOURCES/0369-Revert-install-fix-disable-via-unit-file-path.patch @@ -0,0 +1,32 @@ +From f79f65a2957cca23e0347eb2c9dfbd53be5c8dba Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 8 Aug 2016 15:15:14 +0200 +Subject: [PATCH] Revert "install: fix disable via unit file path" + +This reverts commit 96df052a6a9d09cde2d437861727bf37fe6446b4. + +Related: #1348208 +--- + src/shared/install.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index f7f9866f4..9962508b1 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1910,12 +1910,10 @@ int unit_file_disable( + return r; + + STRV_FOREACH(i, files) { ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) ++ return -EINVAL; + +- if (!is_path(*i)) +- r = install_info_add(&c, *i, NULL, NULL); +- else +- r = install_info_add(&c, NULL, *i, NULL); +- ++ r = install_info_add(&c, *i, NULL, NULL); + if (r < 0) + return r; + } diff --git a/SOURCES/0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch b/SOURCES/0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch new file mode 100644 index 00000000..ab392302 --- /dev/null +++ b/SOURCES/0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch @@ -0,0 +1,82 @@ +From 1f8b1e35e3ec80c50201403171b7375ff14c808c Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 26 Jul 2016 14:25:52 +0200 +Subject: [PATCH] systemctl: allow disable on the unit file path, but warn + about it (#3806) + +systemd now returns an error when it is asked to perform disable on the +unit file path. In the past this was allowed, but systemd never really +considered an actual content of the [Install] section of the unit +file. Instead it performed disable on the unit name, i.e. purged all +symlinks pointing to the given unit file (undo of implicit link action +done by systemd when enable is called on the unit file path) and all +symlinks that have the same basename as the given unit file. + +However, to notice that [Install] info of the file is not consulted one +must create additional symlinks manually. I argue that in most cases +users do not create such links. Let's be nice to our users and don't +break existing scripts that expect disable to work with the unit file +path. + +Fixes #3706. + +IMPORTANT +========= +Note that in this downstream backport we actually pass false to +normalize_names(), hence it will not produce any warning when full path +is passed in. This is because we need to preserve behavior compatible +with prior systemd versions shipped in RHEL. + +Cherry-picked from: 1d3c86c06fca8311923fcf81af0ab0bbb66e1edd +Resolves: #1348208 +--- + src/systemctl/systemctl.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index b7496c006..58998185c 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -5333,6 +5333,29 @@ static int mangle_names(char **original_names, char ***mangled_names) { + return 0; + } + ++static int normalize_names(char **names, bool warn_if_path) { ++ char **u; ++ bool was_path = false; ++ ++ STRV_FOREACH(u, names) { ++ int r; ++ ++ if (!is_path(*u)) ++ continue; ++ ++ r = free_and_strdup(u, basename(*u)); ++ if (r < 0) ++ return log_error_errno(r, "Failed to normalize unit file path: %m"); ++ ++ was_path = true; ++ } ++ ++ if (warn_if_path && was_path) ++ log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name."); ++ ++ return 0; ++} ++ + static int enable_unit(sd_bus *bus, char **args) { + _cleanup_strv_free_ char **names = NULL; + const char *verb = args[0]; +@@ -5357,6 +5380,12 @@ static int enable_unit(sd_bus *bus, char **args) { + if (strv_isempty(names)) + return 0; + ++ if (streq(verb, "disable")) { ++ r = normalize_names(names, false); ++ if (r < 0) ++ return r; ++ } ++ + if (!bus || avoid_bus()) { + if (streq(verb, "enable")) { + r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); diff --git a/SOURCES/0371-tmpfiles-enforce-ordering-when-executing-lines.patch b/SOURCES/0371-tmpfiles-enforce-ordering-when-executing-lines.patch new file mode 100644 index 00000000..6b9fd5b3 --- /dev/null +++ b/SOURCES/0371-tmpfiles-enforce-ordering-when-executing-lines.patch @@ -0,0 +1,102 @@ +From fd09d69b1bca2b4b602f4ee98d4749a39af04bb4 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 10 Apr 2015 16:22:22 +0200 +Subject: [PATCH] tmpfiles: enforce ordering when executing lines + +Always create files first, and then adjust their ACLs, xattrs, file +attributes, never the opposite. Previously the order was not +deterministic, thus possibly first adjusting ACLs/xattrs/file +attributes before actually creating the items. + +Cherry-picked from: 17493fa5d17cadce3b773692d3eeab137de7d323 +Resolves: #1365870 +--- + src/tmpfiles/tmpfiles.c | 39 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 35 insertions(+), 4 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 64c733aaa..bda89df5b 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -78,18 +78,18 @@ typedef enum ItemType { + COPY_FILES = 'C', + + /* These ones take globs */ ++ WRITE_FILE = 'w', + SET_XATTR = 't', + RECURSIVE_SET_XATTR = 'T', + SET_ACL = 'a', + RECURSIVE_SET_ACL = 'A', +- WRITE_FILE = 'w', + IGNORE_PATH = 'x', + IGNORE_DIRECTORY_PATH = 'X', + REMOVE_PATH = 'r', + RECURSIVE_REMOVE_PATH = 'R', +- ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */ + RELABEL_PATH = 'z', + RECURSIVE_RELABEL_PATH = 'Z', ++ ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */ + } ItemType; + + typedef struct Item { +@@ -1480,6 +1480,31 @@ static void item_array_free(ItemArray *a) { + free(a); + } + ++static int item_compare(const void *a, const void *b) { ++ const Item *x = a, *y = b; ++ ++ /* Make sure that the ownership taking item is put first, so ++ * that we first create the node, and then can adjust it */ ++ ++ if (takes_ownership(x->type) && !takes_ownership(y->type)) ++ return -1; ++ if (!takes_ownership(x->type) && takes_ownership(y->type)) ++ return 1; ++ ++ return (int) x->type - (int) y->type; ++} ++ ++static void item_array_sort(ItemArray *a) { ++ ++ /* Sort an item array, to enforce stable ordering in which we ++ * apply things. */ ++ ++ if (a->count <= 1) ++ return; ++ ++ qsort(a->items, a->count, sizeof(Item), item_compare); ++} ++ + static bool item_compatible(Item *a, Item *b) { + assert(a); + assert(b); +@@ -1806,6 +1831,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + return log_oom(); + + memcpy(existing->items + existing->count++, &i, sizeof(i)); ++ item_array_sort(existing); ++ + zero(i); + return 0; + } +@@ -2045,13 +2072,17 @@ int main(int argc, char *argv[]) { + } + } + +- HASHMAP_FOREACH(a, globs, iterator) { ++ /* The non-globbing ones usually create things, hence we apply ++ * them first */ ++ HASHMAP_FOREACH(a, items, iterator) { + k = process_item_array(a); + if (k < 0 && r == 0) + r = k; + } + +- HASHMAP_FOREACH(a, items, iterator) { ++ /* The globbing ones usually alter things, hence we apply them ++ * second. */ ++ HASHMAP_FOREACH(a, globs, iterator) { + k = process_item_array(a); + if (k < 0 && r == 0) + r = k; diff --git a/SOURCES/0372-Introduce-bus_unit_check_load_state-helper.patch b/SOURCES/0372-Introduce-bus_unit_check_load_state-helper.patch new file mode 100644 index 00000000..48ad6120 --- /dev/null +++ b/SOURCES/0372-Introduce-bus_unit_check_load_state-helper.patch @@ -0,0 +1,53 @@ +From c55a7f9448378c10a7e8074db908502ae5ff60aa Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Fri, 13 Nov 2015 14:12:19 +0100 +Subject: [PATCH] Introduce bus_unit_check_load_state() helper + +This function is used to check that a previous unit load succeed and +returns 0 in this case. + +In the case the load failed, the function setup a bus error +accordingly and returns -errno. + +(cherry picked from commit 000a996dc46c187f803b67b0b0d51ad4d0bc1658) +Related: #1256858 +--- + src/core/dbus-unit.c | 17 +++++++++++++++++ + src/core/dbus-unit.h | 2 ++ + 2 files changed, 19 insertions(+) + +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 49770bfda..c3654db9e 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -1083,3 +1083,20 @@ int bus_unit_set_properties( + + return n; + } ++ ++int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { ++ ++ if (u->load_state == UNIT_LOADED) ++ return 0; ++ ++ /* Give a better description of the unit error when ++ * possible. Note that in the case of UNIT_MASKED, load_error ++ * is not set. */ ++ if (u->load_state == UNIT_MASKED) ++ return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit is masked."); ++ ++ if (u->load_state == UNIT_NOT_FOUND) ++ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit not found."); ++ ++ return sd_bus_error_set_errnof(error, u->load_error, "Unit is not loaded properly: %m."); ++} +diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h +index 57a5e1974..433849641 100644 +--- a/src/core/dbus-unit.h ++++ b/src/core/dbus-unit.h +@@ -37,3 +37,5 @@ int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *use + int bus_unit_queue_job(sd_bus *bus, sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error); + int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error); + int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); ++ ++int bus_unit_check_load_state(Unit *u, sd_bus_error *error); diff --git a/SOURCES/0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch b/SOURCES/0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch new file mode 100644 index 00000000..5f2d376a --- /dev/null +++ b/SOURCES/0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch @@ -0,0 +1,76 @@ +From a47b58110f92415fcb69441031e4d04fec48b852 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Wed, 2 Dec 2015 17:03:28 +0100 +Subject: [PATCH] core: use bus_unit_check_load_state() in + transaction_add_job_and_dependencies() + +(cherry picked from commit ee87525c5eeacf3ce8fb730bcd3658e8da085046) +Related: #1256858 +--- + src/core/transaction.c | 27 +++++---------------------- + src/systemctl/systemctl.c | 5 +++++ + 2 files changed, 10 insertions(+), 22 deletions(-) + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index aed64fa41..57e9cb3f8 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -26,6 +26,7 @@ + #include "bus-util.h" + #include "bus-error.h" + #include "transaction.h" ++#include "dbus-unit.h" + + static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); + +@@ -857,30 +858,12 @@ int transaction_add_job_and_dependencies( + return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, + "Unit %s is not loaded properly.", unit->id); + +- if (type != JOB_STOP && unit->load_state == UNIT_ERROR) { +- if (unit->load_error == -ENOENT || unit->manager->test_run) +- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, +- "Unit %s failed to load: %s.", +- unit->id, +- strerror(-unit->load_error)); +- else +- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, +- "Unit %s failed to load: %s. " +- "See system logs and 'systemctl status %s' for details.", +- unit->id, +- strerror(-unit->load_error), +- unit->id); ++ if (type != JOB_STOP) { ++ r = bus_unit_check_load_state(unit, e); ++ if (r < 0) ++ return r; + } + +- if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) +- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, +- "Unit %s failed to load: %s.", +- unit->id, strerror(-unit->load_error)); +- +- if (type != JOB_STOP && unit->load_state == UNIT_MASKED) +- return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED, +- "Unit %s is masked.", unit->id); +- + if (!unit_job_is_applicable(unit, type)) + return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, + "Job type %s is not applicable for unit %s.", +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 58998185c..e4b404abc 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -2617,6 +2617,11 @@ static int start_unit_one( + verb = method_to_verb(method); + + log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r)); ++ ++ if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) && ++ !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED)) ++ log_error("See system logs and 'systemctl status %s' for details.", name); ++ + return r; + } + diff --git a/SOURCES/0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch b/SOURCES/0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch new file mode 100644 index 00000000..0b71cb22 --- /dev/null +++ b/SOURCES/0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch @@ -0,0 +1,31 @@ +From fb9a50a0ad64f28c00c7d0bbc4ee8908d4233593 Mon Sep 17 00:00:00 2001 +From: Hendrik Brueckner +Date: Fri, 19 Feb 2016 15:21:18 +0100 +Subject: [PATCH] udev/path_id: correct segmentation fault due to missing NULL + check + +Running "udevadm test-builtin path_id /sys/devices/platform/" results +in a segmentation fault. + +The problem is that udev_device_get_subsystem(dev) might return NULL +in a streq() call. Solve this problem by using streq_ptr() instead. + +Cherry-picked from: 5181ab917d6407cb57043e98955f0de1614366ea +Resolves: #1365556 +--- + src/udev/udev-builtin-path_id.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 8359e236a..a3b019bfc 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -729,7 +729,7 @@ restart: + * devices do not expose their buses and do not provide a unique + * and predictable name that way. + */ +- if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport) { ++ if (streq_ptr(udev_device_get_subsystem(dev), "block") && !supported_transport) { + free(path); + path = NULL; + } diff --git a/SOURCES/0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch b/SOURCES/0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch new file mode 100644 index 00000000..08241ef3 --- /dev/null +++ b/SOURCES/0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch @@ -0,0 +1,22 @@ +From 3724d66bec53bf53e5378269e6ddf68c99da7f0c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Thu, 18 Aug 2016 14:51:19 +0200 +Subject: [PATCH] rules: load sg driver also when scsi_target appears (#45) + +Resolves: #1322773 +--- + rules/40-redhat.rules | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 9a48adde1..3335fe507 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -11,6 +11,7 @@ ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/sys + + # load SCSI generic (sg) driver + SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST!="[module/sg]", RUN+="/sbin/modprobe -bv sg" ++SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_target", TEST!="[module/sg]", RUN+="/sbin/modprobe -bv sg" + + # Rule for prandom character device node permissions + KERNEL=="prandom", MODE="0644" diff --git a/SOURCES/0376-fix-gcc-warnings-about-uninitialized-variables.patch b/SOURCES/0376-fix-gcc-warnings-about-uninitialized-variables.patch new file mode 100644 index 00000000..eb644813 --- /dev/null +++ b/SOURCES/0376-fix-gcc-warnings-about-uninitialized-variables.patch @@ -0,0 +1,483 @@ +From c815acfb5863d9562a3f1e9cbd6204da3364860c Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Fri, 27 Mar 2015 12:02:49 +0100 +Subject: [PATCH] fix gcc warnings about uninitialized variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +like: + +src/shared/install.c: In function ‘unit_file_lookup_state’: +src/shared/install.c:1861:16: warning: ‘r’ may be used uninitialized in +this function [-Wmaybe-uninitialized] + return r < 0 ? r : state; + ^ +src/shared/install.c:1796:13: note: ‘r’ was declared here + int r; + ^ + +Conflicts: + src/journal/journal-file.c + src/shared/btrfs-util.c + src/shared/install.c + +Cherry-picked from: a7f7d1bde43fc825c49afea3f946f5b4b3d563e0 +Related: #1318994 +--- + src/import/import-job.c | 2 +- + src/journal-remote/journal-gatewayd.c | 2 +- + src/journal-remote/journal-remote-parse.c | 2 +- + src/journal-remote/journal-remote.c | 4 ++-- + src/journal/catalog.c | 2 +- + src/journal/coredump.c | 4 ++-- + src/journal/journal-file.c | 6 +++--- + src/journal/journal-vacuum.c | 2 +- + src/journal/journalctl.c | 2 +- + src/journal/test-journal-stream.c | 2 +- + src/libsystemd-network/lldp-tlv.c | 8 ++++---- + src/libsystemd-network/sd-dhcp-server.c | 2 +- + src/libsystemd-network/sd-pppoe.c | 2 +- + src/libsystemd/sd-login/sd-login.c | 2 +- + src/network/networkctl.c | 2 +- + src/resolve/resolved-dns-transaction.c | 2 +- + src/resolve/test-dns-domain.c | 2 +- + src/shared/base-filesystem.c | 2 +- + src/shared/capability.c | 2 +- + src/shared/copy.c | 6 +++--- + src/shared/install.c | 2 +- + src/shared/logs-show.c | 2 +- + src/shared/util.c | 4 ++-- + src/test/test-path.c | 2 +- + src/test/test-pty.c | 2 +- + src/udev/net/link-config.c | 2 +- + 26 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/src/import/import-job.c b/src/import/import-job.c +index 5f9cfd366..d826f493f 100644 +--- a/src/import/import-job.c ++++ b/src/import/import-job.c +@@ -80,7 +80,7 @@ void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { + long status; + int r; + +- if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, &j) != CURLE_OK) ++ if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j) != CURLE_OK) + return; + + if (!j || j->state == IMPORT_JOB_DONE || j->state == IMPORT_JOB_FAILED) +diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c +index 576f7cae7..d1f0ce3da 100644 +--- a/src/journal-remote/journal-gatewayd.c ++++ b/src/journal-remote/journal-gatewayd.c +@@ -736,7 +736,7 @@ static int request_handler_machine( + RequestMeta *m = connection_cls; + int r; + _cleanup_free_ char* hostname = NULL, *os_name = NULL; +- uint64_t cutoff_from = 0, cutoff_to = 0, usage; ++ uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0; + char *json; + sd_id128_t mid, bid; + _cleanup_free_ char *v = NULL; +diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c +index 7e6295435..64089da19 100644 +--- a/src/journal-remote/journal-remote-parse.c ++++ b/src/journal-remote/journal-remote-parse.c +@@ -316,7 +316,7 @@ int process_data(RemoteSource *source) { + switch(source->state) { + case STATE_LINE: { + char *line, *sep; +- size_t n; ++ size_t n = 0; + + assert(source->data_size == 0); + +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index 9c515f9c8..4fac55cc9 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -353,7 +353,7 @@ static int remove_source(RemoteServer *s, int fd) { + + static int add_source(RemoteServer *s, int fd, char* name, bool own_name) { + +- RemoteSource *source; ++ RemoteSource *source = NULL; + int r; + + /* This takes ownership of name, even on failure, if own_name is true. */ +@@ -1148,7 +1148,7 @@ static int dispatch_raw_connection_event(sd_event_source *event, + .size = sizeof(union sockaddr_union), + .type = SOCK_STREAM, + }; +- char *hostname; ++ char *hostname = NULL; + + fd2 = accept_connection("raw", fd, &addr, &hostname); + if (fd2 < 0) +diff --git a/src/journal/catalog.c b/src/journal/catalog.c +index f17023284..a9c40c6d4 100644 +--- a/src/journal/catalog.c ++++ b/src/journal/catalog.c +@@ -559,7 +559,7 @@ static const char *find_id(void *p, sd_id128_t id) { + int catalog_get(const char* database, sd_id128_t id, char **_text) { + _cleanup_close_ int fd = -1; + void *p = NULL; +- struct stat st; ++ struct stat st = {}; + char *text = NULL; + int r; + const char *s; +diff --git a/src/journal/coredump.c b/src/journal/coredump.c +index f7ba0191e..59ccd46bb 100644 +--- a/src/journal/coredump.c ++++ b/src/journal/coredump.c +@@ -244,7 +244,7 @@ static int maybe_remove_external_coredump(const char *filename, off_t size) { + + static int make_filename(const char *info[_INFO_LEN], char **ret) { + _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL; +- sd_id128_t boot; ++ sd_id128_t boot = {}; + int r; + + assert(info); +@@ -843,7 +843,7 @@ log: + /* Optionally store the entire coredump in the journal */ + if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && + coredump_size <= (off_t) arg_journal_size_max) { +- size_t sz; ++ size_t sz = 0; + + /* Store the coredump itself in the journal */ + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index ef1849787..2a93460d4 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -911,7 +911,7 @@ int journal_file_find_data_object_with_hash( + if (o->object.flags & OBJECT_COMPRESSION_MASK) { + #if defined(HAVE_XZ) || defined(HAVE_LZ4) + uint64_t l; +- size_t rsize; ++ size_t rsize = 0; + + l = le64toh(o->object.size); + if (l <= offsetof(Object, data.payload)) +@@ -1075,7 +1075,7 @@ static int journal_file_append_data( + + #if defined(HAVE_XZ) || defined(HAVE_LZ4) + if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { +- size_t rsize; ++ size_t rsize = 0; + + compression = compress_blob(data, size, o->data.payload, &rsize); + +@@ -2903,7 +2903,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 + + if (o->object.flags & OBJECT_COMPRESSION_MASK) { + #if defined(HAVE_XZ) || defined(HAVE_LZ4) +- size_t rsize; ++ size_t rsize = 0; + + r = decompress_blob(o->object.flags & OBJECT_COMPRESSION_MASK, + o->data.payload, l, &from->compress_buffer, &from->compress_buffer_size, &rsize, 0); +diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c +index 832c327b3..856d11e4e 100644 +--- a/src/journal/journal-vacuum.c ++++ b/src/journal/journal-vacuum.c +@@ -76,7 +76,7 @@ static void patch_realtime( + unsigned long long *realtime) { + + _cleanup_free_ const char *path = NULL; +- usec_t x, crtime; ++ usec_t x, crtime = 0; + + /* The timestamp was determined by the file name, but let's + * see if the file might actually be older than the file name +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index a38ce4b8f..6ba884779 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1644,7 +1644,7 @@ static int verify(sd_journal *j) { + + ORDERED_HASHMAP_FOREACH(f, j->files, i) { + int k; +- usec_t first, validated, last; ++ usec_t first = 0, validated = 0, last = 0; + + #ifdef HAVE_GCRYPT + if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) +diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c +index 3996e778e..b8caeb3d4 100644 +--- a/src/journal/test-journal-stream.c ++++ b/src/journal/test-journal-stream.c +@@ -42,7 +42,7 @@ static void verify_contents(sd_journal *j, unsigned skip) { + const void *d; + char *k, *c; + size_t l; +- unsigned u; ++ unsigned u = 0; + + assert_se(sd_journal_get_cursor(j, &k) >= 0); + printf("cursor: %s\n", k); +diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c +index e43d70d3c..e32783f3e 100644 +--- a/src/libsystemd-network/lldp-tlv.c ++++ b/src/libsystemd-network/lldp-tlv.c +@@ -156,7 +156,7 @@ static inline int tlv_packet_read_internal(tlv_section *m, void **data) { + } + + int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +@@ -174,7 +174,7 @@ int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { + + int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) { + uint16_t t; +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +@@ -211,7 +211,7 @@ int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) { + } + + int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +@@ -229,7 +229,7 @@ int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { + } + + int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) { +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c +index 3f89f344d..0f284eb6a 100644 +--- a/src/libsystemd-network/sd-dhcp-server.c ++++ b/src/libsystemd-network/sd-dhcp-server.c +@@ -776,7 +776,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, + if (pool_offset >= 0 && + server->bound_leases[pool_offset] == existing_lease) { + DHCPLease *lease; +- usec_t time_now; ++ usec_t time_now = 0; + + if (!existing_lease) { + lease = new0(DHCPLease, 1); +diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c +index 4f49b799e..83e58a3db 100644 +--- a/src/libsystemd-network/sd-pppoe.c ++++ b/src/libsystemd-network/sd-pppoe.c +@@ -340,7 +340,7 @@ static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata); + + static int pppoe_arm_timeout(sd_pppoe *ppp) { + _cleanup_event_source_unref_ sd_event_source *timeout = NULL; +- usec_t next_timeout; ++ usec_t next_timeout = 0; + int r; + + assert(ppp); +diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c +index f71749f72..cc0677bdf 100644 +--- a/src/libsystemd/sd-login/sd-login.c ++++ b/src/libsystemd/sd-login/sd-login.c +@@ -82,7 +82,7 @@ _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { + } + + _public_ int sd_peer_get_session(int fd, char **session) { +- struct ucred ucred; ++ struct ucred ucred = {}; + int r; + + assert_return(fd >= 0, -EINVAL); +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index aa83f32f5..778670b73 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -964,7 +964,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { + return -ENOMEM; + + } else if (streq(a, "_TTL")) { +- long long unsigned x; ++ long long unsigned x = 0; + usec_t time; + + r = safe_atollu(b, &x); +diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c +index 74b063414..bc1a90db1 100644 +--- a/src/resolve/resolved-dns-transaction.c ++++ b/src/resolve/resolved-dns-transaction.c +@@ -252,7 +252,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { + fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port); + else { + union in_addr_union address; +- int family; ++ int family = AF_UNSPEC; + + /* Otherwise, try to talk to the owner of a + * the IP address, in case this is a reverse +diff --git a/src/resolve/test-dns-domain.c b/src/resolve/test-dns-domain.c +index ebc8d98fc..4963a9c6a 100644 +--- a/src/resolve/test-dns-domain.c ++++ b/src/resolve/test-dns-domain.c +@@ -162,7 +162,7 @@ static void test_dns_name_single_label(void) { + + static void test_dns_name_reverse_one(const char *address, const char *name) { + _cleanup_free_ char *p = NULL; +- union in_addr_union a, b; ++ union in_addr_union a, b = {}; + int familya, familyb; + + assert_se(in_addr_from_string_auto(address, &familya, &a) >= 0); +diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c +index 73907c635..20a69bdbf 100644 +--- a/src/shared/base-filesystem.c ++++ b/src/shared/base-filesystem.c +@@ -55,7 +55,7 @@ static const BaseFilesystem table[] = { + int base_filesystem_create(const char *root) { + _cleanup_close_ int fd = -1; + unsigned i; +- int r; ++ int r = 0; + + fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + if (fd < 0) +diff --git a/src/shared/capability.c b/src/shared/capability.c +index 915ceb9d9..2b963fde3 100644 +--- a/src/shared/capability.c ++++ b/src/shared/capability.c +@@ -55,7 +55,7 @@ unsigned long cap_last_cap(void) { + static thread_local unsigned long saved; + static thread_local bool valid = false; + _cleanup_free_ char *content = NULL; +- unsigned long p; ++ unsigned long p = 0; + int r; + + if (valid) +diff --git a/src/shared/copy.c b/src/shared/copy.c +index 0239a5806..2a0cb2808 100644 +--- a/src/shared/copy.c ++++ b/src/shared/copy.c +@@ -360,7 +360,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) { + } + + int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) { +- int fdt, r; ++ int fdt = -1, r; + + assert(from); + assert(to); +@@ -390,7 +390,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned + } + + int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) { +- _cleanup_free_ char *t; ++ _cleanup_free_ char *t = NULL; + int r; + + assert(from); +@@ -415,7 +415,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace + int copy_times(int fdf, int fdt) { + struct timespec ut[2]; + struct stat st; +- usec_t crtime; ++ usec_t crtime = 0; + + assert(fdf >= 0); + assert(fdt >= 0); +diff --git a/src/shared/install.c b/src/shared/install.c +index 9962508b1..61aaafe7b 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2046,7 +2046,7 @@ UnitFileState unit_file_lookup_state( + _cleanup_(install_context_done) InstallContext c = {}; + InstallInfo *i; + UnitFileState state; +- int r; ++ int r = 0; + + assert(paths); + assert(name); +diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c +index 8c374116a..a572be94b 100644 +--- a/src/shared/logs-show.c ++++ b/src/shared/logs-show.c +@@ -993,7 +993,7 @@ static int show_journal(FILE *f, + + if (warn_cutoff && line < how_many && not_before > 0) { + sd_id128_t boot_id; +- usec_t cutoff; ++ usec_t cutoff = 0; + + /* Check whether the cutoff line is too early */ + +diff --git a/src/shared/util.c b/src/shared/util.c +index 303026152..4c441a544 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3073,7 +3073,7 @@ int getttyname_malloc(int fd, char **ret) { + + int getttyname_harder(int fd, char **r) { + int k; +- char *s; ++ char *s = NULL; + + k = getttyname_malloc(fd, &s); + if (k < 0) +@@ -3627,7 +3627,7 @@ char **replace_env_argv(char **argv, char **env) { + /* If $FOO appears as single word, replace it by the split up variable */ + if ((*i)[0] == '$' && (*i)[1] != '{') { + char *e; +- char **w, **m; ++ char **w, **m = NULL; + unsigned q; + + e = strv_env_get(env, *i+1); +diff --git a/src/test/test-path.c b/src/test/test-path.c +index 4f9f5c134..a3295aa99 100644 +--- a/src/test/test-path.c ++++ b/src/test/test-path.c +@@ -33,7 +33,7 @@ static int setup_test(Manager **m) { + char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit", + "directorynotempty", "makedirectory"); + char **test_path; +- Manager *tmp; ++ Manager *tmp = NULL; + int r; + + assert_se(m); +diff --git a/src/test/test-pty.c b/src/test/test-pty.c +index cab569a9d..67c125a4c 100644 +--- a/src/test/test-pty.c ++++ b/src/test/test-pty.c +@@ -97,7 +97,7 @@ static void run_parent(Pty *pty) { + + static void test_pty(void) { + pid_t pid; +- Pty *pty; ++ Pty *pty = NULL; + + rcvsiz = 0; + zero(rcvbuf); +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index 489593f4f..ad6a82e50 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -474,7 +474,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, + + int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) { + const char *name; +- char *driver; ++ char *driver = NULL; + int r; + + name = udev_device_get_sysname(device); diff --git a/SOURCES/0377-journalctl-rework-code-that-checks-whether-we-have-a.patch b/SOURCES/0377-journalctl-rework-code-that-checks-whether-we-have-a.patch new file mode 100644 index 00000000..81075d05 --- /dev/null +++ b/SOURCES/0377-journalctl-rework-code-that-checks-whether-we-have-a.patch @@ -0,0 +1,339 @@ +From e9bef2f8146ccf152459248775eec8e8ce123865 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 22 Apr 2015 22:54:23 +0200 +Subject: [PATCH] journalctl: rework code that checks whether we have access to + /var/log/journal + +- fix some memory leaks on error conditions + +- handle all error cases properly, and log about failures + +- move HAVE_ACL and no-HAVE_ACL code closer to each other + +Cherry-picked from: e346512c684e9efae84c6442f7e6a5781564ecde +Related: #1318994 +--- + src/journal/journalctl.c | 120 ++++++++++++++++++++++++----------------------- + src/shared/acl-util.c | 102 ++++++++++++++++++++++------------------ + src/shared/acl-util.h | 2 +- + 3 files changed, 119 insertions(+), 105 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 6ba884779..f60e6415f 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1680,61 +1680,76 @@ static int verify(sd_journal *j) { + return r; + } + +-#ifdef HAVE_ACL + static int access_check_var_log_journal(sd_journal *j) { ++#ifdef HAVE_ACL + _cleanup_strv_free_ char **g = NULL; +- bool have_access; ++ const char* dir; ++#endif + int r; + + assert(j); + +- have_access = in_group("systemd-journal") > 0; ++ if (arg_quiet) ++ return 0; + +- if (!have_access) { +- const char* dir; ++ /* If we are root, we should have access, don't warn. */ ++ if (getuid() == 0) ++ return 0; + +- if (access("/run/log/journal", F_OK) >= 0) +- dir = "/run/log/journal"; +- else +- dir = "/var/log/journal"; ++ /* If we are in the 'systemd-journal' group, we should have ++ * access too. */ ++ r = in_group("systemd-journal"); ++ if (r < 0) ++ return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m"); ++ if (r > 0) ++ return 0; + +- /* Let's enumerate all groups from the default ACL of +- * the directory, which generally should allow access +- * to most journal files too */ +- r = search_acl_groups(&g, dir, &have_access); +- if (r < 0) +- return r; +- } ++#ifdef HAVE_ACL ++ if (laccess("/run/log/journal", F_OK) >= 0) ++ dir = "/run/log/journal"; ++ else ++ dir = "/var/log/journal"; + +- if (!have_access) { ++ /* If we are in any of the groups listed in the journal ACLs, ++ * then all is good, too. Let's enumerate all groups from the ++ * default ACL of the directory, which generally should allow ++ * access to most journal files too. */ ++ r = acl_search_groups(dir, &g); ++ if (r < 0) ++ return log_error_errno(r, "Failed to search journal ACL: %m"); ++ if (r > 0) ++ return 0; + +- if (strv_isempty(g)) +- log_notice("Hint: You are currently not seeing messages from other users and the system.\n" +- " Users in the 'systemd-journal' group can see all messages. Pass -q to\n" +- " turn off this notice."); +- else { +- _cleanup_free_ char *s = NULL; ++ /* Print a pretty list, if there were ACLs set. */ ++ if (!strv_isempty(g)) { ++ _cleanup_free_ char *s = NULL; + +- r = strv_extend(&g, "systemd-journal"); +- if (r < 0) +- return log_oom(); ++ /* Thre are groups in the ACL, let's list them */ ++ r = strv_extend(&g, "systemd-journal"); ++ if (r < 0) ++ return log_oom(); + +- strv_sort(g); +- strv_uniq(g); ++ strv_sort(g); ++ strv_uniq(g); + +- s = strv_join(g, "', '"); +- if (!s) +- return log_oom(); ++ s = strv_join(g, "', '"); ++ if (!s) ++ return log_oom(); + +- log_notice("Hint: You are currently not seeing messages from other users and the system.\n" +- " Users in groups '%s' can see all messages.\n" +- " Pass -q to turn off this notice.", s); +- } ++ log_notice("Hint: You are currently not seeing messages from other users and the system.\n" ++ " Users in groups '%s' can see all messages.\n" ++ " Pass -q to turn off this notice.", s); ++ return 1; + } ++#endif + +- return 0; ++ /* If no ACLs were found, print a short version of the message. */ ++ log_notice("Hint: You are currently not seeing messages from other users and the system.\n" ++ " Users in the 'systemd-journal' group can see all messages. Pass -q to\n" ++ " turn off this notice."); ++ ++ return 1; + } +-#endif + + static int access_check(sd_journal *j) { + Iterator it; +@@ -1746,30 +1761,15 @@ static int access_check(sd_journal *j) { + if (set_isempty(j->errors)) { + if (ordered_hashmap_isempty(j->files)) + log_notice("No journal files were found."); ++ + return 0; + } + + if (set_contains(j->errors, INT_TO_PTR(-EACCES))) { +-#ifdef HAVE_ACL +- /* If /run/log/journal or /var/log/journal exist, try +- to pring a nice notice if the user lacks access to it. */ +- if (!arg_quiet && geteuid() != 0) { +- r = access_check_var_log_journal(j); +- if (r < 0) +- return r; +- } +-#else +- if (geteuid() != 0 && in_group("systemd-journal") <= 0) { +- log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n" +- "group may access messages."); +- return -EACCES; +- } +-#endif ++ (void) access_check_var_log_journal(j); + +- if (ordered_hashmap_isempty(j->files)) { +- log_error("No journal files were opened due to insufficient permissions."); +- r = -EACCES; +- } ++ if (ordered_hashmap_isempty(j->files)) ++ r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions."); + } + + SET_FOREACH(code, j->errors, it) { +@@ -1778,8 +1778,12 @@ static int access_check(sd_journal *j) { + err = -PTR_TO_INT(code); + assert(err > 0); + +- if (err != EACCES) +- log_warning_errno(err, "Error was encountered while opening journal files: %m"); ++ if (err == EACCES) ++ continue; ++ ++ log_warning_errno(err, "Error was encountered while opening journal files: %m"); ++ if (r == 0) ++ r = -err; + } + + return r; +diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c +index e67e9acb6..d18a02f50 100644 +--- a/src/shared/acl-util.c ++++ b/src/shared/acl-util.c +@@ -82,17 +82,18 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { + + if (tag == ACL_MASK) + return 0; +- if (IN_SET(tag, ACL_USER, ACL_GROUP)) +- goto calc; ++ ++ if (IN_SET(tag, ACL_USER, ACL_GROUP)) { ++ if (acl_calc_mask(acl_p) < 0) ++ return -errno; ++ ++ return 1; ++ } + } + if (r < 0) + return -errno; +- return 0; + +-calc: +- if (acl_calc_mask(acl_p) < 0) +- return -errno; +- return 1; ++ return 0; + } + + int add_base_acls_if_needed(acl_t *acl_p, const char *path) { +@@ -159,59 +160,68 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { + return 0; + } + +-int search_acl_groups(char*** dst, const char* path, bool* belong) { +- acl_t acl; ++int acl_search_groups(const char *path, char ***ret_groups) { ++ _cleanup_strv_free_ char **g = NULL; ++ _cleanup_(acl_free) acl_t acl = NULL; ++ bool ret = false; ++ acl_entry_t entry; ++ int r; + + assert(path); +- assert(belong); + + acl = acl_get_file(path, ACL_TYPE_DEFAULT); +- if (acl) { +- acl_entry_t entry; +- int r; +- +- r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); +- while (r > 0) { +- acl_tag_t tag; +- gid_t *gid; +- char *name; ++ if (!acl) ++ return -errno; + +- r = acl_get_tag_type(entry, &tag); +- if (r < 0) +- break; ++ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); ++ for (;;) { ++ _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL; ++ acl_tag_t tag; ++ ++ if (r < 0) ++ return -errno; ++ if (r == 0) ++ break; ++ ++ if (acl_get_tag_type(entry, &tag) < 0) ++ return -errno; + +- if (tag != ACL_GROUP) +- goto next; ++ if (tag != ACL_GROUP) ++ goto next; + +- gid = acl_get_qualifier(entry); +- if (!gid) +- break; ++ gid = acl_get_qualifier(entry); ++ if (!gid) ++ return -errno; ++ ++ if (in_gid(*gid) > 0) { ++ if (!ret_groups) ++ return true; + +- if (in_gid(*gid) > 0) { +- *belong = true; +- break; +- } ++ ret = true; ++ } ++ ++ if (ret_groups) { ++ char *name; + + name = gid_to_name(*gid); +- if (!name) { +- acl_free(acl); +- return log_oom(); +- } +- +- r = strv_consume(dst, name); +- if (r < 0) { +- acl_free(acl); +- return log_oom(); +- } +- +- next: +- r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); ++ if (!name) ++ return -ENOMEM; ++ ++ r = strv_consume(&g, name); ++ if (r < 0) ++ return r; + } + +- acl_free(acl); ++ next: ++ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); + } + +- return 0; ++ if (ret_groups) { ++ *ret_groups = g; ++ g = NULL; ++ } ++ ++ return ret; + } + + int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) { +diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h +index fdb90063f..c8bcc266d 100644 +--- a/src/shared/acl-util.h ++++ b/src/shared/acl-util.h +@@ -32,7 +32,7 @@ + int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry); + int calc_acl_mask_if_needed(acl_t *acl_p); + int add_base_acls_if_needed(acl_t *acl_p, const char *path); +-int search_acl_groups(char*** dst, const char* path, bool* belong); ++int acl_search_groups(const char* path, char ***ret_groups); + int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask); + int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); + diff --git a/SOURCES/0378-journalctl-Improve-boot-ID-lookup.patch b/SOURCES/0378-journalctl-Improve-boot-ID-lookup.patch new file mode 100644 index 00000000..c9ebbff8 --- /dev/null +++ b/SOURCES/0378-journalctl-Improve-boot-ID-lookup.patch @@ -0,0 +1,55 @@ +From a6db5931947acb807b37cac9c832d68cd66fbc2a Mon Sep 17 00:00:00 2001 +From: Jan Janssen +Date: Fri, 1 May 2015 15:15:16 +0200 +Subject: [PATCH] journalctl: Improve boot ID lookup + +This method should greatly improve offset based lookup, by simply jumping +from one boot to the next boot. It starts at the journal head to get the +a boot ID, makes a _BOOT_ID match and then comes from the opposite +journal direction (tail) to get to the end that boot. After flushing the matches +and advancing the journal from that exact position, we arrive at the start +of next boot. Rinse and repeat. + +This is faster than the old method of aggregating the full boot listing just +so we can jump to a specific boot, which can be a real pain on big journals +just for a mere "-b -1" case. + +As an additional benefit --list-boots should improve slightly too, because +it does less seeking. + +Note that there can be a change in boot order with this lookup method +because it will use the order of boots in the journal, not the realtime stamp +stored in them. That's arguably better, though. +Another deficiency is that it will get confused with boots interleaving in the +journal, therefore, it will refuse operation in --merge, --file and --directory mode. + +https://bugs.freedesktop.org/show_bug.cgi?id=72601 + +Conflicts: + src/journal/journalctl.c + +Cherry-picked from: 596a23293d28f93843aef86721b90043e74d3081 +Related: #1318994 +--- + src/journal/journalctl.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index f60e6415f..c7a19f236 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1166,11 +1166,10 @@ static int add_boot(sd_journal *j) { + const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); + + if (sd_id128_is_null(arg_boot_id)) +- log_error("Data from the specified boot (%+i) is not available: %s", +- arg_boot_offset, reason); ++ log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason); + else +- log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s", +- SD_ID128_FORMAT_VAL(arg_boot_id), reason); ++ log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s", ++ SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason); + + return r == 0 ? -ENODATA : r; + } diff --git a/SOURCES/0379-journalctl-only-have-a-single-exit-path-from-main.patch b/SOURCES/0379-journalctl-only-have-a-single-exit-path-from-main.patch new file mode 100644 index 00000000..88ca4840 --- /dev/null +++ b/SOURCES/0379-journalctl-only-have-a-single-exit-path-from-main.patch @@ -0,0 +1,217 @@ +From 134a85fc4fa6d1c3209e11415b2610147e2e1aac Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 18 May 2015 23:50:34 +0200 +Subject: [PATCH] journalctl: only have a single exit path from main() + +That way we can be sure we execute the destructors properly, and can be +valgrind-clean. + +Cherry-picked from: 909dea0c7ced0042fa3acd8cd05f5007a2cf2cea +Related: #1318994 +--- + src/journal/journalctl.c | 51 +++++++++++++++++++++++++----------------------- + 1 file changed, 27 insertions(+), 24 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index c7a19f236..31da357c1 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -532,7 +532,7 @@ static int parse_argv(int argc, char *argv[]) { + arg_boot = true; + + if (optarg) { +- r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset); ++ r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset); + if (r < 0) { + log_error("Failed to parse boot descriptor '%s'", optarg); + return -EINVAL; +@@ -1929,12 +1929,12 @@ int main(int argc, char *argv[]) { + if (r < 0) { + log_error_errno(r, "Failed to open %s: %m", + arg_directory ? arg_directory : arg_file ? "files" : "journal"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = access_check(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + if (arg_action == ACTION_VERIFY) { + r = verify(j); +@@ -1943,7 +1943,8 @@ int main(int argc, char *argv[]) { + + if (arg_action == ACTION_PRINT_HEADER) { + journal_print_header(j); +- return EXIT_SUCCESS; ++ r = 0; ++ goto finish; + } + + if (arg_action == ACTION_DISK_USAGE) { +@@ -1952,11 +1953,11 @@ int main(int argc, char *argv[]) { + + r = sd_journal_get_usage(j, &bytes); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + printf("Archived and active journals take up %s on disk.\n", + format_bytes(sbytes, sizeof(sbytes), bytes)); +- return EXIT_SUCCESS; ++ goto finish; + } + + if (arg_action == ACTION_VACUUM) { +@@ -1976,7 +1977,7 @@ int main(int argc, char *argv[]) { + } + } + +- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++ goto finish; + } + + if (arg_action == ACTION_LIST_BOOTS) { +@@ -1995,11 +1996,11 @@ int main(int argc, char *argv[]) { + * It may need to seek the journal to find parent boot IDs. */ + r = add_boot(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + r = add_dmesg(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + r = add_units(j); + strv_free(arg_system_units); +@@ -2007,25 +2008,25 @@ int main(int argc, char *argv[]) { + + if (r < 0) { + log_error_errno(r, "Failed to add filter for units: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = add_syslog_identifier(j); + if (r < 0) { + log_error_errno(r, "Failed to add filter for syslog identifiers: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = add_priorities(j); + if (r < 0) { + log_error_errno(r, "Failed to add filter for priorities: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = add_matches(j, argv + optind); + if (r < 0) { + log_error_errno(r, "Failed to add filters: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) { +@@ -2042,13 +2043,13 @@ int main(int argc, char *argv[]) { + r = sd_journal_set_data_threshold(j, 0); + if (r < 0) { + log_error("Failed to unset data size threshold"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_query_unique(j, arg_field); + if (r < 0) { + log_error_errno(r, "Failed to query unique data objects: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + SD_JOURNAL_FOREACH_UNIQUE(j, data, size) { +@@ -2066,22 +2067,24 @@ int main(int argc, char *argv[]) { + n_shown ++; + } + +- return EXIT_SUCCESS; ++ r = 0; ++ goto finish; + } + + /* Opening the fd now means the first sd_journal_wait() will actually wait */ + if (arg_follow) { + r = sd_journal_get_fd(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + } + + if (arg_cursor || arg_after_cursor) { + r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor); + if (r < 0) { + log_error_errno(r, "Failed to seek to cursor: %m"); +- return EXIT_FAILURE; ++ goto finish; + } ++ + if (!arg_reverse) + r = sd_journal_next_skip(j, 1 + !!arg_after_cursor); + else +@@ -2099,7 +2102,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_realtime_usec(j, arg_since); + if (r < 0) { + log_error_errno(r, "Failed to seek to date: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + r = sd_journal_next(j); + +@@ -2107,7 +2110,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_realtime_usec(j, arg_until); + if (r < 0) { + log_error_errno(r, "Failed to seek to date: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + r = sd_journal_previous(j); + +@@ -2115,7 +2118,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_tail(j); + if (r < 0) { + log_error_errno(r, "Failed to seek to tail: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_previous_skip(j, arg_lines); +@@ -2124,7 +2127,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_tail(j); + if (r < 0) { + log_error_errno(r, "Failed to seek to tail: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_previous(j); +@@ -2133,7 +2136,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_head(j); + if (r < 0) { + log_error_errno(r, "Failed to seek to head: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_next(j); +@@ -2141,7 +2144,7 @@ int main(int argc, char *argv[]) { + + if (r < 0) { + log_error_errno(r, "Failed to iterate through journal: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + if (r == 0) { diff --git a/SOURCES/0380-journalctl-free-all-command-line-argument-objects.patch b/SOURCES/0380-journalctl-free-all-command-line-argument-objects.patch new file mode 100644 index 00000000..b59cb953 --- /dev/null +++ b/SOURCES/0380-journalctl-free-all-command-line-argument-objects.patch @@ -0,0 +1,45 @@ +From 4cbe0933587385ed0d811ce11264d65d15b05cfd Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 18 May 2015 23:54:05 +0200 +Subject: [PATCH] journalctl: free all command line argument objects + +let's try to be valgrind clean + +Cherry-picked from: d52da2057f06c49d50ed99300dc407c0227b1a32 +Related: #1318994 +--- + src/journal/journalctl.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 31da357c1..92ee3fb27 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -39,7 +39,6 @@ + + #include "sd-journal.h" + #include "sd-bus.h" +- + #include "log.h" + #include "logs-show.h" + #include "util.h" +@@ -2003,9 +2002,6 @@ int main(int argc, char *argv[]) { + goto finish; + + r = add_units(j); +- strv_free(arg_system_units); +- strv_free(arg_user_units); +- + if (r < 0) { + log_error_errno(r, "Failed to add filter for units: %m"); + goto finish; +@@ -2283,5 +2279,9 @@ finish: + + strv_free(arg_file); + ++ strv_free(arg_syslog_identifier); ++ strv_free(arg_system_units); ++ strv_free(arg_user_units); ++ + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + } diff --git a/SOURCES/0381-journalctl-rename-boot_id_t-to-BootId.patch b/SOURCES/0381-journalctl-rename-boot_id_t-to-BootId.patch new file mode 100644 index 00000000..1b947c32 --- /dev/null +++ b/SOURCES/0381-journalctl-rename-boot_id_t-to-BootId.patch @@ -0,0 +1,120 @@ +From 1b84db099fc619719026679236a9db0199fd129a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 00:24:27 +0200 +Subject: [PATCH] journalctl: rename boot_id_t to BootId + +So far we tried to reserve the _t suffix to types we use like a value in +contrast to types we use as objects, hence let's do this in journalctl +too. + +Cherry-picked from: 45bc27b621c51b9d0e0229835deb6d188bcd417b +Related: #1318994 +--- + src/journal/journalctl.c | 42 +++++++++++++++++++++++------------------- + 1 file changed, 23 insertions(+), 19 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 92ee3fb27..e84dd4c9d 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -128,12 +128,12 @@ static enum { + ACTION_VACUUM, + } arg_action = ACTION_SHOW; + +-typedef struct boot_id_t { ++typedef struct BootId { + sd_id128_t id; + uint64_t first; + uint64_t last; +- LIST_FIELDS(struct boot_id_t, boot_list); +-} boot_id_t; ++ LIST_FIELDS(struct BootId, boot_list); ++} BootId; + + static int add_matches_for_device(sd_journal *j, const char *devpath) { + int r; +@@ -934,13 +934,15 @@ static int add_matches(sd_journal *j, char **args) { + return 0; + } + +-static int discover_next_boot(sd_journal *j, +- boot_id_t **boot, +- bool advance_older, +- bool read_realtime) { ++static int discover_next_boot( ++ sd_journal *j, ++ BootId **boot, ++ bool advance_older, ++ bool read_realtime) { ++ + int r; + char match[9+32+1] = "_BOOT_ID="; +- _cleanup_free_ boot_id_t *next_boot = NULL; ++ _cleanup_free_ BootId *next_boot = NULL; + + assert(j); + assert(boot); +@@ -965,7 +967,7 @@ static int discover_next_boot(sd_journal *j, + else if (r == 0) + return 0; /* End of journal, yay. */ + +- next_boot = new0(boot_id_t, 1); ++ next_boot = new0(BootId, 1); + if (!next_boot) + return log_oom(); + +@@ -1012,13 +1014,15 @@ static int discover_next_boot(sd_journal *j, + return 0; + } + +-static int get_boots(sd_journal *j, +- boot_id_t **boots, +- boot_id_t *query_ref_boot, +- int ref_boot_offset) { ++static int get_boots( ++ sd_journal *j, ++ BootId **boots, ++ BootId *query_ref_boot, ++ int ref_boot_offset) { ++ + bool skip_once; + int r, count = 0; +- boot_id_t *head = NULL, *tail = NULL; ++ BootId *head = NULL, *tail = NULL; + const bool advance_older = query_ref_boot && ref_boot_offset <= 0; + + assert(j); +@@ -1073,12 +1077,12 @@ static int get_boots(sd_journal *j, + /* No sd_journal_next/previous here. */ + } + +- while (true) { +- _cleanup_free_ boot_id_t *current = NULL; ++ for (;;) { ++ _cleanup_free_ BootId *current = NULL; + + r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); + if (r < 0) { +- boot_id_t *id, *id_next; ++ BootId *id, *id_next; + LIST_FOREACH_SAFE(boot_list, id, id_next, head) + free(id); + return r; +@@ -1116,7 +1120,7 @@ finish: + + static int list_boots(sd_journal *j) { + int w, i, count; +- boot_id_t *id, *id_next, *all_ids; ++ BootId *id, *id_next, *all_ids; + + assert(j); + +@@ -1148,7 +1152,7 @@ static int list_boots(sd_journal *j) { + static int add_boot(sd_journal *j) { + char match[9+32+1] = "_BOOT_ID="; + int r; +- boot_id_t ref_boot_id = {}; ++ BootId ref_boot_id = {}; + + assert(j); + diff --git a/SOURCES/0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch b/SOURCES/0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch new file mode 100644 index 00000000..2ffef784 --- /dev/null +++ b/SOURCES/0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch @@ -0,0 +1,301 @@ +From 603edc22d0516044b72b09ed94a696edd2de7f37 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 10 Jun 2015 19:10:47 +0200 +Subject: [PATCH] util: introduce CMSG_FOREACH() macro and make use of it + everywhere + +It's only marginally shorter then the usual for() loop, but certainly +more readable. + +Cherry-picked from: 2a1288ff89322a2f49c79f6d1832c8164c14a05c +Related: #1318994 +--- + src/core/manager.c | 2 +- + src/core/namespace.c | 3 +-- + src/import/importd.c | 8 ++------ + src/journal/journald-server.c | 2 +- + src/libsystemd-network/sd-dhcp-client.c | 2 +- + src/libsystemd-network/sd-dhcp-server.c | 2 +- + src/libsystemd/sd-bus/bus-container.c | 2 +- + src/libsystemd/sd-bus/bus-socket.c | 16 ++++++++++------ + src/libsystemd/sd-rtnl/rtnl-message.c | 2 +- + src/resolve/resolved-dns-stream.c | 3 ++- + src/resolve/resolved-manager.c | 2 +- + src/shared/macro.h | 3 +++ + src/shared/util.c | 12 +++++++++++- + src/shared/util.h | 2 ++ + src/timesync/timesyncd-manager.c | 2 +- + 15 files changed, 39 insertions(+), 24 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index c5021993e..71dd70c94 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1679,7 +1679,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + return -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + + fd_array = (int*) CMSG_DATA(cmsg); +diff --git a/src/core/namespace.c b/src/core/namespace.c +index ebd5fb334..00495c144 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -658,12 +658,11 @@ int setup_netns(int netns_storage_socket[2]) { + } else { + /* Yay, found something, so let's join the namespace */ + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); + netns = *(int*) CMSG_DATA(cmsg); + } +- } + + if (setns(netns, CLONE_NEWNET) < 0) { + r = -errno; +diff --git a/src/import/importd.c b/src/import/importd.c +index 9aaf991f8..a29630b12 100644 +--- a/src/import/importd.c ++++ b/src/import/importd.c +@@ -507,12 +507,8 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void + return -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { +- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { +- close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); +- log_warning("Somebody sent us unexpected fds, ignoring."); +- return 0; +- } else if (cmsg->cmsg_level == SOL_SOCKET && ++ CMSG_FOREACH(cmsg, &msghdr) { ++ if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 6a35ebbde..1eb1394d1 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1176,7 +1176,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void + return -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ CMSG_FOREACH(cmsg, &msghdr) { + + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && +diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c +index 5f90617b9..870850ed3 100644 +--- a/src/libsystemd-network/sd-dhcp-client.c ++++ b/src/libsystemd-network/sd-dhcp-client.c +@@ -1590,7 +1590,7 @@ static int client_receive_message_raw(sd_event_source *s, int fd, + } else if ((size_t)len < sizeof(DHCPPacket)) + return 0; + +- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { ++ CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_PACKET && + cmsg->cmsg_type == PACKET_AUXDATA && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) { +diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c +index 0f284eb6a..c9d0ace72 100644 +--- a/src/libsystemd-network/sd-dhcp-server.c ++++ b/src/libsystemd-network/sd-dhcp-server.c +@@ -903,7 +903,7 @@ static int server_receive_message(sd_event_source *s, int fd, + else if ((size_t)len < sizeof(DHCPMessage)) + return 0; + +- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { ++ CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) { +diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c +index d29b98a26..10ab71431 100644 +--- a/src/libsystemd/sd-bus/bus-container.c ++++ b/src/libsystemd/sd-bus/bus-container.c +@@ -222,7 +222,7 @@ int bus_container_connect_kernel(sd_bus *b) { + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; +diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c +index a3c3a45b4..ab56ef4f3 100644 +--- a/src/libsystemd/sd-bus/bus-socket.c ++++ b/src/libsystemd/sd-bus/bus-socket.c +@@ -503,7 +503,6 @@ static int bus_socket_read_auth(sd_bus *b) { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)]; + } control; +- struct cmsghdr *cmsg; + bool handle_cmsg = false; + + assert(b); +@@ -554,8 +553,10 @@ static int bus_socket_read_auth(sd_bus *b) { + + b->rbuffer_size += k; + +- if (handle_cmsg) +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ if (handle_cmsg) { ++ struct cmsghdr *cmsg; ++ ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int j; +@@ -569,6 +570,7 @@ static int bus_socket_read_auth(sd_bus *b) { + } else + log_debug("Got unexpected auxiliary data with level=%d and type=%d", + cmsg->cmsg_level, cmsg->cmsg_type); ++ } + + r = bus_socket_auth_verify(b); + if (r != 0) +@@ -930,7 +932,6 @@ int bus_socket_read_message(sd_bus *bus) { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)]; + } control; +- struct cmsghdr *cmsg; + bool handle_cmsg = false; + + assert(bus); +@@ -976,8 +977,10 @@ int bus_socket_read_message(sd_bus *bus) { + + bus->rbuffer_size += k; + +- if (handle_cmsg) +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ if (handle_cmsg) { ++ struct cmsghdr *cmsg; ++ ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int n, *f; +@@ -1005,6 +1008,7 @@ int bus_socket_read_message(sd_bus *bus) { + } else + log_debug("Got unexpected auxiliary data with level=%d and type=%d", + cmsg->cmsg_level, cmsg->cmsg_type); ++ } + + r = bus_socket_read_message_need(bus, &need); + if (r < 0) +diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c +index 9276bbdeb..cc84253f1 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-message.c ++++ b/src/libsystemd/sd-rtnl/rtnl-message.c +@@ -1444,7 +1444,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool + return (errno == EAGAIN || errno == EINTR) ? 0 : -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { ++ CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { +diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c +index 4c0b557ba..7f47e7223 100644 +--- a/src/resolve/resolved-dns-stream.c ++++ b/src/resolve/resolved-dns-stream.c +@@ -113,7 +113,8 @@ static int dns_stream_identify(DnsStream *s) { + + mh.msg_control = &control; + mh.msg_controllen = sl; +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ ++ CMSG_FOREACH(cmsg, &mh) { + + if (cmsg->cmsg_level == IPPROTO_IPV6) { + assert(s->peer.sa.sa_family == AF_INET6); +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index 7c253aa13..173ab8a14 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -920,7 +920,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { + } else + return -EAFNOSUPPORT; + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ CMSG_FOREACH(cmsg, &mh) { + + if (cmsg->cmsg_level == IPPROTO_IPV6) { + assert(p->family == AF_INET6); +diff --git a/src/shared/macro.h b/src/shared/macro.h +index 9d857dc8d..7a57f4e5b 100644 +--- a/src/shared/macro.h ++++ b/src/shared/macro.h +@@ -471,4 +471,7 @@ static inline bool GID_IS_INVALID(gid_t gid) { + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + ++#define CMSG_FOREACH(cmsg, mh) \ ++ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) ++ + #include "log.h" +diff --git a/src/shared/util.c b/src/shared/util.c +index 4c441a544..357fbfe7d 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -7887,7 +7887,7 @@ int openpt_in_namespace(pid_t pid, int flags) { + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; +@@ -8375,6 +8375,16 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k + return -1; + } + ++void cmsg_close_all(struct msghdr *mh) { ++ struct cmsghdr *cmsg; ++ ++ assert(mh); ++ ++ CMSG_FOREACH(cmsg, mh) ++ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) ++ close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); ++} ++ + char *shell_maybe_quote(const char *s) { + const char *p; + char *r, *t; +diff --git a/src/shared/util.h b/src/shared/util.h +index be04524cc..12afcc342 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -1082,6 +1082,8 @@ void sigkill_wait(pid_t *pid); + + int syslog_parse_priority(const char **p, int *priority, bool with_facility); + ++void cmsg_close_all(struct msghdr *mh); ++ + char *shell_maybe_quote(const char *s); + + typedef enum ExtractFlags { +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 73ac7eecb..5cc196820 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -539,7 +539,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + } + + recv_time = NULL; +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level != SOL_SOCKET) + continue; + diff --git a/SOURCES/0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch b/SOURCES/0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch new file mode 100644 index 00000000..c7941a43 --- /dev/null +++ b/SOURCES/0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch @@ -0,0 +1,251 @@ +From 6d1ef1fb841a0b3b4c53b560892f3570b3379dc9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 10 Jun 2015 19:24:58 +0200 +Subject: [PATCH] journald: don't employ inner loop for reading from incoming + sockets + +Otherwise, if the socket is constantly busy we will never return to the +event loop, but we really need to to dispatch other (possibly more +high-priority) events too. Hence, return after dispatching one message +to the event handler, and rely on the event loop calling us back +right-away. + +Fixes #125 + +Related: #1318994 +Cherry-picked from: a315ac4e076c4ce7ce3e5c95792cf916d5e918c5 +--- + src/journal/journald-server.c | 204 +++++++++++++++++++++--------------------- + 1 file changed, 100 insertions(+), 104 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 1eb1394d1..275224dc9 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1103,6 +1103,42 @@ finish: + + int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Server *s = userdata; ++ struct ucred *ucred = NULL; ++ struct timeval *tv = NULL; ++ struct cmsghdr *cmsg; ++ char *label = NULL; ++ size_t label_len = 0, m; ++ struct iovec iovec; ++ ssize_t n; ++ int *fds = NULL, v = 0; ++ unsigned n_fds = 0; ++ ++ union { ++ struct cmsghdr cmsghdr; ++ ++ /* We use NAME_MAX space for the SELinux label ++ * here. The kernel currently enforces no ++ * limit, but according to suggestions from ++ * the SELinux people this will change and it ++ * will probably be identical to NAME_MAX. For ++ * now we use that, but this should be updated ++ * one day when the final limit is known. */ ++ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + ++ CMSG_SPACE(sizeof(struct timeval)) + ++ CMSG_SPACE(sizeof(int)) + /* fd */ ++ CMSG_SPACE(NAME_MAX)]; /* selinux label */ ++ } control = {}; ++ ++ union sockaddr_union sa = {}; ++ ++ struct msghdr msghdr = { ++ .msg_iov = &iovec, ++ .msg_iovlen = 1, ++ .msg_control = &control, ++ .msg_controllen = sizeof(control), ++ .msg_name = &sa, ++ .msg_namelen = sizeof(sa), ++ }; + + assert(s); + assert(fd == s->native_fd || fd == s->syslog_fd || fd == s->audit_fd); +@@ -1112,119 +1148,79 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void + return -EIO; + } + +- for (;;) { +- struct ucred *ucred = NULL; +- struct timeval *tv = NULL; +- struct cmsghdr *cmsg; +- char *label = NULL; +- size_t label_len = 0; +- struct iovec iovec; +- +- union { +- struct cmsghdr cmsghdr; +- +- /* We use NAME_MAX space for the SELinux label +- * here. The kernel currently enforces no +- * limit, but according to suggestions from +- * the SELinux people this will change and it +- * will probably be identical to NAME_MAX. For +- * now we use that, but this should be updated +- * one day when the final limit is known. */ +- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + +- CMSG_SPACE(sizeof(struct timeval)) + +- CMSG_SPACE(sizeof(int)) + /* fd */ +- CMSG_SPACE(NAME_MAX)]; /* selinux label */ +- } control = {}; +- union sockaddr_union sa = {}; +- struct msghdr msghdr = { +- .msg_iov = &iovec, +- .msg_iovlen = 1, +- .msg_control = &control, +- .msg_controllen = sizeof(control), +- .msg_name = &sa, +- .msg_namelen = sizeof(sa), +- }; +- +- ssize_t n; +- int *fds = NULL; +- unsigned n_fds = 0; +- int v = 0; +- size_t m; +- +- /* Try to get the right size, if we can. (Not all +- * sockets support SIOCINQ, hence we just try, but +- * don't rely on it. */ +- (void) ioctl(fd, SIOCINQ, &v); +- +- /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */ +- m = PAGE_ALIGN(MAX3((size_t) v + 1, +- (size_t) LINE_MAX, +- ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1); +- +- if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m)) +- return log_oom(); +- +- iovec.iov_base = s->buffer; +- iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */ +- +- n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); +- if (n < 0) { +- if (errno == EINTR || errno == EAGAIN) +- return 0; +- +- log_error_errno(errno, "recvmsg() failed: %m"); +- return -errno; +- } ++ /* Try to get the right size, if we can. (Not all ++ * sockets support SIOCINQ, hence we just try, but ++ * don't rely on it. */ ++ (void) ioctl(fd, SIOCINQ, &v); + +- CMSG_FOREACH(cmsg, &msghdr) { +- +- if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_CREDENTIALS && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) +- ucred = (struct ucred*) CMSG_DATA(cmsg); +- else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_SECURITY) { +- label = (char*) CMSG_DATA(cmsg); +- label_len = cmsg->cmsg_len - CMSG_LEN(0); +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SO_TIMESTAMP && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) +- tv = (struct timeval*) CMSG_DATA(cmsg); +- else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_RIGHTS) { +- fds = (int*) CMSG_DATA(cmsg); +- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); +- } +- } ++ /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */ ++ m = PAGE_ALIGN(MAX3((size_t) v + 1, ++ (size_t) LINE_MAX, ++ ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1); + +- /* And a trailing NUL, just in case */ +- s->buffer[n] = 0; ++ if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m)) ++ return log_oom(); + +- if (fd == s->syslog_fd) { +- if (n > 0 && n_fds == 0) +- server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len); +- else if (n_fds > 0) +- log_warning("Got file descriptors via syslog socket. Ignoring."); ++ iovec.iov_base = s->buffer; ++ iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */ + +- } else if (fd == s->native_fd) { +- if (n > 0 && n_fds == 0) +- server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len); +- else if (n == 0 && n_fds == 1) +- server_process_native_file(s, fds[0], ucred, tv, label, label_len); +- else if (n_fds > 0) +- log_warning("Got too many file descriptors via native socket. Ignoring."); ++ n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); ++ if (n < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ return 0; + +- } else { +- assert(fd == s->audit_fd); ++ return log_error_errno(errno, "recvmsg() failed: %m"); ++ } + +- if (n > 0 && n_fds == 0) +- server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen); +- else if (n_fds > 0) +- log_warning("Got file descriptors via audit socket. Ignoring."); ++ CMSG_FOREACH(cmsg, &msghdr) { ++ ++ if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_CREDENTIALS && ++ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) ++ ucred = (struct ucred*) CMSG_DATA(cmsg); ++ else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_SECURITY) { ++ label = (char*) CMSG_DATA(cmsg); ++ label_len = cmsg->cmsg_len - CMSG_LEN(0); ++ } else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SO_TIMESTAMP && ++ cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) ++ tv = (struct timeval*) CMSG_DATA(cmsg); ++ else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_RIGHTS) { ++ fds = (int*) CMSG_DATA(cmsg); ++ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + } ++ } ++ ++ /* And a trailing NUL, just in case */ ++ s->buffer[n] = 0; ++ ++ if (fd == s->syslog_fd) { ++ if (n > 0 && n_fds == 0) ++ server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len); ++ else if (n_fds > 0) ++ log_warning("Got file descriptors via syslog socket. Ignoring."); ++ ++ } else if (fd == s->native_fd) { ++ if (n > 0 && n_fds == 0) ++ server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len); ++ else if (n == 0 && n_fds == 1) ++ server_process_native_file(s, fds[0], ucred, tv, label, label_len); ++ else if (n_fds > 0) ++ log_warning("Got too many file descriptors via native socket. Ignoring."); + +- close_many(fds, n_fds); ++ } else { ++ assert(fd == s->audit_fd); ++ ++ if (n > 0 && n_fds == 0) ++ server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen); ++ else if (n_fds > 0) ++ log_warning("Got file descriptors via audit socket. Ignoring."); + } ++ ++ close_many(fds, n_fds); ++ return 0; + } + + static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { diff --git a/SOURCES/0384-journald-fix-count-of-object-meta-fields.patch b/SOURCES/0384-journald-fix-count-of-object-meta-fields.patch new file mode 100644 index 00000000..47394074 --- /dev/null +++ b/SOURCES/0384-journald-fix-count-of-object-meta-fields.patch @@ -0,0 +1,29 @@ +From 7eee42f5d268084171d435de2b16333d2a0f79ab Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 5 Aug 2015 11:31:52 +0300 +Subject: [PATCH] journald: fix count of object meta fields + +There are 12 object meta fields created in dispatch_message_real(), but +we only allocated space for 11. Fix this. + +Fixes #866. + +Cherry-picked from: 704e4fe7a18a13a8651c0064ef3eda91027baffc +Related: #1318994 +--- + src/journal/journald-server.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h +index c96877c50..b1263a758 100644 +--- a/src/journal/journald-server.h ++++ b/src/journal/journald-server.h +@@ -148,7 +148,7 @@ typedef struct Server { + #define N_IOVEC_META_FIELDS 20 + #define N_IOVEC_KERNEL_FIELDS 64 + #define N_IOVEC_UDEV_FIELDS 32 +-#define N_IOVEC_OBJECT_FIELDS 11 ++#define N_IOVEC_OBJECT_FIELDS 12 + + void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid); + void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4); diff --git a/SOURCES/0385-journal-cat-return-a-correct-error-not-1.patch b/SOURCES/0385-journal-cat-return-a-correct-error-not-1.patch new file mode 100644 index 00000000..878e42aa --- /dev/null +++ b/SOURCES/0385-journal-cat-return-a-correct-error-not-1.patch @@ -0,0 +1,24 @@ +From ced1149f5af28ce2ad6174a2df9483b483d5e1cf Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 23 Sep 2015 19:39:30 +0200 +Subject: [PATCH] journal-cat: return a correct error, not -1 + +Cherry-picked from: e4603df5cf80bbd7a7d51fc66fa6c60e042423bc +Related: #1318994 +--- + src/journal/cat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/cat.c b/src/journal/cat.c +index 79706b692..ed467b078 100644 +--- a/src/journal/cat.c ++++ b/src/journal/cat.c +@@ -96,7 +96,7 @@ static int parse_argv(int argc, char *argv[]) { + arg_priority = log_level_from_string(optarg); + if (arg_priority < 0) { + log_error("Failed to parse priority value."); +- return arg_priority; ++ return -EINVAL; + } + break; + diff --git a/SOURCES/0386-journalctl-introduce-short-options-for-since-and-unt.patch b/SOURCES/0386-journalctl-introduce-short-options-for-since-and-unt.patch new file mode 100644 index 00000000..55666022 --- /dev/null +++ b/SOURCES/0386-journalctl-introduce-short-options-for-since-and-unt.patch @@ -0,0 +1,90 @@ +From f6cf4e14409d25868caccc3606a928a610465405 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 13 Oct 2015 10:50:49 +0200 +Subject: [PATCH] journalctl: introduce short options for --since and --until + +Fixes #1514. + +Cherry-picked from: 66f529249a6b3c3391e732cba44482a498153e16 +Related: #1318994 +--- + man/journalctl.xml | 2 ++ + src/journal/journalctl.c | 16 +++++++--------- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index 0981fba72..dedcf1925 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -528,7 +528,9 @@ + + + ++ + ++ + + + Start showing entries on or newer than the +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index e84dd4c9d..ba9ae05f7 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -274,8 +274,8 @@ static void help(void) { + " --system Show the system journal\n" + " --user Show the user journal for the current user\n" + " -M --machine=CONTAINER Operate on local container\n" +- " --since=DATE Show entries not older than the specified date\n" +- " --until=DATE Show entries not newer than the specified date\n" ++ " -S --since=DATE Show entries not older than the specified date\n" ++ " -U --until=DATE Show entries not newer than the specified date\n" + " -c --cursor=CURSOR Show entries starting at the specified cursor\n" + " --after-cursor=CURSOR Show entries after the specified cursor\n" + " --show-cursor Print the cursor after all the entries\n" +@@ -347,8 +347,6 @@ static int parse_argv(int argc, char *argv[]) { + ARG_VERIFY, + ARG_VERIFY_KEY, + ARG_DISK_USAGE, +- ARG_SINCE, +- ARG_UNTIL, + ARG_AFTER_CURSOR, + ARG_SHOW_CURSOR, + ARG_USER_UNIT, +@@ -398,8 +396,8 @@ static int parse_argv(int argc, char *argv[]) { + { "cursor", required_argument, NULL, 'c' }, + { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, + { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, +- { "since", required_argument, NULL, ARG_SINCE }, +- { "until", required_argument, NULL, ARG_UNTIL }, ++ { "since", required_argument, NULL, 'S' }, ++ { "until", required_argument, NULL, 'U' }, + { "unit", required_argument, NULL, 'u' }, + { "user-unit", required_argument, NULL, ARG_USER_UNIT }, + { "field", required_argument, NULL, 'F' }, +@@ -421,7 +419,7 @@ static int parse_argv(int argc, char *argv[]) { + assert(argc >= 0); + assert(argv); + +- while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0) ++ while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0) + + switch (c) { + +@@ -711,7 +709,7 @@ static int parse_argv(int argc, char *argv[]) { + break; + } + +- case ARG_SINCE: ++ case 'S': + r = parse_timestamp(optarg, &arg_since); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); +@@ -720,7 +718,7 @@ static int parse_argv(int argc, char *argv[]) { + arg_since_set = true; + break; + +- case ARG_UNTIL: ++ case 'U': + r = parse_timestamp(optarg, &arg_until); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); diff --git a/SOURCES/0387-journal-s-Envalid-Invalid.patch b/SOURCES/0387-journal-s-Envalid-Invalid.patch new file mode 100644 index 00000000..2e9ab6fd --- /dev/null +++ b/SOURCES/0387-journal-s-Envalid-Invalid.patch @@ -0,0 +1,24 @@ +From 80476a1b99601168536e4543124d0532c895c498 Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Fri, 23 Oct 2015 16:12:31 -0700 +Subject: [PATCH] journal: s/Envalid/Invalid/ + +Cherry-picked from: 0c4a83a259c2ff87df83f48cd7ceef37b8746f4f +Related: #1318994 +--- + src/journal/journal-verify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 8a66ac7f0..250d4c758 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -899,7 +899,7 @@ int journal_file_verify( + + r = journal_file_object_verify(f, p, o); + if (r < 0) { +- error(p, "Envalid object contents: %s", strerror(-r)); ++ error(p, "Invalid object contents: %s", strerror(-r)); + goto fail; + } + diff --git a/SOURCES/0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch b/SOURCES/0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch new file mode 100644 index 00000000..98ad6079 --- /dev/null +++ b/SOURCES/0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch @@ -0,0 +1,43 @@ +From be21e10cf30e66215e986ab900637b32e502a29a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 10 Nov 2015 16:53:00 +0100 +Subject: [PATCH] journald: dispatch SIGTERM/SIGINT with a low priority + +Let's make sure to process all queued log data before exiting, so that +we don't unnecessary lose messages when shutting down. + +https://github.com/systemd/systemd/pull/1812#issuecomment-155149871 + +Cherry-picked from: b374689c02c681671a3c3c0b0fd3add32386b442 +Related: #1318994 +--- + src/journal/journald-server.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 275224dc9..2b7ecd09a 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1284,10 +1284,22 @@ static int setup_signals(Server *s) { + if (r < 0) + return r; + ++ /* Let's process SIGTERM late, so that we flush all queued ++ * messages to disk before we exit */ ++ r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20); ++ if (r < 0) ++ return r; ++ ++ /* When journald is invoked on the terminal (when debugging), ++ * it's useful if C-c is handled equivalent to SIGTERM. */ + r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s); + if (r < 0) + return r; + ++ r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20); ++ if (r < 0) ++ return r; ++ + return 0; + } + diff --git a/SOURCES/0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch b/SOURCES/0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch new file mode 100644 index 00000000..f47c9ea7 --- /dev/null +++ b/SOURCES/0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch @@ -0,0 +1,25 @@ +From 942cfd50b5c03f19cfe1b03040c54b7a460b5593 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 1 Dec 2015 22:53:23 -0500 +Subject: [PATCH] lz4: fix size check which had no chance of working on + big-endian + +Cherry-picked from: b3aa622929f81b44974d182636b1fde8b2a506e5 +Related: #1318994 +--- + src/journal/compress.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/compress.c b/src/journal/compress.c +index c9a3399cc..4fb09f596 100644 +--- a/src/journal/compress.c ++++ b/src/journal/compress.c +@@ -190,7 +190,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size, + return -EBADMSG; + + size = le64toh( *(le64_t*)src ); +- if (size < 0 || (le64_t) size != *(le64_t*)src) ++ if (size < 0 || (unsigned) size != le64toh(*(le64_t*)src)) + return -EFBIG; + if ((size_t) size > *dst_alloc_size) { + out = realloc(*dst, size); diff --git a/SOURCES/0390-journal-normalize-priority-of-logging-sources.patch b/SOURCES/0390-journal-normalize-priority-of-logging-sources.patch new file mode 100644 index 00000000..fb2f8b28 --- /dev/null +++ b/SOURCES/0390-journal-normalize-priority-of-logging-sources.patch @@ -0,0 +1,70 @@ +From c87355bc80da9e2cba7f7723d7c6568dfa56f1a1 Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Fri, 8 Jan 2016 12:11:44 -0800 +Subject: [PATCH] journal: normalize priority of logging sources + +The stream event source has a priority of SD_EVENT_PRIORITY_NORMAL+5, +and stdout source +10, but the native and syslog event sources are left +at the default of 0. + +As a result, any heavy native or syslog logger can cause starvation of +the other loggers. This is trivially demonstrated by running: + + dd if=/dev/urandom bs=8k | od | systemd-cat & # native spammer + systemd-run echo hello & # stream logger + journalctl --follow --output=verbose --no-pager --identifier=echo & + +... and wait, and wait, the "hello" never comes. + +Now kill %1, "hello" arrives finally. + +Cherry-picked from: 48cef29504b1ffc0df9929f2d8b2af2ad74d2b4a +Related: #1318994 +--- + src/journal/journald-native.c | 4 ++++ + src/journal/journald-stream.c | 2 +- + src/journal/journald-syslog.c | 4 ++++ + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c +index 851625de0..2c9cf6e7a 100644 +--- a/src/journal/journald-native.c ++++ b/src/journal/journald-native.c +@@ -457,5 +457,9 @@ int server_open_native_socket(Server*s) { + if (r < 0) + return log_error_errno(r, "Failed to add native server fd to event loop: %m"); + ++ r = sd_event_source_set_priority(s->native_event_source, SD_EVENT_PRIORITY_NORMAL+5); ++ if (r < 0) ++ return log_error_errno(r, "Failed to adjust native event source priority: %m"); ++ + return 0; + } +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 15a554c34..b8607144b 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -448,7 +448,7 @@ int server_open_stdout_socket(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to add stdout server fd to event source: %m"); + +- r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10); ++ r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+5); + if (r < 0) + return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m"); + +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index 4e118aabc..8602b4a95 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -421,6 +421,10 @@ int server_open_syslog_socket(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to add syslog server fd to event loop: %m"); + ++ r = sd_event_source_set_priority(s->syslog_event_source, SD_EVENT_PRIORITY_NORMAL+5); ++ if (r < 0) ++ return log_error_errno(r, "Failed to adjust syslog event source priority: %m"); ++ + return 0; + } + diff --git a/SOURCES/0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch b/SOURCES/0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch new file mode 100644 index 00000000..b49140e7 --- /dev/null +++ b/SOURCES/0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch @@ -0,0 +1,43 @@ +From 573e86d7e9f0038044d5cba2a1a543e24b063a79 Mon Sep 17 00:00:00 2001 +From: Aleksander Adamowski +Date: Mon, 11 Jan 2016 15:26:41 -0800 +Subject: [PATCH] Fix miscalculated buffer size and uses of size-unlimited + sprintf() function. + +Not sure if this results in an exploitable buffer overflow, probably not +since the the int value is likely sanitized somewhere earlier and it's +being put through a bit mask shortly before being used. + +Cherry-picked from: 13f5402c6b734ed4c2b3e8b7c3d3bf6d815e7661 +Related: #1318994 +--- + src/journal/journald-syslog.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index 8602b4a95..b499a0d38 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -317,7 +317,7 @@ void server_process_syslog_message( + size_t label_len) { + + char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)], +- syslog_facility[sizeof("SYSLOG_FACILITY") + DECIMAL_STR_MAX(int)]; ++ syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)]; + const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; + struct iovec iovec[N_IOVEC_META_FIELDS + 6]; + unsigned n = 0; +@@ -348,11 +348,11 @@ void server_process_syslog_message( + + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog"); + +- sprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK); ++ snprintf(syslog_priority, sizeof(syslog_priority), "PRIORITY=%i", priority & LOG_PRIMASK); + IOVEC_SET_STRING(iovec[n++], syslog_priority); + + if (priority & LOG_FACMASK) { +- sprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)); ++ snprintf(syslog_facility, sizeof(syslog_facility), "SYSLOG_FACILITY=%i", LOG_FAC(priority)); + IOVEC_SET_STRING(iovec[n++], syslog_facility); + } + diff --git a/SOURCES/0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch b/SOURCES/0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch new file mode 100644 index 00000000..fd367cbe --- /dev/null +++ b/SOURCES/0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch @@ -0,0 +1,34 @@ +From e1d77a906fef76c1c8db2132e1d3a407f913444c Mon Sep 17 00:00:00 2001 +From: Klearchos Chaloulos +Date: Tue, 9 Feb 2016 12:14:54 +0200 +Subject: [PATCH] journal: Drop monotonicity check when appending to journal + file + +Remove the check that triggers rotation of the journal file when the +arriving log entry had a monotonic timestamp smaller that the previous +log entry. This check causes unnecessary rotations when journal-remote +was receiving from multiple senders, therefore monotonicity can not be +guaranteed. Also, it does not offer any useful functionality for +systemd-journald. + +Cherry-picked from: ecb6105a1bd8445a123343827d46bb527bcca92f +Related: #1318994 +--- + src/journal/journal-file.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 2a93460d4..8034b771d 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -1419,10 +1419,6 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st + ts = &_ts; + } + +- if (f->tail_entry_monotonic_valid && +- ts->monotonic < le64toh(f->header->tail_entry_monotonic)) +- return -EINVAL; +- + #ifdef HAVE_GCRYPT + r = journal_file_maybe_append_tag(f, ts->realtime); + if (r < 0) diff --git a/SOURCES/0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch b/SOURCES/0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch new file mode 100644 index 00000000..571f3f59 --- /dev/null +++ b/SOURCES/0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch @@ -0,0 +1,83 @@ +From 76d6062ebf93614a45f1f74be7a93a9a662c5812 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 00:35:02 +0200 +Subject: [PATCH] journalctl: unify how we free boot id lists a bit + +Instead of use LIST_FOREACH_SAFE, just use the same, seperate destructor +everywhere. + +Cherry-picked from: 9530e0d023b0e9308f19eadf6e42cdc25bc30793 +Related: #1318994 +--- + src/journal/journalctl.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index ba9ae05f7..5864ff50a 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -932,6 +932,15 @@ static int add_matches(sd_journal *j, char **args) { + return 0; + } + ++static void boot_id_free_all(BootId *l) { ++ ++ while (l) { ++ BootId *i = l; ++ LIST_REMOVE(boot_list, l, i); ++ free(i); ++ } ++} ++ + static int discover_next_boot( + sd_journal *j, + BootId **boot, +@@ -1009,6 +1018,7 @@ static int discover_next_boot( + + *boot = next_boot; + next_boot = NULL; ++ + return 0; + } + +@@ -1080,9 +1090,7 @@ static int get_boots( + + r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); + if (r < 0) { +- BootId *id, *id_next; +- LIST_FOREACH_SAFE(boot_list, id, id_next, head) +- free(id); ++ boot_id_free_all(head); + return r; + } + +@@ -1118,7 +1126,7 @@ finish: + + static int list_boots(sd_journal *j) { + int w, i, count; +- BootId *id, *id_next, *all_ids; ++ BootId *id, *all_ids; + + assert(j); + +@@ -1132,7 +1140,7 @@ static int list_boots(sd_journal *j) { + w = DECIMAL_STR_WIDTH(count - 1) + 1; + + i = 0; +- LIST_FOREACH_SAFE(boot_list, id, id_next, all_ids) { ++ LIST_FOREACH(boot_list, id, all_ids) { + char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX]; + + printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n", +@@ -1141,9 +1149,10 @@ static int list_boots(sd_journal *j) { + format_timestamp_maybe_utc(a, sizeof(a), id->first), + format_timestamp_maybe_utc(b, sizeof(b), id->last)); + i++; +- free(id); + } + ++ boot_id_free_all(all_ids); ++ + return 0; + } + diff --git a/SOURCES/0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch b/SOURCES/0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch new file mode 100644 index 00000000..eadde648 --- /dev/null +++ b/SOURCES/0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch @@ -0,0 +1,187 @@ +From cc5710c3ad0ff51fa84b736d66d5f70aa0ade2b3 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 25 Apr 2016 18:08:42 +0200 +Subject: [PATCH] journalctl: don't trust the per-field entry tables when + looking for boot IDs + +When appending to a journal file, journald will: + +a) first, append the actual entry to the end of the journal file +b) second, add an offset reference to it to the global entry array stored at + the beginning of the file +c) third, add offset references to it to the per-field entry array stored at + various places of the file + +The global entry array, maintained by b) is used when iterating through the +journal without matches applied. + +The per-field entry array maintained by c) is used when iterating through the +journal with a match for that specific field applied. + +In the wild, there are journal files where a) and b) were completed, but c) +was not before the files were abandoned. This means, that in some cases log +entries are at the end of these files that appear in the global entry array, +but not in the per-field entry array of the _BOOT_ID= field. Now, the +"journalctl --list-boots" command alternatingly uses the global entry array +and the per-field entry array of the _BOOT_ID= field. It seeks to the last +entry of a specific _BOOT_ID=field by having the right match installed, and +then jumps to the next following entry with no match installed anymore, under +the assumption this would bring it to the next boot ID. However, if the +per-field entry wasn't written fully, it might actually turn out that the +global entry array might know one more entry with the same _BOOT_ID, thus +resulting in a indefinite loop around the same _BOOT_ID. + +This patch fixes that, by updating the boot search logic to always continue +reading entries until the boot ID actually changed from the previous. Thus, the +per-field entry array is used as quick jump index (i.e. as an optimization), +but not trusted otherwise. Only the global entry array is trusted. + +This replaces PR #1904, which is actually very similar to this one. However, +this one actually reads the boot ID directly from the entry header, and doesn't +try to read it at all until the read pointer is actually really located on the +first item to read. + +Fixes: #617 + +Replaces: #1904 + +Cherry-picked from: dc00966228ff90c554fd034e588ea55eb605ec52 +Related: #1318994 +--- + src/journal/journalctl.c | 71 ++++++++++++++++++++++++++++-------------------- + 1 file changed, 42 insertions(+), 29 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 5864ff50a..723854a2e 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -941,18 +941,18 @@ static void boot_id_free_all(BootId *l) { + } + } + +-static int discover_next_boot( +- sd_journal *j, +- BootId **boot, ++static int discover_next_boot(sd_journal *j, ++ sd_id128_t previous_boot_id, + bool advance_older, +- bool read_realtime) { ++ BootId **ret) { + +- int r; +- char match[9+32+1] = "_BOOT_ID="; + _cleanup_free_ BootId *next_boot = NULL; ++ char match[9+32+1] = "_BOOT_ID="; ++ sd_id128_t boot_id; ++ int r; + + assert(j); +- assert(boot); ++ assert(ret); + + /* We expect the journal to be on the last position of a boot + * (in relation to the direction we are going), so that the next +@@ -965,29 +965,40 @@ static int discover_next_boot( + * we can actually advance to a *different* boot. */ + sd_journal_flush_matches(j); + +- if (advance_older) +- r = sd_journal_previous(j); +- else +- r = sd_journal_next(j); +- if (r < 0) +- return r; +- else if (r == 0) +- return 0; /* End of journal, yay. */ ++ do { ++ if (advance_older) ++ r = sd_journal_previous(j); ++ else ++ r = sd_journal_next(j); ++ if (r < 0) ++ return r; ++ else if (r == 0) ++ return 0; /* End of journal, yay. */ ++ ++ r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); ++ if (r < 0) ++ return r; ++ ++ /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that ++ * normally, this will only require a single iteration, as we seeked to the last entry of the previous ++ * boot entry already. However, it might happen that the per-journal-field entry arrays are less ++ * complete than the main entry array, and hence might reference an entry that's not actually the last ++ * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to ++ * speed things up, but let's not trust that it is complete, and hence, manually advance as ++ * necessary. */ ++ ++ } while (sd_id128_equal(boot_id, previous_boot_id)); + + next_boot = new0(BootId, 1); + if (!next_boot) + return log_oom(); + +- r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id); ++ next_boot->id = boot_id; ++ ++ r = sd_journal_get_realtime_usec(j, &next_boot->first); + if (r < 0) + return r; + +- if (read_realtime) { +- r = sd_journal_get_realtime_usec(j, &next_boot->first); +- if (r < 0) +- return r; +- } +- + /* Now seek to the last occurrence of this boot ID. */ + sd_id128_to_string(next_boot->id, match + 9); + r = sd_journal_add_match(j, match, sizeof(match) - 1); +@@ -1010,13 +1021,11 @@ static int discover_next_boot( + else if (r == 0) + return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */ + +- if (read_realtime) { +- r = sd_journal_get_realtime_usec(j, &next_boot->last); +- if (r < 0) +- return r; +- } ++ r = sd_journal_get_realtime_usec(j, &next_boot->last); ++ if (r < 0) ++ return r; + +- *boot = next_boot; ++ *ret = next_boot; + next_boot = NULL; + + return 0; +@@ -1032,6 +1041,7 @@ static int get_boots( + int r, count = 0; + BootId *head = NULL, *tail = NULL; + const bool advance_older = query_ref_boot && ref_boot_offset <= 0; ++ sd_id128_t previous_boot_id; + + assert(j); + +@@ -1085,10 +1095,11 @@ static int get_boots( + /* No sd_journal_next/previous here. */ + } + ++ previous_boot_id = SD_ID128_NULL; + for (;;) { + _cleanup_free_ BootId *current = NULL; + +- r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); ++ r = discover_next_boot(j, previous_boot_id, advance_older, ¤t); + if (r < 0) { + boot_id_free_all(head); + return r; +@@ -1097,6 +1108,8 @@ static int get_boots( + if (!current) + break; + ++ previous_boot_id = current->id; ++ + if (query_ref_boot) { + if (!skip_once) + ref_boot_offset += advance_older ? 1 : -1; diff --git a/SOURCES/0395-units-remove-udev-control-socket-when-systemd-stops-.patch b/SOURCES/0395-units-remove-udev-control-socket-when-systemd-stops-.patch new file mode 100644 index 00000000..9566cfdc --- /dev/null +++ b/SOURCES/0395-units-remove-udev-control-socket-when-systemd-stops-.patch @@ -0,0 +1,33 @@ +From f77d58374ccd2e3d9c886e59020f1b32e97f2bdc Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 29 Aug 2016 14:49:20 +0200 +Subject: [PATCH] units: remove udev control socket when systemd stops the + socket unit (#49) + +Mere presence of the socket in the filesystem makes +udev_queue_get_udev_is_active() return that udev is running. Note that, +udev on exit doesn't unlink control socket nor does systemd. Thus socket +stays around even when both daemon and socket are stopped. This causes +problems for cryptsetup because when it detects running udev it launches +synchronous operations that *really* require udev. This in turn may +cause blocking and subsequent timeout in systemd-cryptsetup on reboot +while machine is in a state that udev and its control socket units are +stopped, e.g. emergency mode. + +Fixes #2477 + +Cherry-picked from: a2de10775194edec51b1e88d20a380724a3dc716 +Resolves: #1370133 +--- + units/systemd-udevd-control.socket | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-udevd-control.socket b/units/systemd-udevd-control.socket +index 8330a1c03..46f704ed7 100644 +--- a/units/systemd-udevd-control.socket ++++ b/units/systemd-udevd-control.socket +@@ -17,3 +17,4 @@ Service=systemd-udevd.service + ListenSequentialPacket=/run/udev/control + SocketMode=0600 + PassCredentials=yes ++RemoveOnStop=yes diff --git a/SOURCES/0396-logind-don-t-assert-if-the-slice-is-missing.patch b/SOURCES/0396-logind-don-t-assert-if-the-slice-is-missing.patch new file mode 100644 index 00000000..df6a335a --- /dev/null +++ b/SOURCES/0396-logind-don-t-assert-if-the-slice-is-missing.patch @@ -0,0 +1,26 @@ +From 7f681673fa2af8f1898447ee336763f2eeb00d57 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 13 Nov 2015 18:47:02 +0100 +Subject: [PATCH] logind: don't assert if the slice is missing + +After all, we don't actually really need the slice to work, it's just +nice to have it. + +Cherry-picked from: 38599489e49e840291516488a3ef1b4a56198c58 +Resolves: #1371437 +--- + src/login/logind-session.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 59f5a7ad5..746e50aa5 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -507,7 +507,6 @@ static int session_start_scope(Session *s) { + + assert(s); + assert(s->user); +- assert(s->user->slice); + + if (!s->scope) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/SOURCES/0397-core-enable-transient-unit-support-for-slice-units.patch b/SOURCES/0397-core-enable-transient-unit-support-for-slice-units.patch new file mode 100644 index 00000000..57d622cf --- /dev/null +++ b/SOURCES/0397-core-enable-transient-unit-support-for-slice-units.patch @@ -0,0 +1,48 @@ +From e360c720533dccac39d8b88510b15c21a944b042 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 13 Nov 2015 18:46:50 +0100 +Subject: [PATCH] core: enable transient unit support for slice units + +Cherry-picked from: 17f62e9bd00f5fefd486475861b06d3ec6b7ee10 +Resolves: #1370299 +--- + src/core/dbus-manager.c | 13 ++++++++++++- + src/core/slice.c | 1 + + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 9eef290ca..8d3758ac7 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -633,7 +633,18 @@ static int transient_unit_from_message( + if (r < 0) + return r; + +- if (u->load_state != UNIT_NOT_FOUND || ++ /* Check if the unit already exists or is already referenced, ++ * in a number of different ways. Note that to cater for unit ++ * types such as slice, we are generally fine with units that ++ * are marked UNIT_LOADED even even though nothing was ++ * actually loaded, as those unit types don't require a file ++ * on disk to validly load. */ ++ ++ if (!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) || ++ u->fragment_path || ++ u->source_path || ++ !strv_isempty(u->dropin_paths) || ++ u->refs || + set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); + +diff --git a/src/core/slice.c b/src/core/slice.c +index 61ff9d331..9154558b7 100644 +--- a/src/core/slice.c ++++ b/src/core/slice.c +@@ -272,6 +272,7 @@ const UnitVTable slice_vtable = { + + .no_alias = true, + .no_instances = true, ++ .can_transient = true, + + .load = slice_load, + diff --git a/SOURCES/0398-sd-bus-bump-message-queue-size.patch b/SOURCES/0398-sd-bus-bump-message-queue-size.patch new file mode 100644 index 00000000..b1fbb260 --- /dev/null +++ b/SOURCES/0398-sd-bus-bump-message-queue-size.patch @@ -0,0 +1,31 @@ +From aff078e9ce3c43410de9bc3a2e9cf7042ac799aa Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 31 Aug 2016 20:09:31 +0200 +Subject: [PATCH] sd-bus: bump message queue size + +Let's bump it further, as this the current limit turns out to be problematic +IRL. Let's bump it to more than twice what we know of is needed. + +Fixes: #4068 + +Cherry-picked from: 5ddda46 +Resolves: #1371205 +--- + src/libsystemd/sd-bus/bus-internal.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h +index 071b3da79..6a106862e 100644 +--- a/src/libsystemd/sd-bus/bus-internal.h ++++ b/src/libsystemd/sd-bus/bus-internal.h +@@ -326,8 +326,8 @@ struct sd_bus { + + #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) + +-#define BUS_WQUEUE_MAX 1024 +-#define BUS_RQUEUE_MAX 64*1024 ++#define BUS_WQUEUE_MAX (192*1024) ++#define BUS_RQUEUE_MAX (192*1024) + + #define BUS_MESSAGE_SIZE_MAX (64*1024*1024) + #define BUS_AUTH_SIZE_MAX (64*1024) diff --git a/SOURCES/0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch b/SOURCES/0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch new file mode 100644 index 00000000..1c9894bc --- /dev/null +++ b/SOURCES/0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch @@ -0,0 +1,24 @@ +From 30c5299e91db30f07b64c6c47ac7417bd4e6988c Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 30 Aug 2016 15:04:07 +0200 +Subject: [PATCH] install: fix disable when /etc/systemd/system is a symlink + +Cherry-picked from: 67852d08e6a35d34b428e8be64efdb3f003f4697 +Resolves: #1285996 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 61aaafe7b..ab86cd145 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -476,7 +476,7 @@ static int remove_marked_symlinks( + if (set_size(remove_symlinks_to) <= 0) + return 0; + +- fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); ++ fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); + if (fd < 0) + return -errno; + diff --git a/SOURCES/0400-rules-add-NVMe-rules-3136.patch b/SOURCES/0400-rules-add-NVMe-rules-3136.patch new file mode 100644 index 00000000..5c4290f9 --- /dev/null +++ b/SOURCES/0400-rules-add-NVMe-rules-3136.patch @@ -0,0 +1,36 @@ +From d913c83db4d3271a400173dfee55078335055e86 Mon Sep 17 00:00:00 2001 +From: Ming Lin +Date: Fri, 29 Apr 2016 04:02:57 -0700 +Subject: [PATCH] rules: add NVMe rules (#3136) + +Add NVMe rules using the "wwid" attribute. + +root@target:~# cat /sys/block/nvme0n1/wwid +eui.3825004235000591 + +root@target:~# ls /dev/disk/by-id/ -l |grep nvme +lrwxrwxrwx 1 root root 13 Apr 27 16:08 nvme-eui.3825004235000591 -> ../../nvme0n1 +lrwxrwxrwx 1 root root 15 Apr 27 16:08 nvme-eui.3825004235000591-part1 -> ../../nvme0n1p1 +lrwxrwxrwx 1 root root 15 Apr 27 16:08 nvme-eui.3825004235000591-part2 -> ../../nvme0n1p2 + +Cherry-picked from: 427a28ecbe0eb170e651e0530ab58d6e6f6c498c +Resolves: #1274651 +--- + rules/60-persistent-storage.rules | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 71ab97484..cc01acb16 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -22,6 +22,10 @@ TEST=="whole_disk", GOTO="persistent_storage_end" + # for partitions import parent information + ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" + ++# NVMe ++KERNEL=="nvme*[0-9]n*[0-9]", ATTR{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}" ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}-part%n" ++ + # virtio-blk + KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" + KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n" diff --git a/SOURCES/0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch b/SOURCES/0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch new file mode 100644 index 00000000..ae499748 --- /dev/null +++ b/SOURCES/0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch @@ -0,0 +1,36 @@ +From 1e61121501f79e654a36bf2efb6a987f6a11c262 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 17 Aug 2016 14:10:28 +0200 +Subject: [PATCH] rules: introduce disk/by-id (model_serial) symlinks for NVMe + drives (#3974) + +$ ls -l /dev/disk/by-id/nvme* +lrwxrwxrwx. 1 root root 13 Aug 17 04:25 /dev/disk/by-id/nvme-HUSPR3216AHP301_STM0001B6780 -> ../../nvme0n1 +lrwxrwxrwx. 1 root root 15 Aug 17 04:25 /dev/disk/by-id/nvme-HUSPR3216AHP301_STM0001B6780-part1 -> ../../nvme0n1p1 + +https://github.com/systemd/systemd/issues/1453 +https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=779ff75617099f4defe14e20443b95019a4c5ae8 + +Cherry-picked from: a5110c90303cf455db5062faef34d5724d12e2e9 +Related: #1274651 +--- + rules/60-persistent-storage.rules | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index cc01acb16..74f8f21f3 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -26,6 +26,12 @@ ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" + KERNEL=="nvme*[0-9]n*[0-9]", ATTR{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}" + KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}-part%n" + ++KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" ++KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}" ++ ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n" ++ + # virtio-blk + KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" + KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n" diff --git a/SOURCES/0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch b/SOURCES/0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch new file mode 100644 index 00000000..8e48cbf4 --- /dev/null +++ b/SOURCES/0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch @@ -0,0 +1,33 @@ +From 8ed606212fb3e82c12b1fcea8500a5dfe4f89393 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 1 Sep 2016 12:42:05 +0200 +Subject: [PATCH] rules: fix for possible whitespace in the "model" attribute + +Without this the rules would create multiple wrong symlinks, because +SYMLINK treats strings with spaces as a list of links to create. + +Suggested-by: Artur Paszkiewicz + +Cherry-picked from: f41c12825db7460429c857ccc0e545bd631a62a0 +Related: #1274651 +--- + rules/60-persistent-storage.rules | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 74f8f21f3..06e3329cc 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -27,10 +27,10 @@ KERNEL=="nvme*[0-9]n*[0-9]", ATTR{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{w + KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}-part%n" + + KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" +-KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}" ++KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}", OPTIONS="string_escape=replace" + + KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" +-KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n" ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n", OPTIONS="string_escape=replace" + + # virtio-blk + KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" diff --git a/SOURCES/0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch b/SOURCES/0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch new file mode 100644 index 00000000..5d8b6a23 --- /dev/null +++ b/SOURCES/0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch @@ -0,0 +1,111 @@ +From 5f273838f41f27e0045395c1677272d9dd12496c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 21 Apr 2016 20:04:21 -0400 +Subject: [PATCH] systemctl,pid1: do not warn about missing install info with + "preset" + +When "preset" was executed for a unit without install info, we'd warn similarly +as for "enable" and "disable". But "preset" is usually called for all units, +because the preset files are provided by the distribution, and the units are under +control of individual programs, and it's reasonable to call "preset" for all units +rather then try to do it only for the ones that can be installed. +We also don't warn about missing info for "preset-all". Thus it seems reasonable +to silently ignore units w/o install info when presetting. + +(In addition, when more than one unit was specified, we'd issue the warning +only if none of them had install info. But this is probably something to fix +for enable/disable too.) + +Cherry-picked from: 39207373dd638e548019ddb49929f15795b8b404 +Resolves: #1373950 +--- + man/systemctl.xml | 26 +++++++++++++------------- + src/systemctl/systemctl.c | 7 ++++--- + 2 files changed, 17 insertions(+), 16 deletions(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 2d0678d18..bb21f3a88 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -1012,22 +1012,22 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + preset NAME... + + +- Reset one or more unit files, as specified on the +- command line, to the defaults configured in the preset +- policy files. This has the same effect as +- disable or enable, +- depending how the unit is listed in the preset files. ++ Reset the enable/disable status one or more unit files, as specified on ++ the command line, to the defaults configured in the preset policy files. This ++ has the same effect as disable or ++ enable, depending how the unit is listed in the preset ++ files. + +- Use to control +- whether units shall be enabled and disabled, or only +- enabled, or only disabled. ++ Use to control whether units shall be ++ enabled and disabled, or only enabled, or only disabled. ++ ++ If the unit carries no install information, it will be silently ignored ++ by this command. + +- For more information on the preset policy format, +- see ++ For more information on the preset policy format, see + systemd.preset5. +- For more information on the concept of presets, please +- consult the Preset ++ For more information on the concept of presets, please consult the ++ Preset + document. + + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index e4b404abc..e854508d9 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -5367,6 +5367,7 @@ static int enable_unit(sd_bus *bus, char **args) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + int carries_install_info = -1; ++ bool ignore_carries_install_info = false; + int r; + + if (!args[1]) +@@ -5404,7 +5405,6 @@ static int enable_unit(sd_bus *bus, char **args) { + r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + else if (streq(verb, "preset")) { + r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes); +- carries_install_info = r; + } else if (streq(verb, "mask")) + r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + else if (streq(verb, "unmask")) +@@ -5424,7 +5424,7 @@ static int enable_unit(sd_bus *bus, char **args) { + } else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- int expect_carries_install_info = false; ++ bool expect_carries_install_info = false; + bool send_force = true, send_preset_mode = false; + const char *method; + +@@ -5450,6 +5450,7 @@ static int enable_unit(sd_bus *bus, char **args) { + method = "PresetUnitFiles"; + + expect_carries_install_info = true; ++ ignore_carries_install_info = true; + } else if (streq(verb, "mask")) + method = "MaskUnitFiles"; + else if (streq(verb, "unmask")) { +@@ -5515,7 +5516,7 @@ static int enable_unit(sd_bus *bus, char **args) { + r = 0; + } + +- if (carries_install_info == 0) ++ if (carries_install_info == 0 && !ignore_carries_install_info) + log_warning("The unit files have no [Install] section. They are not meant to be enabled\n" + "using systemctl.\n" + "Possible reasons for having this kind of units are:\n" diff --git a/SOURCES/0404-systemctl-core-ignore-masked-units-in-preset-all.patch b/SOURCES/0404-systemctl-core-ignore-masked-units-in-preset-all.patch new file mode 100644 index 00000000..c7016613 --- /dev/null +++ b/SOURCES/0404-systemctl-core-ignore-masked-units-in-preset-all.patch @@ -0,0 +1,148 @@ +From c9a4b1688552a23867d3d9db18620501d57d33da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 16 Apr 2016 19:31:53 -0400 +Subject: [PATCH] systemctl/core: ignore masked units in preset-all + +With any masked unit that would that would be enabled by presets, we'd get: + +test@rawhide $ sudo systemctl preset-all +Failed to execute operation: Unit file is masked. + +test@rawhide $ sudo systemctl --root=/ preset-all +Operation failed: Cannot send after transport endpoint shutdown + +Simply ignore those units: + +test@rawhide $ sudo systemctl preset-all +Unit xxx.service is masked, ignoring. + +Cherry-picked from: 9a0a413a195a21888cf926be5595d0efc1eef0fe +Related: #1375097 +--- + src/core/dbus-manager.c | 12 +++++++----- + src/libsystemd/sd-bus/bus-util.c | 10 ++++++++-- + src/shared/install.c | 4 ++++ + src/shared/install.h | 5 +++++ + src/systemctl/systemctl.c | 20 ++++++++++++++------ + 5 files changed, 38 insertions(+), 13 deletions(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 8d3758ac7..c2067c099 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1598,11 +1598,13 @@ static int reply_unit_file_changes_and_free( + unsigned i; + int r; + +- if (n_changes > 0) { +- r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); +- if (r < 0) +- log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); +- } ++ for (i = 0; i < n_changes; i++) ++ if (unit_file_change_is_modification(changes[i].type)) { ++ r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); ++ if (r < 0) ++ log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); ++ break; ++ } + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 9d70798cd..75d03708e 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1893,11 +1893,17 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un + if (!quiet) { + if (streq(type, "symlink")) + log_info("Created symlink from %s to %s.", path, source); +- else ++ else if (streq(type, "unlink")) + log_info("Removed symlink %s.", path); ++ else if (streq(type, "masked")) ++ log_info("Unit %s is masked, ignoring.", path); ++ else ++ log_notice("Manager reported unknown change type \"%s\" for %s.", type, path); + } + +- r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source); ++ r = unit_file_changes_add(changes, n_changes, ++ unit_file_change_type_from_string(type), ++ path, source); + if (r < 0) + return r; + } +diff --git a/src/shared/install.c b/src/shared/install.c +index ab86cd145..62da52d3b 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2402,6 +2402,9 @@ int unit_file_preset_all( + continue; + + r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name); ++ if (r == -ESHUTDOWN) ++ r = unit_file_changes_add(changes, n_changes, ++ UNIT_FILE_IS_MASKED, de->d_name, NULL); + if (r < 0) + return r; + } +@@ -2535,6 +2538,7 @@ DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); + static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { + [UNIT_FILE_SYMLINK] = "symlink", + [UNIT_FILE_UNLINK] = "unlink", ++ [UNIT_FILE_IS_MASKED] = "masked", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); +diff --git a/src/shared/install.h b/src/shared/install.h +index 87a40b67c..f0e36661b 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -60,10 +60,15 @@ typedef enum UnitFilePresetMode { + typedef enum UnitFileChangeType { + UNIT_FILE_SYMLINK, + UNIT_FILE_UNLINK, ++ UNIT_FILE_IS_MASKED, + _UNIT_FILE_CHANGE_TYPE_MAX, + _UNIT_FILE_CHANGE_TYPE_INVALID = -1 + } UnitFileChangeType; + ++static inline bool unit_file_change_is_modification(UnitFileChangeType type) { ++ return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK); ++} ++ + typedef struct UnitFileChange { + UnitFileChangeType type; + char *path; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index e4b404abc..a688d6905 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1944,12 +1944,20 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha + + assert(changes || n_changes == 0); + +- for (i = 0; i < n_changes; i++) { +- if (changes[i].type == UNIT_FILE_SYMLINK) +- log_info("Created symlink from %s to %s.", changes[i].path, changes[i].source); +- else +- log_info("Removed symlink %s.", changes[i].path); +- } ++ for (i = 0; i < n_changes; i++) ++ switch(changes[i].type) { ++ case UNIT_FILE_SYMLINK: ++ log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); ++ break; ++ case UNIT_FILE_UNLINK: ++ log_info("Removed %s.", changes[i].path); ++ break; ++ case UNIT_FILE_IS_MASKED: ++ log_info("Unit %s is masked, ignoring.", changes[i].path); ++ break; ++ default: ++ assert_not_reached("bad change type"); ++ } + } + + static int set_default(sd_bus *bus, char **args) { diff --git a/SOURCES/0405-shared-install-handle-dangling-aliases-as-an-explici.patch b/SOURCES/0405-shared-install-handle-dangling-aliases-as-an-explici.patch new file mode 100644 index 00000000..021edcd4 --- /dev/null +++ b/SOURCES/0405-shared-install-handle-dangling-aliases-as-an-explici.patch @@ -0,0 +1,113 @@ +From 2047b2d0db643a168144b708cf58091ca47acb21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 4 May 2016 10:10:57 -0400 +Subject: [PATCH] shared/install: handle dangling aliases as an explicit case, + report nicely + +This fixes 'preset-all' with a unit that is a dangling symlink. + +$ systemctl --root=/ preset-all +Unit syslog.service is an alias to a unit that is not present, ignoring. +Unit auditd.service is masked, ignoring. +Unit NetworkManager.service is masked, ignoring. + +Cherry-picked from: 893275df36c8c358d3c0b851ca255a6169dac138 +Resolves: #1375097 +--- + src/libsystemd/sd-bus/bus-util.c | 2 ++ + src/shared/install.c | 17 +++++++++++++---- + src/shared/install.h | 1 + + src/systemctl/systemctl.c | 3 +++ + 4 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 75d03708e..d35776087 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1897,6 +1897,8 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un + log_info("Removed symlink %s.", path); + else if (streq(type, "masked")) + log_info("Unit %s is masked, ignoring.", path); ++ else if (streq(type, "dangling")) ++ log_info("Unit %s is an alias to a unit that is not present, ignoring.", path); + else + log_notice("Manager reported unknown change type \"%s\" for %s.", type, path); + } +diff --git a/src/shared/install.c b/src/shared/install.c +index 62da52d3b..b0a29ddd7 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1253,12 +1253,15 @@ static int install_info_traverse( + if (r < 0) + return r; + ++ /* Try again, with the new target we found. */ + r = unit_file_search(c, i, paths, root_dir, flags); +- if (r < 0) +- return r; ++ if (r == -ENOENT) ++ /* Translate error code to highlight this specific case */ ++ return -ENOLINK; + } + +- /* Try again, with the new target we found. */ ++ if (r < 0) ++ return r; + } + + if (ret) +@@ -1528,7 +1531,9 @@ static int install_context_mark_for_removal( + return r; + + r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); +- if (r < 0) ++ if (r == -ENOLINK) ++ return 0; ++ else if (r < 0) + return r; + + if (i->type != UNIT_FILE_TYPE_REGULAR) +@@ -2405,6 +2410,9 @@ int unit_file_preset_all( + if (r == -ESHUTDOWN) + r = unit_file_changes_add(changes, n_changes, + UNIT_FILE_IS_MASKED, de->d_name, NULL); ++ else if (r == -ENOLINK) ++ r = unit_file_changes_add(changes, n_changes, ++ UNIT_FILE_IS_DANGLING, de->d_name, NULL); + if (r < 0) + return r; + } +@@ -2539,6 +2547,7 @@ static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] + [UNIT_FILE_SYMLINK] = "symlink", + [UNIT_FILE_UNLINK] = "unlink", + [UNIT_FILE_IS_MASKED] = "masked", ++ [UNIT_FILE_IS_DANGLING] = "dangling", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); +diff --git a/src/shared/install.h b/src/shared/install.h +index f0e36661b..7e40445d3 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -61,6 +61,7 @@ typedef enum UnitFileChangeType { + UNIT_FILE_SYMLINK, + UNIT_FILE_UNLINK, + UNIT_FILE_IS_MASKED, ++ UNIT_FILE_IS_DANGLING, + _UNIT_FILE_CHANGE_TYPE_MAX, + _UNIT_FILE_CHANGE_TYPE_INVALID = -1 + } UnitFileChangeType; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index a688d6905..39f0150e5 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1955,6 +1955,9 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha + case UNIT_FILE_IS_MASKED: + log_info("Unit %s is masked, ignoring.", changes[i].path); + break; ++ case UNIT_FILE_IS_DANGLING: ++ log_info("Unit %s is an alias to a unit that is not present, ignoring.", changes[i].path); ++ break; + default: + assert_not_reached("bad change type"); + } diff --git a/SOURCES/0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch b/SOURCES/0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch new file mode 100644 index 00000000..6d099d45 --- /dev/null +++ b/SOURCES/0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch @@ -0,0 +1,75 @@ +From 412044ee341c574e5163bf2be32e5da9618f2640 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 13 Aug 2016 01:20:29 -0400 +Subject: [PATCH] shared/install: ignore unit symlinks when doing preset-all + +Before, when interating over unit files during preset-all, behaviour was the +following: + +- if we hit the real unit name first, presets were queried for that name, and + that unit was enabled or disabled accordingly, + +- if we hit an alias first (one of the symlinks chaining to the real unit), we + checked the presets using the symlink name, and then proceeded to enable or + disable the real unit. + +E.g. for systemd-networkd.service we have the alias dbus-org.freedesktop.network1.service +(/usr/lib/systemd/system/dbus-org.freedesktop.network1.service), but the preset +is only for the systemd-networkd.service name. The service would be enabled or +disabled pseudorandomly depending on the order of iteration. + +For "preset", behaviour was analogous: preset on the alias name disabled the +service (following the default disable policy), preset on the "real" name +applied the presets. + +With the patch, for "preset" and "preset-all" we silently skip symlinks. This +gives mostly the right behaviour, with the limitation that presets on aliases +are ignored. I think that presets on aliases are not that common (at least my +preset files on Fedora don't exhibit any such usage), and should not be +necessary, since whoever installs the preset can just refer to the real unit +file. It would be possible to overcome this limitation by gathering a list of +names of a unit first, and then checking whether *any* of the names matches the +presets list. That would require a significant redesign of the code, and be +a lot slower (since we would have to fully read all unit directories to preset +one unit) to so I'm not doing that for now. + +With this patch, two properties are satisfied: +- preset-all and preset are idempotent, and the second and subsequent invocations + do not produce any changes, +- preset-all and preset for a specific name produce the same state for that unit. + +Fixes #3616. + +Cherry-picked from: 11e11fd57a837ea1cb142009c3048882392f3ed3 +Related: #1375097 +--- + src/shared/install.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index b0a29ddd7..f01a21262 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2270,12 +2270,20 @@ static int preset_prepare_one( + const char *name) { + + InstallInfo *i; ++ _cleanup_(install_context_done) InstallContext tmp = {}; + int r; + +- if (install_info_find(plus, name) || +- install_info_find(minus, name)) ++ if (install_info_find(plus, name) || install_info_find(minus, name)) + return 0; + ++ r = install_info_discover(scope, &tmp, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ if (!streq(name, i->name)) { ++ log_debug("Skipping %s because is an alias for %s", name, i->name); ++ return 0; ++ } ++ + r = unit_file_query_preset(scope, root_dir, name); + if (r < 0) + return r; diff --git a/SOURCES/0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch b/SOURCES/0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch new file mode 100644 index 00000000..3346db0f --- /dev/null +++ b/SOURCES/0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch @@ -0,0 +1,23 @@ +From 195083a33b4204d513787e7f4b6c63f19a0fe1c7 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 13 Sep 2016 13:18:38 +0200 +Subject: [PATCH] 40-redhat.rules: don't hoplug memory on s390x + +Resolves: #1370161 +--- + rules/40-redhat.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 3335fe507..4c56950da 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -4,7 +4,7 @@ + SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" + + # Memory hotadd request +-SUBSYSTEM=="memory", ACTION=="add", ATTR{state}=="offline", ATTR{state}="online" ++SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/usr/bin/systemd-detect-virt", RESULT!="zvm", ATTR{state}=="offline", ATTR{state}="online" + + # reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded + ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge" diff --git a/SOURCES/0408-If-the-notification-message-length-is-0-ignore-the-m.patch b/SOURCES/0408-If-the-notification-message-length-is-0-ignore-the-m.patch new file mode 100644 index 00000000..3ac0db29 --- /dev/null +++ b/SOURCES/0408-If-the-notification-message-length-is-0-ignore-the-m.patch @@ -0,0 +1,31 @@ +From cd238111a7980917e04cfdc5dae144d1fb4c0a49 Mon Sep 17 00:00:00 2001 +From: Jorge Niedbalski +Date: Wed, 28 Sep 2016 18:25:50 -0300 +Subject: [PATCH] If the notification message length is 0, ignore the message + (#4237) + +Fixes #4234. + +Signed-off-by: Jorge Niedbalski + +Cherry-picked from: 531ac2b2349da02acc9c382849758e07eb92b020 +Resolves: #1380175 +--- + src/core/manager.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 71dd70c94..689b26615 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1678,6 +1678,10 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + + return -errno; + } ++ if (n == 0) { ++ log_debug("Got zero-length notification message. Ignoring."); ++ return 0; ++ } + + CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { diff --git a/SOURCES/0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch b/SOURCES/0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch new file mode 100644 index 00000000..43ade4a8 --- /dev/null +++ b/SOURCES/0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch @@ -0,0 +1,61 @@ +From 6d590cc99d696e9b0bf5b6edf7582b824f5177ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 24 Sep 2016 20:58:04 -0400 +Subject: [PATCH] systemctl: suppress errors with "show" for nonexistent units + and properties + +Show is documented to be program-parseable, and printing the warning about +about a non-existent unit, while useful for humans, broke a lot of scripts. +Restore previous behaviour of returning success and printing empty or useless +stuff for units which do not exist, and printing empty values for properties +which do not exists. + +With SYSTEMD_LOG_LEVEL=debug, hints are printed, but the return value is +still 0. + +This undoes parts of e33a06a and 3dced37b7 and fixes #3856. + +We might consider adding an explicit switch to fail on missing units/properties +(e.g. --ensure-exists or similar), and make -P foobar equivalent to +--ensure-exists --property=foobar. + +Cherry-picked from: bd5b9f0a12dd9c1947b11534e99c395ddf44caa9 +Resolves: #1380259 +--- + src/systemctl/systemctl.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 0644784a5..a578897d9 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4272,12 +4272,14 @@ static int show_one( + return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); + + if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) { +- log_error("Unit %s could not be found.", unit); ++ log_full(streq(verb, "status") ? LOG_ERR : LOG_DEBUG, ++ "Unit %s could not be found.", unit); + + if (streq(verb, "status")) + return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + +- return -ENOENT; ++ if (!streq(verb, "show")) ++ return -ENOENT; + } + + r = sd_bus_message_rewind(reply, true); +@@ -4343,10 +4345,11 @@ static int show_one( + + if (show_properties) { + char **pp; ++ int not_found_level = streq(verb, "show") ? LOG_DEBUG : LOG_WARNING; + + STRV_FOREACH(pp, arg_properties) { + if (!set_contains(found_properties, *pp)) { +- log_warning("Property %s does not exist.", *pp); ++ log_full(not_found_level, "Property %s does not exist.", *pp); + r = -ENXIO; + } + } diff --git a/SOURCES/0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch b/SOURCES/0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch new file mode 100644 index 00000000..2bcd11b5 --- /dev/null +++ b/SOURCES/0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch @@ -0,0 +1,24 @@ +From 2cd738ce220e0dd11d3b19cf593e159a7e31ddc4 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 16 Sep 2016 14:45:01 +0200 +Subject: [PATCH] 40-redhat.rules: disable auto-online of hot-plugged memory on + IBM z Systems + +Related: #1375603 +--- + rules/40-redhat.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 4c56950da..0164dc921 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -4,7 +4,7 @@ + SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" + + # Memory hotadd request +-SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/usr/bin/systemd-detect-virt", RESULT!="zvm", ATTR{state}=="offline", ATTR{state}="online" ++SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online" + + # reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded + ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge" diff --git a/SOURCES/0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch b/SOURCES/0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch new file mode 100644 index 00000000..c9eca034 --- /dev/null +++ b/SOURCES/0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch @@ -0,0 +1,49 @@ +From 93c5087eed9abf8012dc5b0ccd2dd7ead1323899 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Thu, 29 Sep 2016 19:44:34 +0200 +Subject: [PATCH] pid1: don't return any error in manager_dispatch_notify_fd() + (#4240) + +If manager_dispatch_notify_fd() fails and returns an error then the handling of +service notifications will be disabled entirely leading to a compromised system. + +For example pid1 won't be able to receive the WATCHDOG messages anymore and +will kill all services supposed to send such messages. +Cherry-picked from: 9987750e7a4c62e0eb8473603150596ba7c3a015 +Resolves: #1380259 +--- + src/core/manager.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 689b26615..ed8105955 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1673,10 +1673,14 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + + n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (n < 0) { +- if (errno == EAGAIN || errno == EINTR) +- return 0; ++ if (!IN_SET(errno, EAGAIN, EINTR)) ++ log_error("Failed to receive notification message: %m"); + +- return -errno; ++ /* It's not an option to return an error here since it ++ * would disable the notification handler entirely. Services ++ * wouldn't be able to send the WATCHDOG message for ++ * example... */ ++ return 0; + } + if (n == 0) { + log_debug("Got zero-length notification message. Ignoring."); +@@ -1703,7 +1707,8 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + r = fdset_new_array(&fds, fd_array, n_fds); + if (r < 0) { + close_many(fd_array, n_fds); +- return log_oom(); ++ log_oom(); ++ return 0; + } + } + diff --git a/SOURCES/0412-pid1-process-zero-length-notification-messages-again.patch b/SOURCES/0412-pid1-process-zero-length-notification-messages-again.patch new file mode 100644 index 00000000..6fb6d68c --- /dev/null +++ b/SOURCES/0412-pid1-process-zero-length-notification-messages-again.patch @@ -0,0 +1,81 @@ +From c7bcd6cf1967e401225c3d6057e0ee62cdc29f8c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 29 Sep 2016 16:06:02 +0200 +Subject: [PATCH] pid1: process zero-length notification messages again + +This undoes 531ac2b234. I acked that patch without looking at the code +carefully enough. There are two problems: +- we want to process the fds anyway +- in principle empty notification messages are valid, and we should + process them as usual, including logging using log_unit_debug(). + +Cherry-picked from: 8523bf7dd514a3a2c6114b7b8fb8f308b4f09fc4 +Resolves: #1380259 + +Cherry-picked from: a86b767 +Resolves: #1380259 +--- + src/core/manager.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index ed8105955..0376c4d4b 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1614,13 +1614,12 @@ static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, ui + return 0; + } + +-static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) { ++static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, FDSet *fds) { + _cleanup_strv_free_ char **tags = NULL; + + assert(m); + assert(u); + assert(buf); +- assert(n > 0); + + tags = strv_split(buf, "\n\r"); + if (!tags) { +@@ -1682,10 +1681,6 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + * example... */ + return 0; + } +- if (n == 0) { +- log_debug("Got zero-length notification message. Ignoring."); +- return 0; +- } + + CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { +@@ -1722,25 +1717,27 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + return 0; + } + ++ /* The message should be a string. Here we make sure it's NUL-terminated, ++ * but only the part until first NUL will be used anyway. */ + buf[n] = 0; + + /* Notify every unit that might be interested, but try + * to avoid notifying the same one multiple times. */ + u1 = manager_get_unit_by_pid(m, ucred->pid); + if (u1) { +- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); ++ manager_invoke_notify_message(m, u1, ucred->pid, buf, fds); + found = true; + } + + u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); + if (u2 && u2 != u1) { +- manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); ++ manager_invoke_notify_message(m, u2, ucred->pid, buf, fds); + found = true; + } + + u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); + if (u3 && u3 != u2 && u3 != u1) { +- manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); ++ manager_invoke_notify_message(m, u3, ucred->pid, buf, fds); + found = true; + } + diff --git a/SOURCES/0413-pid1-more-informative-error-message-for-ignored-noti.patch b/SOURCES/0413-pid1-more-informative-error-message-for-ignored-noti.patch new file mode 100644 index 00000000..63d5797b --- /dev/null +++ b/SOURCES/0413-pid1-more-informative-error-message-for-ignored-noti.patch @@ -0,0 +1,37 @@ +From f441ddae6363a10b1e8d8764bc906866f6ee6f48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 29 Sep 2016 16:07:41 +0200 +Subject: [PATCH] pid1: more informative error message for ignored + notifications + +It's probably easier to diagnose a bad notification message if the +contents are printed. But still, do anything only if debugging is on. + + Conflicts: + src/core/manager.c + +Cherry-picked from: a86b76753d7868c2d05f046f601bc7dc89fc2203 +Resolves: #1380259 +--- + src/core/manager.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 0376c4d4b..27f032b9d 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1631,6 +1631,14 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const + + if (UNIT_VTABLE(u)->notify_message) + UNIT_VTABLE(u)->notify_message(u, pid, tags, fds); ++ else if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) { ++ _cleanup_free_ char *x = NULL, *y = NULL; ++ ++ x = cescape(buf); ++ if (x) ++ y = ellipsize(x, 20, 90); ++ log_unit_debug(u, "Got notification message \"%s\", ignoring.", strnull(y)); ++ } + } + + static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { diff --git a/SOURCES/0414-manager-219-needs-u-id-in-log_unit_debug.patch b/SOURCES/0414-manager-219-needs-u-id-in-log_unit_debug.patch new file mode 100644 index 00000000..ed6eda40 --- /dev/null +++ b/SOURCES/0414-manager-219-needs-u-id-in-log_unit_debug.patch @@ -0,0 +1,24 @@ +From 7dbaab7b61fb25d91178f097cf7474d855d0ae29 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 7 Oct 2016 14:05:40 +0200 +Subject: [PATCH] manager: 219 needs u->id in log_unit_debug + +RHEL-only +Related: #1380259 +--- + 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 27f032b9d..6d045fdf3 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1637,7 +1637,7 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const + x = cescape(buf); + if (x) + y = ellipsize(x, 20, 90); +- log_unit_debug(u, "Got notification message \"%s\", ignoring.", strnull(y)); ++ log_unit_debug(u->id, "Got notification message \"%s\", ignoring.", strnull(y)); + } + } + diff --git a/SOURCES/0415-virt-add-possibility-to-skip-the-check-for-chroot.patch b/SOURCES/0415-virt-add-possibility-to-skip-the-check-for-chroot.patch new file mode 100644 index 00000000..f40e585f --- /dev/null +++ b/SOURCES/0415-virt-add-possibility-to-skip-the-check-for-chroot.patch @@ -0,0 +1,55 @@ +From f3750cbfd21b2e5f6f46077082f60e3a74ee4807 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 17 Oct 2016 08:09:58 +0200 +Subject: [PATCH] virt: add possibility to skip the check for chroot + +Cherry-picked from: 08a28eeca70eeefb55af61191b63e4c938daca73 +Resolves: #1379852 +--- + src/shared/env-util.c | 10 ++++++++++ + src/shared/env-util.h | 2 ++ + src/shared/util.c | 3 +++ + 3 files changed, 15 insertions(+) + +diff --git a/src/shared/env-util.c b/src/shared/env-util.c +index 038246d21..e8da4c978 100644 +--- a/src/shared/env-util.c ++++ b/src/shared/env-util.c +@@ -449,3 +449,13 @@ char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const cha + + return e; + } ++ ++int getenv_bool(const char *p) { ++ const char *e; ++ ++ e = getenv(p); ++ if (!e) ++ return -ENXIO; ++ ++ return parse_boolean(e); ++} +diff --git a/src/shared/env-util.h b/src/shared/env-util.h +index 618441a65..252d87be1 100644 +--- a/src/shared/env-util.h ++++ b/src/shared/env-util.h +@@ -45,3 +45,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_; + + char *strv_env_get_n(char **l, const char *name, size_t k) _pure_; + char *strv_env_get(char **x, const char *n) _pure_; ++ ++int getenv_bool(const char *p); +diff --git a/src/shared/util.c b/src/shared/util.c +index 357fbfe7d..eab5ab816 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3776,6 +3776,9 @@ int files_same(const char *filea, const char *fileb) { + int running_in_chroot(void) { + int ret; + ++ if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0) ++ return 0; ++ + ret = files_same("/proc/1/root", "/"); + if (ret < 0) + return ret; diff --git a/SOURCES/0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch b/SOURCES/0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch new file mode 100644 index 00000000..2335a3e5 --- /dev/null +++ b/SOURCES/0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch @@ -0,0 +1,51 @@ +From 38d00b8a0453d38aecb725342ddd89a7c3dcb134 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 18 Nov 2016 14:00:57 +0100 +Subject: [PATCH] load-fragment: fix parsing values in bytes and prevent + returning -ERANGE incorrectly + +We didn't port our code base to use uint64_t instead of off_t as +upstream did. RLIMIT_INIFINITY is -1ULL and if we cast to off_t (64 bit +signed int on arches we support) then we get -1 and that is always +smaller than correct value returned by parse_size(). + +To make code changes as minimal as possible (i.e. not port everything +to uint64_t) let's cast off_t to uint64_t and not the other way +around. + +RHEL-only + +Resolves: #1396277 +--- + src/core/load-fragment.c | 2 +- + src/test/test-unit-file.c | 4 ++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 2f6209e05..83b6e7efc 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1105,7 +1105,7 @@ static int rlim_parse_size(const char *val, rlim_t *res) { + off_t u; + + r = parse_size(val, 1024, &u); +- if (r >= 0 && u >= (off_t) RLIM_INFINITY) ++ if (r >= 0 && (uint64_t) u >= RLIM_INFINITY) + r = -ERANGE; + if (r == 0) + *res = (rlim_t) u; +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 8acf071ff..038430505 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -554,6 +554,10 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + ++ assert_se(config_parse_bytes_limit(NULL, "fake", 1, "section", 1, "LimitSTACK", RLIMIT_STACK, "55", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_STACK]); ++ assert_se(rl[RLIMIT_STACK]->rlim_cur == 55); ++ assert_se(rl[RLIMIT_STACK]->rlim_cur == rl[RLIMIT_STACK]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); diff --git a/SOURCES/0417-core-fix-assertion-check.patch b/SOURCES/0417-core-fix-assertion-check.patch new file mode 100644 index 00000000..c5e5b29e --- /dev/null +++ b/SOURCES/0417-core-fix-assertion-check.patch @@ -0,0 +1,26 @@ +From efd1250249494b7501578da7de7830659b65c98b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 16 Feb 2016 13:18:36 +0100 +Subject: [PATCH] core: fix assertion check + +Fixes: #2632 + +Cherry-picked from: 3f51aec8647fe13f4b1e46b2f75ff635403adf91 +Resolves: #1396312 +--- + src/core/timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/timer.c b/src/core/timer.c +index 972dd73df..f318dc6f4 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -321,7 +321,7 @@ static void add_random(Timer *t, usec_t *v) { + usec_t add; + + assert(t); +- assert(*v); ++ assert(v); + + if (t->random_usec == 0) + return; diff --git a/SOURCES/0418-tmp.mount.hm4-After-swap.target-3087.patch b/SOURCES/0418-tmp.mount.hm4-After-swap.target-3087.patch new file mode 100644 index 00000000..dea3e054 --- /dev/null +++ b/SOURCES/0418-tmp.mount.hm4-After-swap.target-3087.patch @@ -0,0 +1,24 @@ +From 81c1781b3d148fb3853af8cc72bb403846a2b7ed Mon Sep 17 00:00:00 2001 +From: frankheckenbach +Date: Fri, 22 Apr 2016 14:21:30 +0200 +Subject: [PATCH] tmp.mount.hm4: After swap.target (#3087) + +fix issue #2930 +Cherry-picked from: a11fe93e04e775c3ce2ace92be761d5ff9fce2d9 +Resolves: #1298355 +--- + units/tmp.mount | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/tmp.mount b/units/tmp.mount +index af0cf4a55..8c53a8705 100644 +--- a/units/tmp.mount ++++ b/units/tmp.mount +@@ -13,6 +13,7 @@ ConditionPathIsSymbolicLink=!/tmp + DefaultDependencies=no + Conflicts=umount.target + Before=local-fs.target umount.target ++After=swap.target + + [Mount] + What=tmpfs diff --git a/SOURCES/0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch b/SOURCES/0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch new file mode 100644 index 00000000..0d0625e1 --- /dev/null +++ b/SOURCES/0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch @@ -0,0 +1,56 @@ +From 4fec67c88f7ddd02fecf711996f42ed4c9d24da6 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Mon, 23 Nov 2015 11:14:10 +0100 +Subject: [PATCH] make sure all swap units are ordered before the swap target + +When shutting down the system, the swap devices can be disabled long +time before the swap target is stopped. They're actually the first +units systemd turns off on my system. + +This is incorrect and due to swap devices having multiple associated +swap unit files. The main one is usually created by the fstab +generator and is used to start the swap device. + +Once done, systemd creates some 'alias' units for the same swap +device, one for each swap dev link. But those units are missing an +ordering dependencies which was created by the fstab generator for the +main swap unit. + +Therefore during shutdown those 'alias' units can be stopped at +anytime before unmount.target target. + +This patch makes sure that all swap units are stopped after the +swap.target target. + +Cherry-picked from: 8bf23dc757dacaaf5a8d2c21aabf71aee08d1a04 +Resolves: #1298355 +--- + src/core/swap.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/core/swap.c b/src/core/swap.c +index 42f995990..984be2d9a 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -210,6 +210,8 @@ static int swap_add_device_links(Swap *s) { + } + + static int swap_add_default_dependencies(Swap *s) { ++ int r; ++ + assert(s); + + if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM) +@@ -218,6 +220,12 @@ static int swap_add_default_dependencies(Swap *s) { + if (detect_container(NULL) > 0) + return 0; + ++ /* swap units generated for the swap dev links are missing the ++ * ordering dep against the swap target. */ ++ r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true); ++ if (r < 0) ++ return r; ++ + return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + } + diff --git a/SOURCES/0420-Recognise-Lustre-as-a-remote-file-system-4530.patch b/SOURCES/0420-Recognise-Lustre-as-a-remote-file-system-4530.patch new file mode 100644 index 00000000..05180ada --- /dev/null +++ b/SOURCES/0420-Recognise-Lustre-as-a-remote-file-system-4530.patch @@ -0,0 +1,30 @@ +From f1cb9320c6aca21b17c9a120eb70a788df8ac6d5 Mon Sep 17 00:00:00 2001 +From: "Brian J. Murrell" +Date: Mon, 31 Oct 2016 23:48:00 -0400 +Subject: [PATCH] Recognise Lustre as a remote file system (#4530) + +Lustre is also a remote file system that wants the network to be up before it is mounted. + +Cherry-picked from: 67ae43665e7e03becba197e98df5b3ce40269567 +Resolves: #1390542 +--- + src/shared/util.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index eab5ab816..66729f70e 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -1924,7 +1924,11 @@ bool fstype_is_network(const char *fstype) { + "nfs4\0" + "gfs\0" + "gfs2\0" +- "glusterfs\0"; ++ "glusterfs\0" ++ "pvfs2\0" /* OrangeFS */ ++ "ocfs2\0" ++ "lustre\0" ++ ; + + const char *x; + diff --git a/SOURCES/0421-unit-don-t-add-Requires-for-tmp.mount.patch b/SOURCES/0421-unit-don-t-add-Requires-for-tmp.mount.patch new file mode 100644 index 00000000..8cb9e110 --- /dev/null +++ b/SOURCES/0421-unit-don-t-add-Requires-for-tmp.mount.patch @@ -0,0 +1,24 @@ +From a0adbe08c612f1330221c1a8bcad3cb5aedcb71b Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 5 Sep 2016 12:47:09 +0200 +Subject: [PATCH] unit: don't add Requires for tmp.mount + +rhel-only +Resolves: #1372249 +--- + src/core/unit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 0e90d130a..a7d6d2f45 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -1155,7 +1155,7 @@ static int unit_add_mount_dependencies(Unit *u) { + if (r < 0) + return r; + +- if (m->fragment_path) { ++ if (m->fragment_path && !streq(m->id, "tmp.mount")) { + r = unit_add_dependency(u, UNIT_REQUIRES, m, true); + if (r < 0) + return r; diff --git a/SOURCES/0422-core-return-0-from-device_serialize.patch b/SOURCES/0422-core-return-0-from-device_serialize.patch new file mode 100644 index 00000000..a6cc1f58 --- /dev/null +++ b/SOURCES/0422-core-return-0-from-device_serialize.patch @@ -0,0 +1,32 @@ +From 16ea84cf76e69975336fc347226ee3f58be25bc2 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 24 Apr 2015 16:14:48 +0200 +Subject: [PATCH] core: return 0 from device_serialize() + +Fixes: + + CC src/core/libsystemd_core_la-device.lo +src/core/device.c: In function 'device_serialize': +src/core/device.c:169:1: warning: control reaches end of non-void function [-Wreturn-type] + } + ^ + +Cherry-picked from: 0108f6ecc85eccc0177579f575d7bc3d56d43bc6 +Resolves: #1403249 +--- + src/core/device.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/core/device.c b/src/core/device.c +index bdc8466ab..befbae83f 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -168,6 +168,8 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) { + assert(fds); + + unit_serialize_item(u, f, "state", device_state_to_string(d->state)); ++ ++ return 0; + } + + static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { diff --git a/SOURCES/0423-mtd_probe-include-stdint.patch b/SOURCES/0423-mtd_probe-include-stdint.patch new file mode 100644 index 00000000..a7b5b43f --- /dev/null +++ b/SOURCES/0423-mtd_probe-include-stdint.patch @@ -0,0 +1,23 @@ +From 5c1473ccbbcdf4f1ec3b18609adb351946ed74b5 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 13 Dec 2016 14:25:38 +0100 +Subject: [PATCH] mtd_probe: include stdint + +rhel-only +Resolves: #1404251 +--- + src/udev/mtd_probe/mtd_probe.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h +index d99be9add..cead37402 100644 +--- a/src/udev/mtd_probe/mtd_probe.h ++++ b/src/udev/mtd_probe/mtd_probe.h +@@ -20,6 +20,7 @@ + #pragma once + + #include ++#include + + /* Full oob structure as written on the flash */ + struct sm_oob { diff --git a/SOURCES/0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch b/SOURCES/0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch new file mode 100644 index 00000000..9cfda58a --- /dev/null +++ b/SOURCES/0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch @@ -0,0 +1,41 @@ +From 0f3a67a0e4d243952e9ae4965a30e704885f03ef Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 6 Jan 2017 10:27:35 +0100 +Subject: [PATCH] tests: fix failure of test-execute if /dev/mem is not + available (#5028) + +/dev/mem isn't necessarily available. Recently, I've encountered arm64 +systems that didn't provide raw memory access via /dev/mem. Instead, +let's use /dev/kmsg since we don't support systems w/o it anyway. + +Cherry-picked from: 01349f5d01e0b59168722403b0c1c2325b15512c +Resolves: #1410056 +--- + test/exec-privatedevices-no.service | 2 +- + test/exec-privatedevices-yes.service | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/exec-privatedevices-no.service b/test/exec-privatedevices-no.service +index cf4f275fb..af1daf78f 100644 +--- a/test/exec-privatedevices-no.service ++++ b/test/exec-privatedevices-no.service +@@ -2,6 +2,6 @@ + Description=Test for PrivateDev=no + + [Service] +-ExecStart=/bin/sh -c 'exit $(test -c /dev/mem)' ++ExecStart=/bin/sh -c 'exit $(test -c /dev/kmsg)' + Type=oneshot + PrivateDevices=no +diff --git a/test/exec-privatedevices-yes.service b/test/exec-privatedevices-yes.service +index 85b3f4f98..384a7b01a 100644 +--- a/test/exec-privatedevices-yes.service ++++ b/test/exec-privatedevices-yes.service +@@ -2,6 +2,6 @@ + Description=Test for PrivateDev=yes + + [Service] +-ExecStart=/bin/sh -c 'exit $(test ! -c /dev/mem)' ++ExecStart=/bin/sh -c 'exit $(test ! -c /dev/kmsg)' + Type=oneshot + PrivateDevices=yes diff --git a/SOURCES/0425-sd-journal-properly-export-has_-persistent-runtime-_.patch b/SOURCES/0425-sd-journal-properly-export-has_-persistent-runtime-_.patch new file mode 100644 index 00000000..eecd2fdc --- /dev/null +++ b/SOURCES/0425-sd-journal-properly-export-has_-persistent-runtime-_.patch @@ -0,0 +1,28 @@ +From 0bf93125d4833bcdb7d187543581e4a6c14de159 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 21 Dec 2016 18:04:57 +0100 +Subject: [PATCH] sd-journal: properly export has_{persistent|runtime}_files() + +Cherry-picked from: 9a07f779bbeacc3358d405f6cf583506aaf655ae +Resolves: #1409527 +--- + src/libsystemd/libsystemd.sym.m4 | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 +index 76a8c921c..b1c2b43dd 100644 +--- a/src/libsystemd/libsystemd.sym.m4 ++++ b/src/libsystemd/libsystemd.sym.m4 +@@ -163,6 +163,12 @@ global: + sd_pid_notify_with_fds; + } LIBSYSTEMD_217; + ++LIBSYSTEMD_229 { ++global: ++ sd_journal_has_runtime_files; ++ sd_journal_has_persistent_files; ++} LIBSYSTEMD_219; ++ + m4_ifdef(`ENABLE_KDBUS', + LIBSYSTEMD_FUTURE { + global: diff --git a/SOURCES/0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch b/SOURCES/0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch new file mode 100644 index 00000000..ace4a1fc --- /dev/null +++ b/SOURCES/0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch @@ -0,0 +1,201 @@ +From be9fad86ae9ab721cd295210962da85706b839e9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Fri, 7 Oct 2016 03:08:21 +0200 +Subject: [PATCH] core: add possibility to set action for ctrl-alt-del burst + (#4105) + +For some certification, it should not be possible to reboot the machine through ctrl-alt-delete. Currently we suggest our customers to mask the ctrl-alt-delete target, but that is obviously not enough. + +Patching the keymaps to disable that is really not a way to go for them, because the settings need to be easily checked by some SCAP tools. + +Cherry-picked from: 24dd31c19ede505143833346ff850af942694aa6 +Resolves: #1353028 +--- + man/systemd-system.conf.xml | 11 ++++++++++ + src/core/main.c | 5 +++++ + src/core/manager.c | 51 +++++++++++++++++++++++++++++++++------------ + src/core/manager.h | 14 ++++++++++++- + src/core/system.conf | 1 + + 5 files changed, 68 insertions(+), 14 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 39d19bc71..236c20d5f 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -101,6 +101,17 @@ + arguments. + + ++ ++ CtrlAltDelBurstAction= ++ ++ Defines what action will be performed ++ if user presses Ctr-Alt-Delete more than 7 times in 2s. ++ Can be set to reboot-force, poweroff-force ++ or disabled with ignore. Defaults to ++ reboot-force. ++ ++ ++ + + CPUAffinity= + +diff --git a/src/core/main.c b/src/core/main.c +index c9d8ce4a4..6ac9c9d44 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -115,6 +115,7 @@ static FILE* arg_serialization = NULL; + static bool arg_default_cpu_accounting = false; + static bool arg_default_blockio_accounting = false; + static bool arg_default_memory_accounting = false; ++static CADBurstAction arg_cad_burst_action = CAD_BURST_ACTION_REBOOT; + + static void nop_handler(int sig) {} + +@@ -625,6 +626,8 @@ static int config_parse_join_controllers(const char *unit, + return 0; + } + ++static DEFINE_CONFIG_PARSE_ENUM(config_parse_cad_burst_action, cad_burst_action, CADBurstAction, "Failed to parse service restart specifier"); ++ + static int parse_config_file(void) { + + const ConfigTableItem items[] = { +@@ -673,6 +676,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting }, + { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, + { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, ++ { "Manager", "CtrlAltDelBurstAction", config_parse_cad_burst_action, 0, &arg_cad_burst_action}, + {} + }; + +@@ -1690,6 +1694,7 @@ int main(int argc, char *argv[]) { + m->initrd_timestamp = initrd_timestamp; + m->security_start_timestamp = security_start_timestamp; + m->security_finish_timestamp = security_finish_timestamp; ++ m->cad_burst_action = arg_cad_burst_action; + + manager_set_default_rlimits(m, arg_default_rlimit); + manager_environment_add(m, NULL, arg_default_environment); +diff --git a/src/core/manager.c b/src/core/manager.c +index 6d045fdf3..9048dde96 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1859,6 +1859,35 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) { + return r; + } + ++static void manager_handle_ctrl_alt_del(Manager *m) { ++ /* If the user presses C-A-D more than ++ * 7 times within 2s, we reboot/shutdown immediately, ++ * unless it was disabled in system.conf */ ++ ++ if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == CAD_BURST_ACTION_IGNORE) ++ manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); ++ else { ++ switch (m->cad_burst_action) { ++ ++ case CAD_BURST_ACTION_REBOOT: ++ m->exit_code = MANAGER_REBOOT; ++ break; ++ ++ case CAD_BURST_ACTION_POWEROFF: ++ m->exit_code = MANAGER_POWEROFF; ++ break; ++ ++ default: ++ assert_not_reached("Unknown action."); ++ } ++ ++ log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.", ++ cad_burst_action_to_string(m->cad_burst_action)); ++ status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.", ++ cad_burst_action_to_string(m->cad_burst_action)); ++ } ++} ++ + static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + ssize_t n; +@@ -1909,19 +1938,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t + + case SIGINT: + if (m->running_as == SYSTEMD_SYSTEM) { +- +- /* If the user presses C-A-D more than +- * 7 times within 2s, we reboot +- * immediately. */ +- +- if (ratelimit_test(&m->ctrl_alt_del_ratelimit)) +- manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); +- else { +- log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately."); +- status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately."); +- m->exit_code = MANAGER_REBOOT; +- } +- ++ manager_handle_ctrl_alt_del(m); + break; + } + +@@ -3319,3 +3336,11 @@ static const char *const manager_state_table[_MANAGER_STATE_MAX] = { + }; + + DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState); ++ ++static const char *const cad_burst_action_table[_CAD_BURST_ACTION_MAX] = { ++ [CAD_BURST_ACTION_IGNORE] = "ignore", ++ [CAD_BURST_ACTION_REBOOT] = "reboot-force", ++ [CAD_BURST_ACTION_POWEROFF] = "poweroff-force", ++}; ++ ++DEFINE_STRING_TABLE_LOOKUP(cad_burst_action, CADBurstAction); +diff --git a/src/core/manager.h b/src/core/manager.h +index 3e855db46..42be1fc43 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -64,6 +64,14 @@ typedef enum ManagerExitCode { + _MANAGER_EXIT_CODE_INVALID = -1 + } ManagerExitCode; + ++typedef enum CADBurstAction { ++ CAD_BURST_ACTION_IGNORE, ++ CAD_BURST_ACTION_REBOOT, ++ CAD_BURST_ACTION_POWEROFF, ++ _CAD_BURST_ACTION_MAX, ++ _CAD_BURST_ACTION_INVALID = -1 ++} CADBurstAction; ++ + typedef enum StatusType { + STATUS_TYPE_EPHEMERAL, + STATUS_TYPE_NORMAL, +@@ -300,8 +308,9 @@ struct Manager { + /* Used for processing polkit authorization responses */ + Hashmap *polkit_registry; + +- /* When the user hits C-A-D more than 7 times per 2s, reboot immediately... */ ++ /* When the user hits C-A-D more than 7 times per 2s, do something immediately... */ + RateLimit ctrl_alt_del_ratelimit; ++ CADBurstAction cad_burst_action; + }; + + int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m); +@@ -372,3 +381,6 @@ ManagerState manager_state(Manager *m); + + const char *manager_state_to_string(ManagerState m) _const_; + ManagerState manager_state_from_string(const char *s) _pure_; ++ ++const char *cad_burst_action_to_string(CADBurstAction a) _const_; ++CADBurstAction cad_burst_action_from_string(const char *s) _pure_; +diff --git a/src/core/system.conf b/src/core/system.conf +index 231609033..a11f59903 100644 +--- a/src/core/system.conf ++++ b/src/core/system.conf +@@ -20,6 +20,7 @@ + #CrashShell=no + #ShowStatus=yes + #CrashChVT=1 ++#CtrlAltDelBurstAction=reboot-force + #CPUAffinity=1 2 + #JoinControllers=cpu,cpuacct net_cls,net_prio + #RuntimeWatchdogSec=0 diff --git a/SOURCES/0427-failure-action-generalize-failure-action-to-emergenc.patch b/SOURCES/0427-failure-action-generalize-failure-action-to-emergenc.patch new file mode 100644 index 00000000..89b5d7c8 --- /dev/null +++ b/SOURCES/0427-failure-action-generalize-failure-action-to-emergenc.patch @@ -0,0 +1,461 @@ +From 2b787d523662b91334da24f1c77a7d803e53fab9 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 3 Jan 2017 16:05:42 +0100 +Subject: [PATCH] failure-action: generalize failure action to emergency action + +Cherry-picked from: 87a47f99bc8e576a63581ad2593c62eb10a53814 +Resolves: #1353028 +--- + Makefile.am | 4 +- + src/core/dbus-service.c | 6 +-- + src/core/dbus-unit.c | 4 +- + src/core/{failure-action.c => emergency-action.c} | 65 ++++++++++++----------- + src/core/{failure-action.h => emergency-action.h} | 28 +++++----- + src/core/job.c | 2 +- + src/core/load-fragment-gperf.gperf.m4 | 6 +-- + src/core/load-fragment.c | 4 +- + src/core/load-fragment.h | 2 +- + src/core/manager.h | 2 +- + src/core/service.c | 4 +- + src/core/service.h | 6 +-- + src/core/unit.c | 4 +- + src/core/unit.h | 4 +- + src/test/test-tables.c | 2 +- + 15 files changed, 72 insertions(+), 71 deletions(-) + rename src/core/{failure-action.c => emergency-action.c} (63%) + rename src/core/{failure-action.h => emergency-action.h} (58%) + +diff --git a/Makefile.am b/Makefile.am +index 3848338a2..b347aed7d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1182,8 +1182,8 @@ libsystemd_core_la_SOURCES = \ + src/core/audit-fd.h \ + src/core/show-status.c \ + src/core/show-status.h \ +- src/core/failure-action.c \ +- src/core/failure-action.h ++ src/core/emergency-action.c \ ++ src/core/emergency-action.h + + nodist_libsystemd_core_la_SOURCES = \ + src/core/load-fragment-gperf.c \ +diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c +index 6d4713bab..325ed13f5 100644 +--- a/src/core/dbus-service.c ++++ b/src/core/dbus-service.c +@@ -34,7 +34,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult); + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart); + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess); +-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction); ++static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction); + + const sd_bus_vtable bus_service_vtable[] = { + SD_BUS_VTABLE_START(0), +@@ -49,9 +49,9 @@ const sd_bus_vtable bus_service_vtable[] = { + BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0), + SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), +- SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Service, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), +- SD_BUS_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("FailureAction", "s", property_get_emergency_action, offsetof(Service, emergency_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST), +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index c3654db9e..89b00e94c 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -33,7 +33,7 @@ + + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); +-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction); ++static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction); + + static int property_get_names( + sd_bus *bus, +@@ -595,7 +595,7 @@ const sd_bus_vtable bus_unit_vtable[] = { + SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), +- SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), +diff --git a/src/core/failure-action.c b/src/core/emergency-action.c +similarity index 63% +rename from src/core/failure-action.c +rename to src/core/emergency-action.c +index ce522a4e4..f07b1257a 100644 +--- a/src/core/failure-action.c ++++ b/src/core/emergency-action.c +@@ -27,44 +27,45 @@ + #include "bus-util.h" + #include "bus-error.h" + #include "special.h" +-#include "failure-action.h" ++#include "emergency-action.h" + +-static void log_and_status(Manager *m, const char *message) { +- log_warning("%s", message); ++static void log_and_status(Manager *m, const char *message, const char *reason) { ++ log_warning("%s: %s", message, reason); + manager_status_printf(m, STATUS_TYPE_EMERGENCY, + ANSI_HIGHLIGHT_RED_ON " !! " ANSI_HIGHLIGHT_OFF, +- "%s", message); ++ "%s: %s", message, reason); + } + +-int failure_action( ++int emergency_action( + Manager *m, +- FailureAction action, +- const char *reboot_arg) { ++ EmergencyAction action, ++ const char *reboot_arg, ++ const char *reason) { + + int r; + + assert(m); + assert(action >= 0); +- assert(action < _FAILURE_ACTION_MAX); ++ assert(action < _EMERGENCY_ACTION_MAX); + +- if (action == FAILURE_ACTION_NONE) ++ if (action == EMERGENCY_ACTION_NONE) + return -ECANCELED; + + if (m->running_as == SYSTEMD_USER) { + /* Downgrade all options to simply exiting if we run + * in user mode */ + +- log_warning("Exiting as result of failure."); ++ log_warning("Exiting: %s", reason); + m->exit_code = MANAGER_EXIT; + return -ECANCELED; + } + + switch (action) { + +- case FAILURE_ACTION_REBOOT: { ++ case EMERGENCY_ACTION_REBOOT: { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + +- log_and_status(m, "Rebooting as result of failure."); ++ log_and_status(m, "Rebooting", reason); + + update_reboot_param_file(reboot_arg); + r = manager_add_job_by_name(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL); +@@ -74,15 +75,15 @@ int failure_action( + break; + } + +- case FAILURE_ACTION_REBOOT_FORCE: +- log_and_status(m, "Forcibly rebooting as result of failure."); ++ case EMERGENCY_ACTION_REBOOT_FORCE: ++ log_and_status(m, "Forcibly rebooting", reason); + + update_reboot_param_file(reboot_arg); + m->exit_code = MANAGER_REBOOT; + break; + +- case FAILURE_ACTION_REBOOT_IMMEDIATE: +- log_and_status(m, "Rebooting immediately as result of failure."); ++ case EMERGENCY_ACTION_REBOOT_IMMEDIATE: ++ log_and_status(m, "Rebooting immediately", reason); + + sync(); + +@@ -95,10 +96,10 @@ int failure_action( + reboot(RB_AUTOBOOT); + break; + +- case FAILURE_ACTION_POWEROFF: { ++ case EMERGENCY_ACTION_POWEROFF: { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + +- log_and_status(m, "Powering off as result of failure."); ++ log_and_status(m, "Powering off", reason); + + r = manager_add_job_by_name(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, true, &error, NULL); + if (r < 0) +@@ -107,13 +108,13 @@ int failure_action( + break; + } + +- case FAILURE_ACTION_POWEROFF_FORCE: +- log_and_status(m, "Forcibly powering off as result of failure."); ++ case EMERGENCY_ACTION_POWEROFF_FORCE: ++ log_and_status(m, "Forcibly powering off", reason); + m->exit_code = MANAGER_POWEROFF; + break; + +- case FAILURE_ACTION_POWEROFF_IMMEDIATE: +- log_and_status(m, "Powering off immediately as result of failure."); ++ case EMERGENCY_ACTION_POWEROFF_IMMEDIATE: ++ log_and_status(m, "Powering off immediately", reason); + + sync(); + +@@ -122,19 +123,19 @@ int failure_action( + break; + + default: +- assert_not_reached("Unknown failure action"); ++ assert_not_reached("Unknown emergency action"); + } + + return -ECANCELED; + } + +-static const char* const failure_action_table[_FAILURE_ACTION_MAX] = { +- [FAILURE_ACTION_NONE] = "none", +- [FAILURE_ACTION_REBOOT] = "reboot", +- [FAILURE_ACTION_REBOOT_FORCE] = "reboot-force", +- [FAILURE_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate", +- [FAILURE_ACTION_POWEROFF] = "poweroff", +- [FAILURE_ACTION_POWEROFF_FORCE] = "poweroff-force", +- [FAILURE_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate" ++static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = { ++ [EMERGENCY_ACTION_NONE] = "none", ++ [EMERGENCY_ACTION_REBOOT] = "reboot", ++ [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force", ++ [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate", ++ [EMERGENCY_ACTION_POWEROFF] = "poweroff", ++ [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force", ++ [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate" + }; +-DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction); ++DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction); +diff --git a/src/core/failure-action.h b/src/core/emergency-action.h +similarity index 58% +rename from src/core/failure-action.h +rename to src/core/emergency-action.h +index 1af4dd987..d3ac0f31c 100644 +--- a/src/core/failure-action.h ++++ b/src/core/emergency-action.h +@@ -22,22 +22,22 @@ + along with systemd; If not, see . + ***/ + +-typedef enum FailureAction { +- FAILURE_ACTION_NONE, +- FAILURE_ACTION_REBOOT, +- FAILURE_ACTION_REBOOT_FORCE, +- FAILURE_ACTION_REBOOT_IMMEDIATE, +- FAILURE_ACTION_POWEROFF, +- FAILURE_ACTION_POWEROFF_FORCE, +- FAILURE_ACTION_POWEROFF_IMMEDIATE, +- _FAILURE_ACTION_MAX, +- _FAILURE_ACTION_INVALID = -1 +-} FailureAction; ++typedef enum EmergencyAction { ++ EMERGENCY_ACTION_NONE, ++ EMERGENCY_ACTION_REBOOT, ++ EMERGENCY_ACTION_REBOOT_FORCE, ++ EMERGENCY_ACTION_REBOOT_IMMEDIATE, ++ EMERGENCY_ACTION_POWEROFF, ++ EMERGENCY_ACTION_POWEROFF_FORCE, ++ EMERGENCY_ACTION_POWEROFF_IMMEDIATE, ++ _EMERGENCY_ACTION_MAX, ++ _EMERGENCY_ACTION_INVALID = -1 ++} EmergencyAction; + + #include "macro.h" + #include "manager.h" + +-int failure_action(Manager *m, FailureAction action, const char *reboot_arg); ++int emergency_action(Manager *m, EmergencyAction action, const char *reboot_arg, const char *reason); + +-const char* failure_action_to_string(FailureAction i) _const_; +-FailureAction failure_action_from_string(const char *s) _pure_; ++const char* emergency_action_to_string(EmergencyAction i) _const_; ++EmergencyAction emergency_action_from_string(const char *s) _pure_; +diff --git a/src/core/job.c b/src/core/job.c +index c2876dec1..703286496 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -916,7 +916,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user + u = j->unit; + job_finish_and_invalidate(j, JOB_TIMEOUT, true, false); + +- failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg); ++ emergency_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg, "job timed out"); + + return 0; + } +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index ce1397c7e..45d1ead45 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -156,7 +156,7 @@ Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, + Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate) + Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Unit, ignore_on_snapshot) + Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout) +-Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action) ++Unit.JobTimeoutAction, config_parse_emergency_action, 0, offsetof(Unit, job_timeout_action) + Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) + Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions) + Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions) +@@ -211,9 +211,9 @@ Service.TimeoutStopSec, config_parse_service_timeout, 0, + Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec) + Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval) + Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst) +-Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Service, start_limit_action) ++Service.StartLimitAction, config_parse_emergency_action, 0, offsetof(Service, start_limit_action) + Service.RebootArgument, config_parse_string, 0, offsetof(Service, reboot_arg) +-Service.FailureAction, config_parse_failure_action, 0, offsetof(Service, failure_action) ++Service.FailureAction, config_parse_emergency_action, 0, offsetof(Service, emergency_action) + Service.Type, config_parse_service_type, 0, offsetof(Service, type) + Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) + Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 83b6e7efc..4fecb8314 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -2382,7 +2382,7 @@ int config_parse_unit_condition_null( + } + + DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); +-DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier"); ++DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier"); + + int config_parse_unit_requires_mounts_for( + const char *unit, +@@ -3931,7 +3931,7 @@ void unit_dump_config_items(FILE *f) { + { config_parse_unit_slice, "SLICE" }, + { config_parse_documentation, "URL" }, + { config_parse_service_timeout, "SECONDS" }, +- { config_parse_failure_action, "ACTION" }, ++ { config_parse_emergency_action, "ACTION" }, + { config_parse_set_status, "STATUS" }, + { config_parse_service_sockets, "SOCKETS" }, + { config_parse_environ, "ENVIRON" }, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 359794d0a..611479612 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -78,7 +78,7 @@ int config_parse_unit_condition_string(const char *unit, const char *filename, u + int config_parse_unit_condition_null(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_kill_mode(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_notify_access(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_failure_action(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_emergency_action(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_unit_requires_mounts_for(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_syscall_filter(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_syscall_archs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/core/manager.h b/src/core/manager.h +index 42be1fc43..59913f489 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -85,7 +85,7 @@ typedef enum StatusType { + #include "unit-name.h" + #include "exit-status.h" + #include "show-status.h" +-#include "failure-action.h" ++#include "emergency-action.h" + + struct Manager { + /* Note that the set of units we know of is allowed to be +diff --git a/src/core/service.c b/src/core/service.c +index babd3c52a..6e7baa76c 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -1280,7 +1280,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) + + if (s->result != SERVICE_SUCCESS) { + log_unit_warning(UNIT(s)->id, "%s failed.", UNIT(s)->id); +- failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg); ++ emergency_action(UNIT(s)->manager, s->emergency_action, s->reboot_arg, "service failed"); + } + + if (allow_restart && +@@ -1821,7 +1821,7 @@ static int service_start_limit_test(Service *s) { + + log_unit_warning(UNIT(s)->id, "start request repeated too quickly for %s", UNIT(s)->id); + +- return failure_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg); ++ return emergency_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg, "service failed"); + } + + static int service_start(Unit *u) { +diff --git a/src/core/service.h b/src/core/service.h +index dfeee6a68..1f937dfe5 100644 +--- a/src/core/service.h ++++ b/src/core/service.h +@@ -29,7 +29,7 @@ typedef struct ServiceFDStore ServiceFDStore; + #include "ratelimit.h" + #include "kill.h" + #include "exit-status.h" +-#include "failure-action.h" ++#include "emergency-action.h" + + typedef enum ServiceState { + SERVICE_DEAD, +@@ -197,8 +197,8 @@ struct Service { + int status_errno; + + RateLimit start_limit; +- FailureAction start_limit_action; +- FailureAction failure_action; ++ EmergencyAction start_limit_action; ++ EmergencyAction emergency_action; + char *reboot_arg; + + UnitRef accept_socket; +diff --git a/src/core/unit.c b/src/core/unit.c +index a7d6d2f45..4eb0d78f4 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -937,8 +937,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { + if (u->job_timeout > 0) + fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0)); + +- if (u->job_timeout_action != FAILURE_ACTION_NONE) +- fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, failure_action_to_string(u->job_timeout_action)); ++ if (u->job_timeout_action != EMERGENCY_ACTION_NONE) ++ fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action)); + + if (u->job_timeout_reboot_arg) + fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg); +diff --git a/src/core/unit.h b/src/core/unit.h +index 35287a5b7..85f52df18 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -41,7 +41,7 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; + #include "condition.h" + #include "install.h" + #include "unit-name.h" +-#include "failure-action.h" ++#include "emergency-action.h" + + enum UnitActiveState { + UNIT_ACTIVE, +@@ -121,7 +121,7 @@ struct Unit { + + /* Job timeout and action to take */ + usec_t job_timeout; +- FailureAction job_timeout_action; ++ EmergencyAction job_timeout_action; + char *job_timeout_reboot_arg; + + /* References to this */ +diff --git a/src/test/test-tables.c b/src/test/test-tables.c +index bda224bec..e4097903c 100644 +--- a/src/test/test-tables.c ++++ b/src/test/test-tables.c +@@ -67,7 +67,7 @@ int main(int argc, char **argv) { + test_table(device_state, DEVICE_STATE); + test_table(exec_input, EXEC_INPUT); + test_table(exec_output, EXEC_OUTPUT); +- test_table(failure_action, FAILURE_ACTION); ++ test_table(emergency_action, EMERGENCY_ACTION); + test_table(job_mode, JOB_MODE); + test_table(job_result, JOB_RESULT); + test_table(job_state, JOB_STATE); diff --git a/SOURCES/0428-core-use-emergency_action-for-ctr-alt-del-burst.patch b/SOURCES/0428-core-use-emergency_action-for-ctr-alt-del-burst.patch new file mode 100644 index 00000000..5442c84b --- /dev/null +++ b/SOURCES/0428-core-use-emergency_action-for-ctr-alt-del-burst.patch @@ -0,0 +1,157 @@ +From 2170d1e510a9c30e71bc642b54d8b71fb01b47bc Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 18 Oct 2016 12:16:32 +0200 +Subject: [PATCH] core: use emergency_action for ctr+alt+del burst + +Fixes #4306 + +Cherry-picked from: ae8c7939df962cbf660b2b9517fe46be272f58b9 +Resolves: #1353028 +--- + man/systemd-system.conf.xml | 7 ++++--- + src/core/main.c | 7 +++---- + src/core/manager.c | 33 ++++----------------------------- + src/core/manager.h | 13 +------------ + 4 files changed, 12 insertions(+), 48 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 236c20d5f..57b3b90be 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -105,9 +105,10 @@ + CtrlAltDelBurstAction= + + Defines what action will be performed +- if user presses Ctr-Alt-Delete more than 7 times in 2s. +- Can be set to reboot-force, poweroff-force +- or disabled with ignore. Defaults to ++ if user presses Ctrl-Alt-Delete more than 7 times in 2s. ++ Can be set to reboot-force, poweroff-force, ++ reboot-immediate, poweroff-immediate ++ or disabled with none. Defaults to + reboot-force. + + +diff --git a/src/core/main.c b/src/core/main.c +index 6ac9c9d44..6f8367632 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -77,6 +77,7 @@ + #include "ima-setup.h" + #include "smack-setup.h" + #include "kmod-setup.h" ++#include "emergency-action.h" + + static enum { + ACTION_RUN, +@@ -115,7 +116,7 @@ static FILE* arg_serialization = NULL; + static bool arg_default_cpu_accounting = false; + static bool arg_default_blockio_accounting = false; + static bool arg_default_memory_accounting = false; +-static CADBurstAction arg_cad_burst_action = CAD_BURST_ACTION_REBOOT; ++static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; + + static void nop_handler(int sig) {} + +@@ -626,8 +627,6 @@ static int config_parse_join_controllers(const char *unit, + return 0; + } + +-static DEFINE_CONFIG_PARSE_ENUM(config_parse_cad_burst_action, cad_burst_action, CADBurstAction, "Failed to parse service restart specifier"); +- + static int parse_config_file(void) { + + const ConfigTableItem items[] = { +@@ -676,7 +675,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting }, + { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, + { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, +- { "Manager", "CtrlAltDelBurstAction", config_parse_cad_burst_action, 0, &arg_cad_burst_action}, ++ { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, + {} + }; + +diff --git a/src/core/manager.c b/src/core/manager.c +index 9048dde96..8bd80e687 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1864,28 +1864,11 @@ static void manager_handle_ctrl_alt_del(Manager *m) { + * 7 times within 2s, we reboot/shutdown immediately, + * unless it was disabled in system.conf */ + +- if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == CAD_BURST_ACTION_IGNORE) ++ if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE) + manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); +- else { +- switch (m->cad_burst_action) { +- +- case CAD_BURST_ACTION_REBOOT: +- m->exit_code = MANAGER_REBOOT; +- break; +- +- case CAD_BURST_ACTION_POWEROFF: +- m->exit_code = MANAGER_POWEROFF; +- break; +- +- default: +- assert_not_reached("Unknown action."); +- } +- +- log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.", +- cad_burst_action_to_string(m->cad_burst_action)); +- status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.", +- cad_burst_action_to_string(m->cad_burst_action)); +- } ++ else ++ emergency_action(m, m->cad_burst_action, NULL, ++ "Ctrl-Alt-Del was pressed more than 7 times within 2s"); + } + + static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { +@@ -3336,11 +3319,3 @@ static const char *const manager_state_table[_MANAGER_STATE_MAX] = { + }; + + DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState); +- +-static const char *const cad_burst_action_table[_CAD_BURST_ACTION_MAX] = { +- [CAD_BURST_ACTION_IGNORE] = "ignore", +- [CAD_BURST_ACTION_REBOOT] = "reboot-force", +- [CAD_BURST_ACTION_POWEROFF] = "poweroff-force", +-}; +- +-DEFINE_STRING_TABLE_LOOKUP(cad_burst_action, CADBurstAction); +diff --git a/src/core/manager.h b/src/core/manager.h +index 59913f489..231c076b1 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -64,14 +64,6 @@ typedef enum ManagerExitCode { + _MANAGER_EXIT_CODE_INVALID = -1 + } ManagerExitCode; + +-typedef enum CADBurstAction { +- CAD_BURST_ACTION_IGNORE, +- CAD_BURST_ACTION_REBOOT, +- CAD_BURST_ACTION_POWEROFF, +- _CAD_BURST_ACTION_MAX, +- _CAD_BURST_ACTION_INVALID = -1 +-} CADBurstAction; +- + typedef enum StatusType { + STATUS_TYPE_EPHEMERAL, + STATUS_TYPE_NORMAL, +@@ -310,7 +302,7 @@ struct Manager { + + /* When the user hits C-A-D more than 7 times per 2s, do something immediately... */ + RateLimit ctrl_alt_del_ratelimit; +- CADBurstAction cad_burst_action; ++ EmergencyAction cad_burst_action; + }; + + int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m); +@@ -381,6 +373,3 @@ ManagerState manager_state(Manager *m); + + const char *manager_state_to_string(ManagerState m) _const_; + ManagerState manager_state_from_string(const char *s) _pure_; +- +-const char *cad_burst_action_to_string(CADBurstAction a) _const_; +-CADBurstAction cad_burst_action_from_string(const char *s) _pure_; diff --git a/SOURCES/0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch b/SOURCES/0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch new file mode 100644 index 00000000..021e726f --- /dev/null +++ b/SOURCES/0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch @@ -0,0 +1,40 @@ +From ee5aadde983315e72a82241dee95c0e041af15f4 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 6 Jan 2017 17:30:53 +0100 +Subject: [PATCH] udev/path_id: introduce support for NVMe devices (#4169) + +This appends the nvme name and namespace identifier attribute the the +PCI path for by-path links. Symlinks like the following are now present: + +lrwxrwxrwx. 1 root root 13 Sep 16 12:12 pci-0000:01:00.0-nvme-1 -> ../../nvme0n1 +lrwxrwxrwx. 1 root root 15 Sep 16 12:12 pci-0000:01:00.0-nvme-1-part1 -> ../../nvme0n1p1 + +Cc: Michal Sekletar +Signed-off-by: Keith Busch + +Cherry-picked from: b4c6f71b827d41a4af8007b735edf21ef7609f99 +Resolves: #1373150 +--- + src/udev/udev-builtin-path_id.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index a3b019bfc..88a812ff5 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -709,6 +709,15 @@ restart: + parent = skip_subsystem(parent, "scm"); + supported_transport = true; + supported_parent = true; ++ } else if (streq(subsys, "nvme")) { ++ const char *nsid = udev_device_get_sysattr_value(dev, "nsid"); ++ ++ if (nsid) { ++ path_prepend(&path, "nvme-%s", nsid); ++ parent = skip_subsystem(parent, "nvme"); ++ supported_parent = true; ++ supported_transport = true; ++ } + } + + parent = udev_device_get_parent(parent); diff --git a/SOURCES/0430-core-fix-CapabilityBoundingSet-merging.patch b/SOURCES/0430-core-fix-CapabilityBoundingSet-merging.patch new file mode 100644 index 00000000..50163847 --- /dev/null +++ b/SOURCES/0430-core-fix-CapabilityBoundingSet-merging.patch @@ -0,0 +1,40 @@ +From 5c7d92d36bd1b608ccba0adc3fdc5446e6575623 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Tue, 27 Oct 2015 14:40:28 +0300 +Subject: [PATCH] core: fix CapabilityBoundingSet merging + +Fixes: #1221 + +Cherry-picked from: b9d345b +Resolves: #1409586 +--- + src/core/load-fragment.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 4fecb8314..90d42b002 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1027,6 +1027,7 @@ int config_parse_bounding_set(const char *unit, + void *userdata) { + + uint64_t *capability_bounding_set_drop = data; ++ uint64_t capability_bounding_set; + const char *word, *state; + size_t l; + bool invert = false; +@@ -1067,10 +1068,11 @@ int config_parse_bounding_set(const char *unit, + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Trailing garbage, ignoring."); + +- if (invert) +- *capability_bounding_set_drop |= sum; ++ capability_bounding_set = invert ? ~sum : sum; ++ if (*capability_bounding_set_drop) ++ *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); + else +- *capability_bounding_set_drop |= ~sum; ++ *capability_bounding_set_drop = ~capability_bounding_set; + + return 0; + } diff --git a/SOURCES/0431-core-fix-capability-bounding-set-parsing.patch b/SOURCES/0431-core-fix-capability-bounding-set-parsing.patch new file mode 100644 index 00000000..0cd56488 --- /dev/null +++ b/SOURCES/0431-core-fix-capability-bounding-set-parsing.patch @@ -0,0 +1,26 @@ +From 13b70c13553c94c444f149bd086bd3e8d9cc39b6 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Thu, 29 Oct 2015 14:13:04 +0300 +Subject: [PATCH] core: fix capability bounding set parsing + +bug: CapabilityBoundingSet= doesn't reset all caps + +Cherry-picked from: 661b37b +Resolves: #1409586 +--- + src/core/load-fragment.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 90d42b002..705641971 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1069,7 +1069,7 @@ int config_parse_bounding_set(const char *unit, + "Trailing garbage, ignoring."); + + capability_bounding_set = invert ? ~sum : sum; +- if (*capability_bounding_set_drop) ++ if (*capability_bounding_set_drop && capability_bounding_set) + *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); + else + *capability_bounding_set_drop = ~capability_bounding_set; diff --git a/SOURCES/0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch b/SOURCES/0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch new file mode 100644 index 00000000..fc5bd245 --- /dev/null +++ b/SOURCES/0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch @@ -0,0 +1,163 @@ +From c56c1f6c2b683d6f20a7e8caeecec6c3cb76798f Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 3 Jan 2017 14:21:25 +0100 +Subject: [PATCH] core: make parsing of RLIMIT_NICE aware of actual nice levels + +RHEL-only +(most of code taken from 29857001854a02c292f1f3b324e7a66831e859c8) + +Resolves: #1409588 +--- + man/systemd.exec.xml | 7 +++- + src/core/load-fragment-gperf.gperf.m4 | 2 +- + src/core/load-fragment.c | 72 +++++++++++++++++++++++++++++++++++ + src/core/load-fragment.h | 1 + + src/core/main.c | 2 +- + 5 files changed, 81 insertions(+), 3 deletions(-) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 0cd469cd9..c5199d3a5 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -575,7 +575,12 @@ + granularity of the limits might influence their + enforcement. For example, time limits specified for + LimitCPU= will be rounded up implicitly to +- multiples of 1s. ++ multiples of 1s. For LimitNICE= the value ++ may be specified in two syntaxes: if prefixed with + ++ or -, the value is understood as regular Linux ++ nice value in the range -20..19. If not prefixed like this the value ++ is understood as raw resource limit parameter in the range 0..40 (with 0 being ++ equivalent to 1). + + Note that most process resource limits configured with + these options are per-process, and processes may fork in order +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 45d1ead45..f3a6e13d9 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -71,7 +71,7 @@ $1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEML + $1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) + $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) + $1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) +-$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) ++$1.LimitNICE, config_parse_nice_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) + $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) + $1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) + $1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 705641971..3a3c456da 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1154,6 +1154,56 @@ static int rlim_parse_usec(const char *val, rlim_t *res) { + return r; + } + ++static int rlim_parse_nice(const char *val, rlim_t *ret) { ++ uint64_t rl; ++ int r; ++ ++ /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the ++ * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is ++ * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight ++ * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we ++ * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0. ++ * ++ * Yeah, Linux is quality engineering sometimes... */ ++ ++ if (val[0] == '+') { ++ ++ /* Prefixed with "+": Parse as positive user-friendly nice value */ ++ r = safe_atou64(val + 1, &rl); ++ if (r < 0) ++ return r; ++ ++ if (rl >= PRIO_MAX) ++ return -ERANGE; ++ ++ rl = 20 - rl; ++ ++ } else if (val[0] == '-') { ++ ++ /* Prefixed with "-": Parse as negative user-friendly nice value */ ++ r = safe_atou64(val + 1, &rl); ++ if (r < 0) ++ return r; ++ ++ if (rl > (uint64_t) (-PRIO_MIN)) ++ return -ERANGE; ++ ++ rl = 20 + rl; ++ } else { ++ ++ /* Not prefixed: parse as raw resource limit value */ ++ r = safe_atou64(val, &rl); ++ if (r < 0) ++ return r; ++ ++ if (rl > (uint64_t) (20 - PRIO_MIN)) ++ return -ERANGE; ++ } ++ ++ *ret = (rlim_t) rl; ++ return 0; ++} ++ + static int parse_rlimit_range( + const char *unit, + const char *filename, +@@ -1286,6 +1336,28 @@ int config_parse_usec_limit( + return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec); + } + ++int config_parse_nice_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ struct rlimit **rl = data; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_nice); ++} + + #ifdef HAVE_SYSV_COMPAT + int config_parse_sysv_priority(const char *unit, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 611479612..7c69e5369 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -59,6 +59,7 @@ int config_parse_limit(const char *unit, const char *filename, unsigned line, co + int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_nice_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/core/main.c b/src/core/main.c +index 6f8367632..820cbc3e5 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -669,7 +669,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] }, + { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] }, + { "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, +- { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, ++ { "Manager", "DefaultLimitNICE", config_parse_nice_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, + { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] }, + { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, + { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting }, diff --git a/SOURCES/0433-shared-fix-double-free-in-unmask-5005.patch b/SOURCES/0433-shared-fix-double-free-in-unmask-5005.patch new file mode 100644 index 00000000..c8651741 --- /dev/null +++ b/SOURCES/0433-shared-fix-double-free-in-unmask-5005.patch @@ -0,0 +1,42 @@ +From 45f3c8e04093a1ed871eb67aa4c1c28b11d3346c Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 3 Jan 2017 21:34:36 +0100 +Subject: [PATCH] shared: fix double free in unmask (#5005) + +Easily reproducible: +1) systemctl mask foo +2) systemctl unmask foo foo + +The problem here is that the *i that is put into todo[] is later freed +in strv_uniq(), which is not directly visible from this patch. Somewhere +further in the code, the string that *i pointed to is freed again. That +happens only when multiple services with the same name/path are specified. + +(cherry picked from commit dc7dd61de610e9330abe7014860acfa733887d5e) +Resolves: #1409997 +--- + src/shared/install.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index f01a21262..1b59a96b1 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1602,7 +1602,7 @@ int unit_file_unmask( + + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + _cleanup_free_ char *config_path = NULL; +- _cleanup_free_ char **todo = NULL; ++ _cleanup_strv_free_ char **todo = NULL; + size_t n_todo = 0, n_allocated = 0; + char **i; + int r, q; +@@ -1639,7 +1639,7 @@ int unit_file_unmask( + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; + +- todo[n_todo++] = *i; ++ todo[n_todo++] = strdup(*i); + } + + strv_uniq(todo); diff --git a/SOURCES/0434-shared-fix-double-free-in-link.patch b/SOURCES/0434-shared-fix-double-free-in-link.patch new file mode 100644 index 00000000..ca6e2fde --- /dev/null +++ b/SOURCES/0434-shared-fix-double-free-in-link.patch @@ -0,0 +1,118 @@ +From 7ac4fc60181cfc7ff06e696da78e1b2819580745 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Mon, 9 Jan 2017 04:46:11 +0000 +Subject: [PATCH] shared: fix double free in link + +Fixes: +``` +touch hola.service +systemctl link $(pwd)/hola.service $(pwd)/hola.service +``` + +``` +==1==ERROR: AddressSanitizer: attempting double-free on 0x60300002c560 in thread T0 (systemd): + #0 0x7fc8c961cb00 in free (/lib64/libasan.so.3+0xc6b00) + #1 0x7fc8c90ebd3b in strv_clear src/basic/strv.c:83 + #2 0x7fc8c90ebdb6 in strv_free src/basic/strv.c:89 + #3 0x55637c758c77 in strv_freep src/basic/strv.h:37 + #4 0x55637c763ba9 in method_enable_unit_files_generic src/core/dbus-manager.c:1960 + #5 0x55637c763d16 in method_link_unit_files src/core/dbus-manager.c:2001 + #6 0x7fc8c92537ec in method_callbacks_run src/libsystemd/sd-bus/bus-objects.c:418 + #7 0x7fc8c9258830 in object_find_and_run src/libsystemd/sd-bus/bus-objects.c:1255 + #8 0x7fc8c92594d7 in bus_process_object src/libsystemd/sd-bus/bus-objects.c:1371 + #9 0x7fc8c91e7553 in process_message src/libsystemd/sd-bus/sd-bus.c:2563 + #10 0x7fc8c91e78ce in process_running src/libsystemd/sd-bus/sd-bus.c:2605 + #11 0x7fc8c91e8f61 in bus_process_internal src/libsystemd/sd-bus/sd-bus.c:2837 + #12 0x7fc8c91e90d2 in sd_bus_process src/libsystemd/sd-bus/sd-bus.c:2856 + #13 0x7fc8c91ea8f9 in io_callback src/libsystemd/sd-bus/sd-bus.c:3126 + #14 0x7fc8c928333b in source_dispatch src/libsystemd/sd-event/sd-event.c:2268 + #15 0x7fc8c9285cf7 in sd_event_dispatch src/libsystemd/sd-event/sd-event.c:2627 + #16 0x7fc8c92865fa in sd_event_run src/libsystemd/sd-event/sd-event.c:2686 + #17 0x55637c6b5257 in manager_loop src/core/manager.c:2274 + #18 0x55637c6a2194 in main src/core/main.c:1920 + #19 0x7fc8c7ac7400 in __libc_start_main (/lib64/libc.so.6+0x20400) + #20 0x55637c697339 in _start (/usr/lib/systemd/systemd+0xcd339) + +0x60300002c560 is located 0 bytes inside of 19-byte region [0x60300002c560,0x60300002c573) +freed by thread T0 (systemd) here: + #0 0x7fc8c961cb00 in free (/lib64/libasan.so.3+0xc6b00) + #1 0x7fc8c90ee320 in strv_remove src/basic/strv.c:630 + #2 0x7fc8c90ee190 in strv_uniq src/basic/strv.c:602 + #3 0x7fc8c9180533 in unit_file_link src/shared/install.c:1996 + #4 0x55637c763b25 in method_enable_unit_files_generic src/core/dbus-manager.c:1985 + #5 0x55637c763d16 in method_link_unit_files src/core/dbus-manager.c:2001 + #6 0x7fc8c92537ec in method_callbacks_run src/libsystemd/sd-bus/bus-objects.c:418 + #7 0x7fc8c9258830 in object_find_and_run src/libsystemd/sd-bus/bus-objects.c:1255 + #8 0x7fc8c92594d7 in bus_process_object src/libsystemd/sd-bus/bus-objects.c:1371 + #9 0x7fc8c91e7553 in process_message src/libsystemd/sd-bus/sd-bus.c:2563 + #10 0x7fc8c91e78ce in process_running src/libsystemd/sd-bus/sd-bus.c:2605 + #11 0x7fc8c91e8f61 in bus_process_internal src/libsystemd/sd-bus/sd-bus.c:2837 + #12 0x7fc8c91e90d2 in sd_bus_process src/libsystemd/sd-bus/sd-bus.c:2856 + #13 0x7fc8c91ea8f9 in io_callback src/libsystemd/sd-bus/sd-bus.c:3126 + #14 0x7fc8c928333b in source_dispatch src/libsystemd/sd-event/sd-event.c:2268 + #15 0x7fc8c9285cf7 in sd_event_dispatch src/libsystemd/sd-event/sd-event.c:2627 + #16 0x7fc8c92865fa in sd_event_run src/libsystemd/sd-event/sd-event.c:2686 + #17 0x55637c6b5257 in manager_loop src/core/manager.c:2274 + #18 0x55637c6a2194 in main src/core/main.c:1920 + #19 0x7fc8c7ac7400 in __libc_start_main (/lib64/libc.so.6+0x20400) + +previously allocated by thread T0 (systemd) here: + #0 0x7fc8c95b0160 in strdup (/lib64/libasan.so.3+0x5a160) + #1 0x7fc8c90edf32 in strv_extend src/basic/strv.c:552 + #2 0x7fc8c923ae41 in bus_message_read_strv_extend src/libsystemd/sd-bus/bus-message.c:5578 + #3 0x7fc8c923b0de in sd_bus_message_read_strv src/libsystemd/sd-bus/bus-message.c:5600 + #4 0x55637c7639d1 in method_enable_unit_files_generic src/core/dbus-manager.c:1969 + #5 0x55637c763d16 in method_link_unit_files src/core/dbus-manager.c:2001 + #6 0x7fc8c92537ec in method_callbacks_run src/libsystemd/sd-bus/bus-objects.c:418 + #7 0x7fc8c9258830 in object_find_and_run src/libsystemd/sd-bus/bus-objects.c:1255 + #8 0x7fc8c92594d7 in bus_process_object src/libsystemd/sd-bus/bus-objects.c:1371 + #9 0x7fc8c91e7553 in process_message src/libsystemd/sd-bus/sd-bus.c:2563 + #10 0x7fc8c91e78ce in process_running src/libsystemd/sd-bus/sd-bus.c:2605 + #11 0x7fc8c91e8f61 in bus_process_internal src/libsystemd/sd-bus/sd-bus.c:2837 + #12 0x7fc8c91e90d2 in sd_bus_process src/libsystemd/sd-bus/sd-bus.c:2856 + #13 0x7fc8c91ea8f9 in io_callback src/libsystemd/sd-bus/sd-bus.c:3126 + #14 0x7fc8c928333b in source_dispatch src/libsystemd/sd-event/sd-event.c:2268 + #15 0x7fc8c9285cf7 in sd_event_dispatch src/libsystemd/sd-event/sd-event.c:2627 + #16 0x7fc8c92865fa in sd_event_run src/libsystemd/sd-event/sd-event.c:2686 + #17 0x55637c6b5257 in manager_loop src/core/manager.c:2274 + #18 0x55637c6a2194 in main src/core/main.c:1920 + #19 0x7fc8c7ac7400 in __libc_start_main (/lib64/libc.so.6+0x20400) + +SUMMARY: AddressSanitizer: double-free (/lib64/libasan.so.3+0xc6b00) in free +==1==ABORTING +``` + +Closes #5015 + +(cherry picked from commit 8af35ba681116eb79a46e3dbd65b166c1efd6164) +Related: #1409997 +--- + src/shared/install.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 1b59a96b1..87d805c94 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1682,7 +1682,7 @@ int unit_file_link( + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_free_ char *config_path = NULL; +- _cleanup_free_ char **todo = NULL; ++ _cleanup_strv_free_ char **todo = NULL; + size_t n_todo = 0, n_allocated = 0; + char **i; + int r,q; +@@ -1736,7 +1736,11 @@ int unit_file_link( + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; + +- todo[n_todo++] = *i; ++ todo[n_todo] = strdup(*i); ++ if (!todo[n_todo]) ++ return -ENOMEM; ++ ++ n_todo++; + } + + strv_uniq(todo); diff --git a/SOURCES/0435-shared-check-strdup-NULL.patch b/SOURCES/0435-shared-check-strdup-NULL.patch new file mode 100644 index 00000000..4f0c1f6e --- /dev/null +++ b/SOURCES/0435-shared-check-strdup-NULL.patch @@ -0,0 +1,30 @@ +From eb591ab12405209edb498c9c57ddf76862c237c5 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Mon, 9 Jan 2017 22:45:41 +0000 +Subject: [PATCH] shared: check strdup != NULL + +This is a follow-up for dc7dd61de610e9330 + +(cherry picked from commit d054eae6c954baa857170bb60072c8a2ecea0d6b) +Related: #1409997 +--- + src/shared/install.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 87d805c94..62bdf674c 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1639,7 +1639,11 @@ int unit_file_unmask( + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; + +- todo[n_todo++] = strdup(*i); ++ todo[n_todo] = strdup(*i); ++ if (!todo[n_todo]) ++ return -ENOMEM; ++ ++ n_todo++; + } + + strv_uniq(todo); diff --git a/SOURCES/0436-core-improve-error-message-when-RefuseManualStart-St.patch b/SOURCES/0436-core-improve-error-message-when-RefuseManualStart-St.patch new file mode 100644 index 00000000..92689e71 --- /dev/null +++ b/SOURCES/0436-core-improve-error-message-when-RefuseManualStart-St.patch @@ -0,0 +1,39 @@ +From 92ff0ade63ae85c6b6170af7b1209aaf37298ab1 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 24 Jan 2017 04:06:05 +0100 +Subject: [PATCH] core: improve error message when RefuseManualStart(Stop) is + hit (#5132) + +(cherry picked from commit 7e974e8530e3605db8186bd0c33bf36087e24e22) +Resolves: #1026648 +--- + src/core/dbus-unit.c | 2 +- + src/core/dbus.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 89b00e94c..056a17ac1 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -843,7 +843,7 @@ int bus_unit_queue_job( + if ((type == JOB_START && u->refuse_manual_start) || + (type == JOB_STOP && u->refuse_manual_stop) || + ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) +- return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); ++ return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id); + + r = manager_add_job(u->manager, type, u, mode, true, error, &j); + if (r < 0) +diff --git a/src/core/dbus.c b/src/core/dbus.c +index 29524d49a..0061211fa 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -187,7 +187,7 @@ static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void + goto failed; + + if (u->refuse_manual_start) { +- r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id); ++ r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id); + goto failed; + } + diff --git a/SOURCES/0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch b/SOURCES/0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch new file mode 100644 index 00000000..219dd20a --- /dev/null +++ b/SOURCES/0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch @@ -0,0 +1,25 @@ +From e8507d683bce9dd61adc3fa5d19ec35e3caadff9 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Wed, 30 Nov 2016 18:27:42 +0100 +Subject: [PATCH] systemctl: fix 'is-enabled' exit status on failure when + executed in chroot (#4773) + +(cherry picked from commit c5024cd05c194b93ae960bf38e567d3d998f2a03) +Resolves: #1413964 +--- + src/systemctl/systemctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index a578897d9..1e1009f38 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -5739,7 +5739,7 @@ static int unit_is_enabled(sd_bus *bus, char **args) { + + r = unit_file_get_state(arg_scope, arg_root, *name, &state); + if (r < 0) +- return log_error_errno(state, "Failed to get unit file state for %s: %m", *name); ++ return log_error_errno(r, "Failed to get unit file state for %s: %m", *name); + + if (state == UNIT_FILE_ENABLED || + state == UNIT_FILE_ENABLED_RUNTIME || diff --git a/SOURCES/0438-man-document-that-the-automatic-journal-limits-are-c.patch b/SOURCES/0438-man-document-that-the-automatic-journal-limits-are-c.patch new file mode 100644 index 00000000..a934dc76 --- /dev/null +++ b/SOURCES/0438-man-document-that-the-automatic-journal-limits-are-c.patch @@ -0,0 +1,26 @@ +From 4464cd08f503af0459d779d92fb943aa3ef3f9a5 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sat, 3 Oct 2015 11:34:11 +0200 +Subject: [PATCH] man: document that the automatic journal limits are capped to + 4G by default + +(cherry picked from commit 32252660954804747ae6b64c3921d5cb9a1c09c9) +Resolves: #1418547 +--- + man/journald.conf.xml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/man/journald.conf.xml b/man/journald.conf.xml +index c4f71e887..46a498b67 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -210,7 +210,8 @@ + and use the smaller of the two values. + + The first pair defaults to 10% and the second to 15% of +- the size of the respective file system. If the file system is ++ the size of the respective file system, but each value ++ is capped to 4G. If the file system is + nearly full and either SystemKeepFree= or + RuntimeKeepFree= is violated when + systemd-journald is started, the value will be raised to diff --git a/SOURCES/0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch b/SOURCES/0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch new file mode 100644 index 00000000..9c9e233a --- /dev/null +++ b/SOURCES/0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch @@ -0,0 +1,23 @@ +From 6a4ea99f07b32659362c9a1a38be8bec2bb0964c Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 25 Jan 2017 08:39:15 +0100 +Subject: [PATCH] random-seed: raise POOL_SIZE_MIN to 1024 + +Resolves: #1386824 +--- + src/random-seed/random-seed.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c +index ce1bd195d..3ccc8f681 100644 +--- a/src/random-seed/random-seed.c ++++ b/src/random-seed/random-seed.c +@@ -29,7 +29,7 @@ + #include "util.h" + #include "mkdir.h" + +-#define POOL_SIZE_MIN 512 ++#define POOL_SIZE_MIN 1024 + + int main(int argc, char *argv[]) { + _cleanup_close_ int seed_fd = -1, random_fd = -1; diff --git a/SOURCES/0440-bash-completion-add-support-for-now-5155.patch b/SOURCES/0440-bash-completion-add-support-for-now-5155.patch new file mode 100644 index 00000000..2f263073 --- /dev/null +++ b/SOURCES/0440-bash-completion-add-support-for-now-5155.patch @@ -0,0 +1,24 @@ +From 88cc61d44a1567fd81e073defa01fc351051fec5 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 25 Jan 2017 13:44:04 +0100 +Subject: [PATCH] bash-completion: add support for --now (#5155) + +(cherry picked from commit 0067c7b29ab996bf99cf1bafe63c118b9b6d5b56) +Resolves: #1351806 +--- + shell-completion/bash/systemctl.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in +index 0a022c4cf..a1dde32c3 100644 +--- a/shell-completion/bash/systemctl.in ++++ b/shell-completion/bash/systemctl.in +@@ -91,7 +91,7 @@ _systemctl () { + + local -A OPTS=( + [STANDALONE]='--all -a --reverse --after --before --defaults --fail --ignore-dependencies --failed --force -f --full -l --global +- --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall ++ --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall --now + --quiet -q --privileged -P --system --version --runtime --recursive -r' + [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --root' + ) diff --git a/SOURCES/0441-basic-fix-touch-creating-files-with-07777-mode.patch b/SOURCES/0441-basic-fix-touch-creating-files-with-07777-mode.patch new file mode 100644 index 00000000..0f89cadc --- /dev/null +++ b/SOURCES/0441-basic-fix-touch-creating-files-with-07777-mode.patch @@ -0,0 +1,30 @@ +From 616db6ddcacd25e4c3a771cd317373971c9055ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mantas=20Mikul=C4=97nas?= +Date: Fri, 29 Jan 2016 23:36:08 +0200 +Subject: [PATCH] basic: fix touch() creating files with 07777 mode + +mode_t is unsigned, so MODE_INVALID < 0 can never be true. + +This fixes a possible DoS where any user could fill /run by writing to +a world-writable /run/systemd/show-status. + +Cherry-picked from: 06eeacb6fe029804f296b065b3ce91e796e1cd0e +Resolves: #1416062 +--- + src/shared/util.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 66729f70e..1070e32c4 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3908,7 +3908,8 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi + if (parents) + mkdir_parents(path, 0755); + +- fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); ++ fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, ++ (mode == 0 || mode == MODE_INVALID) ? 0644 : mode); + if (fd < 0) + return -errno; + diff --git a/SOURCES/0442-udev-net_id-add-support-for-phys_port_name-attribute.patch b/SOURCES/0442-udev-net_id-add-support-for-phys_port_name-attribute.patch new file mode 100644 index 00000000..5b951cc4 --- /dev/null +++ b/SOURCES/0442-udev-net_id-add-support-for-phys_port_name-attribute.patch @@ -0,0 +1,97 @@ +From 192545bc67fed763ac54761ca067b9c2f93ecdd1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ji=C5=99=C3=AD=20P=C3=ADrko?= +Date: Wed, 2 Nov 2016 03:46:01 +0100 +Subject: [PATCH] udev: net_id: add support for phys_port_name attribute + (#4506) + +Switch drivers uses phys_port_name attribute to pass front panel port +name to user. Use it to generate netdev names. + +Signed-off-by: Jiri Pirko + +Cherry-picked from: 4887b656c22af059d4e833de7b56544f24951184 +Resolves: #1392426 +--- + src/udev/udev-builtin-net_id.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 19e1f2631..7c154355d 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][d/] ++ * [P]ps[f][n|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; ++ const char *attr, *port_name; + int idx; + + /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ +@@ -161,10 +161,15 @@ 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 (dev_port > 0) ++ if (port_name) ++ l = strpcpyf(&s, l, "n%s", port_name); ++ else if (dev_port > 0) + l = strpcpyf(&s, l, "d%d", dev_port); + if (l == 0) + names->pci_onboard[0] = '\0'; +@@ -199,7 +204,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; ++ const char *attr, *port_name; + struct udev_device *pci = NULL; + char slots[256], str[256]; + _cleanup_closedir_ DIR *dir = NULL; +@@ -220,6 +225,9 @@ 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); +@@ -228,7 +236,9 @@ 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 (dev_id > 0) ++ if (port_name) ++ l = strpcpyf(&s, l, "n%s", port_name); ++ else if (dev_id > 0) + l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_path[0] = '\0'; +@@ -278,7 +288,9 @@ 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 (dev_id > 0) ++ if (port_name) ++ l = strpcpyf(&s, l, "n%s", port_name); ++ else if (dev_id > 0) + l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_slot[0] = '\0'; diff --git a/SOURCES/0443-install-introduce-UnitFileFlags.patch b/SOURCES/0443-install-introduce-UnitFileFlags.patch new file mode 100644 index 00000000..8123106c --- /dev/null +++ b/SOURCES/0443-install-introduce-UnitFileFlags.patch @@ -0,0 +1,988 @@ +From 111080b06c79e6bcbe9da4786f9c7229f1fb573e Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 20 Oct 2016 14:48:33 +0200 +Subject: [PATCH] install: introduce UnitFileFlags + +Introduce a new enum to get rid of some boolean arguments of unit_file_* +functions. It unifies the code, makes it a bit cleaner and extensible. + +(cherry picked from commit b3796dd8349af4235143889e44522a730c1635c0) +Related: #1413041 +--- + src/core/dbus-manager.c | 36 ++++++++++++++++++-------- + src/core/main.c | 2 +- + src/shared/install.c | 61 ++++++++++++++++++++------------------------ + src/shared/install.h | 25 ++++++++++-------- + src/systemctl/systemctl.c | 28 ++++++++++++-------- + src/test/test-install-root.c | 58 ++++++++++++++++++++--------------------- + src/test/test-install.c | 38 +++++++++++++-------------- + 7 files changed, 135 insertions(+), 113 deletions(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index c2067c099..5b40aa20f 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -41,6 +41,11 @@ + #include "dbus-execute.h" + #include "bus-common-errors.h" + ++static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) { ++ return (runtime ? UNIT_FILE_RUNTIME : 0) | ++ (force ? UNIT_FILE_FORCE : 0); ++} ++ + static int property_get_version( + sd_bus *bus, + const char *path, +@@ -1647,7 +1652,7 @@ static int method_enable_unit_files_generic( + sd_bus_message *message, + Manager *m, + const char *verb, +- int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes), ++ int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), + bool carries_install_info, + sd_bus_error *error) { + +@@ -1655,6 +1660,7 @@ static int method_enable_unit_files_generic( + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileScope scope; ++ UnitFileFlags flags; + int runtime, force, r; + + assert(bus); +@@ -1676,12 +1682,13 @@ static int method_enable_unit_files_generic( + return r; + + r = mac_selinux_unit_access_check_strv(l, message, m, verb, error); ++ flags = unit_file_bools_to_flags(runtime, force); + if (r < 0) + return r; + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- r = call(scope, runtime, NULL, l, force, &changes, &n_changes); ++ r = call(scope, flags, NULL, l, &changes, &n_changes); + if (r < 0) + return r; + +@@ -1700,8 +1707,8 @@ static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *us + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false, error); + } + +-static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) { +- return unit_file_preset(scope, runtime, root_dir, files, UNIT_FILE_PRESET_FULL, force, changes, n_changes); ++static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes) { ++ return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes); + } + + static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { +@@ -1721,6 +1728,7 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa + UnitFilePresetMode mm; + UnitFileScope scope; + int runtime, force, r; ++ UnitFileFlags flags; + const char *mode; + + assert(bus); +@@ -1741,6 +1749,8 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa + if (r < 0) + return r; + ++ flags = unit_file_bools_to_flags(runtime, force); ++ + if (isempty(mode)) + mm = UNIT_FILE_PRESET_FULL; + else { +@@ -1755,7 +1765,7 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes); ++ r = unit_file_preset(scope, flags, NULL, l, mm, &changes, &n_changes); + if (r < 0) + return r; + +@@ -1767,7 +1777,7 @@ static int method_disable_unit_files_generic( + sd_bus_message *message, + Manager *m, const + char *verb, +- int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), ++ int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), + sd_bus_error *error) { + + _cleanup_strv_free_ char **l = NULL; +@@ -1800,7 +1810,7 @@ static int method_disable_unit_files_generic( + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- r = call(scope, runtime, NULL, l, &changes, &n_changes); ++ r = call(scope, runtime ? UNIT_FILE_RUNTIME : 0, NULL, l, &changes, &n_changes); + if (r < 0) + return r; + +@@ -1843,7 +1853,7 @@ static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes); ++ r = unit_file_set_default(scope, force ? UNIT_FILE_FORCE : 0, NULL, name, &changes, &n_changes); + if (r < 0) + return r; + +@@ -1857,6 +1867,7 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo + UnitFilePresetMode mm; + UnitFileScope scope; + const char *mode; ++ UnitFileFlags flags; + int force, runtime, r; + + assert(bus); +@@ -1877,6 +1888,8 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo + if (r < 0) + return r; + ++ flags = unit_file_bools_to_flags(runtime, force); ++ + if (isempty(mode)) + mm = UNIT_FILE_PRESET_FULL; + else { +@@ -1887,7 +1900,7 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes); ++ r = unit_file_preset_all(scope, flags, NULL, mm, &changes, &n_changes); + if (r < 0) { + unit_file_changes_free(changes, n_changes); + return r; +@@ -1906,6 +1919,7 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message + char *target; + char *type; + UnitDependency dep; ++ UnitFileFlags flags; + + assert(bus); + assert(message); +@@ -1925,6 +1939,8 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message + if (r < 0) + return r; + ++ flags = unit_file_bools_to_flags(runtime, force); ++ + dep = unit_dependency_from_string(type); + if (dep < 0) + return -EINVAL; +@@ -1935,7 +1951,7 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); ++ r = unit_file_add_dependency(scope, flags, NULL, l, target, dep, &changes, &n_changes); + if (r < 0) + return r; + +diff --git a/src/core/main.c b/src/core/main.c +index 820cbc3e5..a0df1e5ce 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1658,7 +1658,7 @@ int main(int argc, char *argv[]) { + bump_rlimit_nofile(&saved_rlimit_nofile); + + if (empty_etc) { +- r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_FULL, false, NULL, 0); ++ r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_FULL, NULL, 0); + if (r < 0) + log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m"); + else +diff --git a/src/shared/install.c b/src/shared/install.c +index 62bdf674c..b3df6b35c 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1549,10 +1549,9 @@ static int install_context_mark_for_removal( + + int unit_file_mask( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -1567,7 +1566,7 @@ int unit_file_mask( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &prefix); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &prefix); + if (r < 0) + return r; + +@@ -1584,7 +1583,7 @@ int unit_file_mask( + if (!path) + return -ENOMEM; + +- q = create_symlink("/dev/null", path, force, changes, n_changes); ++ q = create_symlink("/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + if (q < 0 && r >= 0) + r = q; + } +@@ -1594,7 +1593,7 @@ int unit_file_mask( + + int unit_file_unmask( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, +@@ -1614,7 +1613,7 @@ int unit_file_unmask( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &config_path); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path); + if (r < 0) + return r; + +@@ -1677,10 +1676,9 @@ int unit_file_unmask( + + int unit_file_link( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -1702,7 +1700,7 @@ int unit_file_link( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &config_path); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path); + if (r < 0) + return r; + +@@ -1757,7 +1755,7 @@ int unit_file_link( + if (!path) + return -ENOMEM; + +- q = create_symlink(*i, path, force, changes, n_changes); ++ q = create_symlink(*i, path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + if (q < 0 && r >= 0) + r = q; + } +@@ -1767,12 +1765,11 @@ int unit_file_link( + + int unit_file_add_dependency( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, + const char *target, + UnitDependency dep, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -1801,7 +1798,7 @@ int unit_file_add_dependency( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &config_path); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path); + if (r < 0) + return r; + +@@ -1839,16 +1836,15 @@ int unit_file_add_dependency( + return -ENOMEM; + } + +- return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); ++ return install_context_apply(scope, &c, &paths, config_path, root_dir, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + } + + + int unit_file_enable( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -1870,7 +1866,7 @@ int unit_file_enable( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &config_path); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path); + if (r < 0) + return r; + +@@ -1889,12 +1885,12 @@ int unit_file_enable( + useful to determine whether the passed files had any + installation data at all. */ + +- return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); ++ return install_context_apply(scope, &c, &paths, config_path, root_dir, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes); + } + + int unit_file_disable( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFileChange **changes, +@@ -1918,7 +1914,7 @@ int unit_file_disable( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &config_path); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path); + if (r < 0) + return r; + +@@ -1940,10 +1936,9 @@ int unit_file_disable( + + int unit_file_reenable( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -1958,19 +1953,19 @@ int unit_file_reenable( + n[i] = basename(files[i]); + n[i] = NULL; + +- r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes); ++ r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes); + if (r < 0) + return r; + + /* But the enable command with the full name */ +- return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes); ++ return unit_file_enable(scope, flags, root_dir, files, changes, n_changes); + } + + int unit_file_set_default( + UnitFileScope scope, ++ UnitFileFlags flags, + const char *root_dir, + const char *name, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -2010,7 +2005,7 @@ int unit_file_set_default( + + path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET); + +- return create_symlink(i->path, path, force, changes, n_changes); ++ return create_symlink(i->path, path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + } + + int unit_file_get_default( +@@ -2311,11 +2306,10 @@ static int preset_prepare_one( + + int unit_file_preset( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + char **files, + UnitFilePresetMode mode, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -2337,7 +2331,7 @@ int unit_file_preset( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &config_path); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path); + if (r < 0) + return r; + +@@ -2350,15 +2344,14 @@ int unit_file_preset( + return r; + } + +- return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes); ++ return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + } + + int unit_file_preset_all( + UnitFileScope scope, +- bool runtime, ++ UnitFileFlags flags, + const char *root_dir, + UnitFilePresetMode mode, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -2380,7 +2373,7 @@ int unit_file_preset_all( + if (r < 0) + return r; + +- r = get_config_path(scope, runtime, root_dir, &config_path); ++ r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path); + if (r < 0) + return r; + +@@ -2434,7 +2427,7 @@ int unit_file_preset_all( + } + } + +- return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes); ++ return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); + } + + static void unit_file_list_free_one(UnitFileList *f) { +diff --git a/src/shared/install.h b/src/shared/install.h +index 7e40445d3..c961b53d0 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -66,6 +66,11 @@ typedef enum UnitFileChangeType { + _UNIT_FILE_CHANGE_TYPE_INVALID = -1 + } UnitFileChangeType; + ++typedef enum UnitFileFlags { ++ UNIT_FILE_RUNTIME = 1, ++ UNIT_FILE_FORCE = 1 << 1 ++} UnitFileFlags; ++ + static inline bool unit_file_change_is_modification(UnitFileChangeType type) { + return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK); + } +@@ -120,17 +125,17 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(InstallInfo *i) { + return !strv_isempty(i->also); + } + +-int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); +-int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_enable(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_disable(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_reenable(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_link(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_preset(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFilePresetMode mode, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_preset_all(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, UnitFilePresetMode mode, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_mask(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_unmask(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_set_default(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, const char *file, UnitFileChange **changes, unsigned *n_changes); + int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name); +-int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); ++int unit_file_add_dependency(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, const char *target, UnitDependency dep, UnitFileChange **changes, unsigned *n_changes); + + int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret); + int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 1e1009f38..e0dbf0fda 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -165,6 +165,11 @@ static int daemon_reload(sd_bus *bus, char **args); + static int halt_now(enum action a); + static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet); + ++static UnitFileFlags args_to_flags(void) { ++ return (arg_runtime ? UNIT_FILE_RUNTIME : 0) | ++ (arg_force ? UNIT_FILE_FORCE : 0); ++} ++ + static char** strv_skip_first(char **strv) { + if (strv_length(strv) > 0) + return strv + 1; +@@ -1974,7 +1979,7 @@ static int set_default(sd_bus *bus, char **args) { + return log_oom(); + + if (!bus || avoid_bus()) { +- r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); ++ r = unit_file_set_default(arg_scope, UNIT_FILE_FORCE, arg_root, unit, &changes, &n_changes); + if (r < 0) + return log_error_errno(r, "Failed to set default target: %m"); + +@@ -5407,22 +5412,25 @@ static int enable_unit(sd_bus *bus, char **args) { + } + + if (!bus || avoid_bus()) { ++ UnitFileFlags flags; ++ ++ flags = args_to_flags(); + if (streq(verb, "enable")) { +- r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); ++ r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes); + carries_install_info = r; + } else if (streq(verb, "disable")) +- r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes); ++ r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes); + else if (streq(verb, "reenable")) { +- r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); ++ r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes); + carries_install_info = r; + } else if (streq(verb, "link")) +- r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); ++ r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes); + else if (streq(verb, "preset")) { +- r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes); ++ r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes); + } else if (streq(verb, "mask")) +- r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); ++ r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes); + else if (streq(verb, "unmask")) +- r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes); ++ r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes); + else + assert_not_reached("Unknown verb"); + +@@ -5588,7 +5596,7 @@ static int add_dependency(sd_bus *bus, char **args) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + +- r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); ++ r = unit_file_add_dependency(arg_scope, args_to_flags(), arg_root, names, target, dep, &changes, &n_changes); + + if (r < 0) + return log_error_errno(r, "Can't add dependency: %m"); +@@ -5652,7 +5660,7 @@ static int preset_all(sd_bus *bus, char **args) { + + if (!bus || avoid_bus()) { + +- r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); ++ r = unit_file_preset_all(arg_scope, args_to_flags(), arg_root, arg_preset_mode, &changes, &n_changes); + if (r < 0) { + log_error_errno(r, "Operation failed: %m"); + goto finish; +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index 667c3748c..cb417d4c1 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -62,7 +62,7 @@ static void test_basic_mask_and_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/dev/null")); +@@ -78,11 +78,11 @@ static void test_basic_mask_and_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + /* Enabling a masked unit should fail! */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ESHUTDOWN); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); +@@ -90,7 +90,7 @@ static void test_basic_mask_and_enable(const char *root) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); +@@ -105,12 +105,12 @@ static void test_basic_mask_and_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* Enabling it again should succeed but be a NOP */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); +@@ -124,13 +124,13 @@ static void test_basic_mask_and_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + /* Disabling a disabled unit must suceed but be a NOP */ +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + /* Let's enable this indirectly via a symlink */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); +@@ -146,7 +146,7 @@ static void test_basic_mask_and_enable(const char *root) { + + /* Let's try to reenable */ + +- assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); +@@ -215,7 +215,7 @@ static void test_linked_units(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* First, let's link the unit into the search path */ +- assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/opt/linked.service")); +@@ -227,7 +227,7 @@ static void test_linked_units(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* Let's unlink it from the search path again */ +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); +@@ -238,7 +238,7 @@ static void test_linked_units(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + + /* Now, let's not just link it, but also enable it */ +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); +@@ -260,7 +260,7 @@ static void test_linked_units(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* And let's unlink it again */ +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); +@@ -280,7 +280,7 @@ static void test_linked_units(const char *root) { + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service"); +@@ -299,7 +299,7 @@ static void test_linked_units(const char *root) { + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) == -ELOOP); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + } +@@ -318,14 +318,14 @@ static void test_default(const char *root) { + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + +- assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT); ++ assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + +- assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); +@@ -355,7 +355,7 @@ static void test_add_dependency(const char *root) { + p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); + assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); + +- assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); +@@ -392,7 +392,7 @@ static void test_template_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); +@@ -408,7 +408,7 @@ static void test_template_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); +@@ -422,7 +422,7 @@ static void test_template_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service"); +@@ -437,7 +437,7 @@ static void test_template_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); +@@ -453,7 +453,7 @@ static void test_template_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service"); +@@ -498,7 +498,7 @@ static void test_indirect(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + +- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); +@@ -511,7 +511,7 @@ static void test_indirect(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); +@@ -551,7 +551,7 @@ static void test_preset_and_list(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); +@@ -563,7 +563,7 @@ static void test_preset_and_list(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); +@@ -574,7 +574,7 @@ static void test_preset_and_list(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +@@ -582,7 +582,7 @@ static void test_preset_and_list(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + +- assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); + + assert_se(n_changes > 0); + +diff --git a/src/test/test-install.c b/src/test/test-install.c +index 08a1faf2c..0cae0e794 100644 +--- a/src/test/test-install.c ++++ b/src/test/test-install.c +@@ -73,12 +73,12 @@ int main(int argc, char* argv[]) { + + log_error("enable"); + +- r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); ++ r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + log_error("enable2"); + +- r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); ++ r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -93,7 +93,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -107,10 +107,10 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); ++ r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_error("mask2"); +- r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); ++ r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -124,10 +124,10 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_error("unmask2"); +- r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -141,7 +141,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); ++ r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -155,10 +155,10 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_error("disable2"); +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -172,7 +172,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); ++ r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -186,7 +186,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); ++ r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -200,7 +200,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -213,7 +213,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); ++ r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -227,7 +227,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -240,7 +240,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); ++ r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -254,7 +254,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_reenable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); ++ r = unit_file_reenable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -268,7 +268,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); +@@ -280,7 +280,7 @@ int main(int argc, char* argv[]) { + changes = NULL; + n_changes = 0; + +- r = unit_file_preset(UNIT_FILE_SYSTEM, false, NULL, (char**) files, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes); ++ r = unit_file_preset(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); diff --git a/SOURCES/0444-shared-systemctl-teach-is-enabled-to-show-installati.patch b/SOURCES/0444-shared-systemctl-teach-is-enabled-to-show-installati.patch new file mode 100644 index 00000000..e33c4e16 --- /dev/null +++ b/SOURCES/0444-shared-systemctl-teach-is-enabled-to-show-installati.patch @@ -0,0 +1,363 @@ +From fef4e6a045ae703de12ec271b0c8fd02d0bac0fc Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 20 Oct 2016 15:20:11 +0200 +Subject: [PATCH] shared, systemctl: teach is-enabled to show installation + targets + +It may be desired by users to know what targets a particular service is +installed into. Improve user friendliness by teaching the is-enabled +command to show such information when used with --full. + +This patch makes use of the newly added UnitFileFlags and adds +UNIT_FILE_DRY_RUN flag into it. Since the API had already been modified, +it's now easy to add the new dry-run feature for other commands as +well. As a next step, --dry-run could be added to systemctl, which in +turn might pave the way for a long requested dry-run feature when +running systemctl start. + +(cherry picked from commit 3b3557c410c7910fae0990599dcb82711cf5fbb7) +Resolves: #1413041 +--- + man/systemctl.xml | 3 ++ + src/core/dbus-manager.c | 44 ++++++++++++++++++++ + src/core/org.freedesktop.systemd1.conf | 4 ++ + src/shared/install.c | 35 +++++++++------- + src/shared/install.h | 3 +- + src/systemctl/systemctl.c | 73 +++++++++++++++++++++++++++++++++- + 6 files changed, 145 insertions(+), 17 deletions(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index bb21f3a88..4a1aff227 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -223,6 +223,8 @@ + of status, list-units, + list-jobs, and + list-timers. ++ Also, show installation targets in the output of ++ is-enabled. + + + +@@ -1054,6 +1056,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + exit code of 0 if at least one is enabled, non-zero + otherwise. Prints the current enable status (see table). + To suppress this output, use . ++ To show installation targets, use . + + + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 5b40aa20f..7ba1b519e 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1958,6 +1958,49 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message + return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes); + } + ++static int method_get_unit_file_links(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { ++ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0, i; ++ UnitFileFlags flags; ++ const char *name; ++ char **p; ++ int runtime, r; ++ ++ r = sd_bus_message_read(message, "sb", &name, &runtime); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_new_method_return(message, &reply); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_open_container(reply, SD_BUS_TYPE_ARRAY, "s"); ++ if (r < 0) ++ return r; ++ ++ p = STRV_MAKE(name); ++ flags = UNIT_FILE_DRY_RUN | ++ (runtime ? UNIT_FILE_RUNTIME : 0); ++ ++ r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get file links for %s: %m", name); ++ ++ for (i = 0; i < n_changes; i++) ++ if (changes[i].type == UNIT_FILE_UNLINK) { ++ r = sd_bus_message_append(reply, "s", changes[i].path); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_bus_message_close_container(reply); ++ if (r < 0) ++ return r; ++ ++ return sd_bus_send(bus, reply, NULL); ++} ++ + const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_VTABLE_START(0), + +@@ -2049,6 +2092,7 @@ const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("GetUnitFileLinks", "sb", "as", method_get_unit_file_links, SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_SIGNAL("UnitNew", "so", 0), + SD_BUS_SIGNAL("UnitRemoved", "so", 0), +diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf +index 6a7a37ee9..3997dd0b4 100644 +--- a/src/core/org.freedesktop.systemd1.conf ++++ b/src/core/org.freedesktop.systemd1.conf +@@ -76,6 +76,10 @@ + send_interface="org.freedesktop.systemd1.Manager" + send_member="GetUnitFileState"/> + ++ ++ + +diff --git a/src/shared/install.c b/src/shared/install.c +index b3df6b35c..bdfd7b96a 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -340,6 +340,7 @@ static int remove_marked_symlinks_fd( + int fd, + const char *path, + const char *config_path, ++ bool dry_run, + bool *restart, + UnitFileChange **changes, + unsigned *n_changes) { +@@ -400,7 +401,7 @@ static int remove_marked_symlinks_fd( + } + + /* This will close nfd, regardless whether it succeeds or not */ +- q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes); ++ q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, dry_run, restart, changes, n_changes); + if (q < 0 && r == 0) + r = q; + +@@ -439,21 +440,23 @@ static int remove_marked_symlinks_fd( + if (!found) + continue; + +- if (unlink(p) < 0 && errno != ENOENT) { +- if (r == 0) +- r = -errno; +- continue; +- } ++ if (!dry_run) { ++ if (unlink(p) < 0 && errno != ENOENT) { ++ if (r == 0) ++ r = -errno; ++ continue; ++ } + +- path_kill_slashes(p); +- (void) rmdir_parents(p, config_path); ++ path_kill_slashes(p); ++ (void) rmdir_parents(p, config_path); ++ } + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); + + q = mark_symlink_for_removal(&remove_symlinks_to, p); + if (q < 0) + return q; +- if (q > 0) ++ if (q > 0 && !dry_run) + *restart = true; + } + } +@@ -464,6 +467,7 @@ static int remove_marked_symlinks_fd( + static int remove_marked_symlinks( + Set *remove_symlinks_to, + const char *config_path, ++ bool dry_run, + UnitFileChange **changes, + unsigned *n_changes) { + +@@ -491,7 +495,7 @@ static int remove_marked_symlinks( + } + + /* This takes possession of cfd and closes it */ +- q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes); ++ q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, dry_run, &restart, changes, n_changes); + if (r == 0) + r = q; + } while (restart); +@@ -1604,6 +1608,7 @@ int unit_file_unmask( + _cleanup_strv_free_ char **todo = NULL; + size_t n_todo = 0, n_allocated = 0; + char **i; ++ bool dry_run; + int r, q; + + assert(scope >= 0); +@@ -1617,6 +1622,8 @@ int unit_file_unmask( + if (r < 0) + return r; + ++ dry_run = !!(flags & UNIT_FILE_DRY_RUN); ++ + STRV_FOREACH(i, files) { + _cleanup_free_ char *path = NULL; + +@@ -1655,7 +1662,7 @@ int unit_file_unmask( + if (!path) + return -ENOMEM; + +- if (unlink(path) < 0) { ++ if (!dry_run && unlink(path) < 0) { + if (errno != -ENOENT && r >= 0) + r = -errno; + } else { +@@ -1667,7 +1674,7 @@ int unit_file_unmask( + } + } + +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); ++ q = remove_marked_symlinks(remove_symlinks_to, config_path, dry_run, changes, n_changes); + if (r >= 0) + r = q; + +@@ -1931,7 +1938,7 @@ int unit_file_disable( + if (r < 0) + return r; + +- return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); ++ return remove_marked_symlinks(remove_symlinks_to, config_path, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes); + } + + int unit_file_reenable( +@@ -2243,7 +2250,7 @@ static int execute_preset( + if (r < 0) + return r; + +- r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); ++ r = remove_marked_symlinks(remove_symlinks_to, config_path, false, changes, n_changes); + } else + r = 0; + +diff --git a/src/shared/install.h b/src/shared/install.h +index c961b53d0..c236dcfd8 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -68,7 +68,8 @@ typedef enum UnitFileChangeType { + + typedef enum UnitFileFlags { + UNIT_FILE_RUNTIME = 1, +- UNIT_FILE_FORCE = 1 << 1 ++ UNIT_FILE_FORCE = 1 << 1, ++ UNIT_FILE_DRY_RUN = 1 << 2 + } UnitFileFlags; + + static inline bool unit_file_change_is_modification(UnitFileChangeType type) { +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index e0dbf0fda..ff8b4e978 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -5722,6 +5722,63 @@ finish: + return r; + } + ++static int show_installation_targets_client_side(const char *name) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0, i; ++ UnitFileFlags flags; ++ char **p; ++ int r; ++ ++ p = STRV_MAKE(name); ++ flags = UNIT_FILE_DRY_RUN | ++ (arg_runtime ? UNIT_FILE_RUNTIME : 0); ++ ++ r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get file links for %s: %m", name); ++ ++ for (i = 0; i < n_changes; i++) ++ if (changes[i].type == UNIT_FILE_UNLINK) ++ printf(" %s\n", changes[i].path); ++ ++ return 0; ++} ++ ++static int show_installation_targets(sd_bus *bus, const char *name) { ++ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; ++ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; ++ const char *link; ++ int r; ++ ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ "GetUnitFileLinks", ++ &error, ++ &reply, ++ "sb", name, arg_runtime); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r)); ++ ++ r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s"); ++ if (r < 0) ++ return bus_log_parse_error(r); ++ ++ while ((r = sd_bus_message_read(reply, "s", &link)) > 0) ++ printf(" %s\n", link); ++ ++ if (r < 0) ++ return bus_log_parse_error(r); ++ ++ r = sd_bus_message_exit_container(reply); ++ if (r < 0) ++ return bus_log_parse_error(r); ++ ++ return 0; ++} ++ + static int unit_is_enabled(sd_bus *bus, char **args) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +@@ -5755,8 +5812,14 @@ static int unit_is_enabled(sd_bus *bus, char **args) { + state == UNIT_FILE_INDIRECT) + enabled = true; + +- if (!arg_quiet) ++ if (!arg_quiet) { + puts(unit_file_state_to_string(state)); ++ if (arg_full) { ++ r = show_installation_targets_client_side(*name); ++ if (r < 0) ++ return r; ++ } ++ } + } + + } else { +@@ -5785,8 +5848,14 @@ static int unit_is_enabled(sd_bus *bus, char **args) { + if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect")) + enabled = true; + +- if (!arg_quiet) ++ if (!arg_quiet) { + puts(s); ++ if (arg_full) { ++ r = show_installation_targets(bus, *name); ++ if (r < 0) ++ return r; ++ } ++ } + } + } + diff --git a/SOURCES/0445-udev-fix-crash-with-invalid-udev.log-priority.patch b/SOURCES/0445-udev-fix-crash-with-invalid-udev.log-priority.patch new file mode 100644 index 00000000..0aaf4a96 --- /dev/null +++ b/SOURCES/0445-udev-fix-crash-with-invalid-udev.log-priority.patch @@ -0,0 +1,32 @@ +From 22423054480ed8dee70160e9e886ca372b3440f3 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Tue, 21 Jul 2015 18:26:09 +0200 +Subject: [PATCH] udev: fix crash with invalid udev.log-priority + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1245293 + +Conflicts: + src/udev/udevd.c + +Cherry-picked from: e00f5bddde0daff900cbd93e1ee0530ad1ae06ce +Resolves: #1245293 +--- + src/udev/udevd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 21e7e7f9a..82c7a5425 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -990,7 +990,10 @@ static void kernel_cmdline_options(struct udev *udev) { + int prio; + + prio = util_log_priority(value); +- log_set_max_level(prio); ++ if (prio < 0) ++ log_warning("Invalid udev.log-priority ignored: %s", value); ++ else ++ log_set_max_level(prio); + } else if ((value = startswith(opt, "udev.children-max="))) { + r = safe_atoi(value, &arg_children_max); + if (r < 0) diff --git a/SOURCES/0446-core-make-exec-code-a-bit-more-readable.patch b/SOURCES/0446-core-make-exec-code-a-bit-more-readable.patch new file mode 100644 index 00000000..0a685cdb --- /dev/null +++ b/SOURCES/0446-core-make-exec-code-a-bit-more-readable.patch @@ -0,0 +1,73 @@ +From ccf46ebc548054f876a418fc2e949a05a74a9c2a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 13 May 2015 16:34:02 +0200 +Subject: [PATCH] core: make exec code a bit more readable + +Let's add a function that checks whether we need fs namespacing, to make +things easier to read, instead of using a humungous if expression... + +Cherry-picked from: 8b44a3d22c1fdfc5ce5fcb77e38a90ec02ba8019 +Related: #1421181 +--- + src/core/execute.c | 41 +++++++++++++++++++++++++++++++---------- + 1 file changed, 31 insertions(+), 10 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index e9b4359a7..59340ec05 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1256,6 +1256,36 @@ static int build_environment( + return 0; + } + ++static bool exec_needs_mount_namespace( ++ const ExecContext *context, ++ const ExecParameters *params, ++ ExecRuntime *runtime) { ++ ++ assert(context); ++ assert(params); ++ ++ if (!strv_isempty(context->read_write_dirs) || ++ !strv_isempty(context->read_only_dirs) || ++ !strv_isempty(context->inaccessible_dirs)) ++ return true; ++ ++ if (context->mount_flags != 0) ++ return true; ++ ++ if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) ++ return true; ++ ++ if (params->bus_endpoint_path) ++ return true; ++ ++ if (context->private_devices || ++ context->protect_system != PROTECT_SYSTEM_NO || ++ context->protect_home != PROTECT_HOME_NO) ++ return true; ++ ++ return false; ++} ++ + static int exec_child( + ExecCommand *command, + const ExecContext *context, +@@ -1563,16 +1593,7 @@ static int exec_child( + } + } + +- if (!strv_isempty(context->read_write_dirs) || +- !strv_isempty(context->read_only_dirs) || +- !strv_isempty(context->inaccessible_dirs) || +- context->mount_flags != 0 || +- (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) || +- params->bus_endpoint_path || +- context->private_devices || +- context->protect_system != PROTECT_SYSTEM_NO || +- context->protect_home != PROTECT_HOME_NO) { +- ++ if (exec_needs_mount_namespace(context, params, runtime)) { + char *tmp = NULL, *var = NULL; + + /* The runtime struct only contains the parent diff --git a/SOURCES/0447-core-Private-Protect-options-with-RootDirectory.patch b/SOURCES/0447-core-Private-Protect-options-with-RootDirectory.patch new file mode 100644 index 00000000..9ac4d3c4 --- /dev/null +++ b/SOURCES/0447-core-Private-Protect-options-with-RootDirectory.patch @@ -0,0 +1,295 @@ +From 2b4894764e9e92ae9004524ed466b4bdf94b2a34 Mon Sep 17 00:00:00 2001 +From: Alban Crequy +Date: Mon, 18 May 2015 12:20:28 +0200 +Subject: [PATCH] core: Private*/Protect* options with RootDirectory + +When a service is chrooted with the option RootDirectory=/opt/..., then +the options PrivateDevices, PrivateTmp, ProtectHome, ProtectSystem must +mount the directories under $RootDirectory/{dev,tmp,home,usr,boot}. + +The test-ns tool can test setup_namespace() with and without chroot: + $ sudo TEST_NS_PROJECTS=/home/lennart/projects ./test-ns + $ sudo TEST_NS_CHROOT=/home/alban/debian-tree TEST_NS_PROJECTS=/home/alban/debian-tree/home/alban/Documents ./test-ns + +Cherry-picked from: ee818b89f4890b3a00e93772249fce810f60811e +Resolves: #1421181 +--- + src/core/execute.c | 8 ++++-- + src/core/namespace.c | 80 +++++++++++++++++++++++++++++++++++++++++++++------- + src/core/namespace.h | 3 +- + src/test/test-ns.c | 24 ++++++++++++++-- + 4 files changed, 100 insertions(+), 15 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 59340ec05..863babd76 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1305,6 +1305,7 @@ static int exec_child( + uid_t uid = UID_INVALID; + gid_t gid = GID_INVALID; + int i, r; ++ bool needs_mount_namespace; + + assert(command); + assert(context); +@@ -1593,7 +1594,9 @@ static int exec_child( + } + } + +- if (exec_needs_mount_namespace(context, params, runtime)) { ++ needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime); ++ ++ if (needs_mount_namespace) { + char *tmp = NULL, *var = NULL; + + /* The runtime struct only contains the parent +@@ -1610,6 +1613,7 @@ static int exec_child( + } + + r = setup_namespace( ++ params->apply_chroot ? context->root_directory : NULL, + context->read_write_dirs, + context->read_only_dirs, + context->inaccessible_dirs, +@@ -1635,7 +1639,7 @@ static int exec_child( + } + + if (params->apply_chroot) { +- if (context->root_directory) ++ if (!needs_mount_namespace && context->root_directory) + if (chroot(context->root_directory) < 0) { + *exit_status = EXIT_CHROOT; + return -errno; +diff --git a/src/core/namespace.c b/src/core/namespace.c +index 00495c144..574746273 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -44,6 +44,7 @@ + #include "label.h" + #include "selinux-util.h" + #include "namespace.h" ++#include "mkdir.h" + + typedef enum MountMode { + /* This is ordered by priority! */ +@@ -132,6 +133,22 @@ static void drop_duplicates(BindMount *m, unsigned *n) { + *n = t - m; + } + ++static int mount_move_root(const char *path) { ++ if (chdir(path) < 0) ++ return -errno; ++ ++ if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) ++ return -errno; ++ ++ if (chroot(".") < 0) ++ return -errno; ++ ++ if (chdir("/") < 0) ++ return -errno; ++ ++ return 0; ++} ++ + static int mount_dev(BindMount *m) { + static const char devnodes[] = + "/dev/null\0" +@@ -231,7 +248,13 @@ static int mount_dev(BindMount *m) { + + dev_setup(temporary_mount); + +- if (mount(dev, "/dev/", NULL, MS_MOVE, NULL) < 0) { ++ /* Create the /dev directory if missing. It is more likely to be ++ * missing when the service is started with RootDirectory. This is ++ * consistent with mount units creating the mount points when missing. ++ */ ++ (void) mkdir_p_label(m->path, 0755); ++ ++ if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) { + r = -errno; + goto fail; + } +@@ -410,6 +433,7 @@ static int make_read_only(BindMount *m) { + } + + int setup_namespace( ++ const char* root_directory, + char** read_write_dirs, + char** read_only_dirs, + char** inaccessible_dirs, +@@ -455,37 +479,56 @@ int setup_namespace( + return r; + + if (tmp_dir) { +- m->path = "/tmp"; ++ m->path = prefix_roota(root_directory, "/tmp"); + m->mode = PRIVATE_TMP; + m++; + } + + if (var_tmp_dir) { +- m->path = "/var/tmp"; ++ m->path = prefix_roota(root_directory, "/var/tmp"); + m->mode = PRIVATE_VAR_TMP; + m++; + } + + if (private_dev) { +- m->path = "/dev"; ++ m->path = prefix_roota(root_directory, "/dev"); + m->mode = PRIVATE_DEV; + m++; + } + + if (bus_endpoint_path) { +- m->path = bus_endpoint_path; ++ m->path = prefix_roota(root_directory, bus_endpoint_path); + m->mode = PRIVATE_BUS_ENDPOINT; + m++; + } + + if (protect_home != PROTECT_HOME_NO) { +- r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE); ++ const char *home_dir, *run_user_dir, *root_dir; ++ ++ home_dir = prefix_roota(root_directory, "/home"); ++ home_dir = strjoina("-", home_dir); ++ run_user_dir = prefix_roota(root_directory, "/run/user"); ++ run_user_dir = strjoina("-", run_user_dir); ++ root_dir = prefix_roota(root_directory, "/root"); ++ root_dir = strjoina("-", root_dir); ++ ++ r = append_mounts(&m, STRV_MAKE(home_dir, run_user_dir, root_dir), ++ protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE); + if (r < 0) + return r; + } + + if (protect_system != PROTECT_SYSTEM_NO) { +- r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ? STRV_MAKE("/usr", "-/boot", "/etc") : STRV_MAKE("/usr", "-/boot"), READONLY); ++ const char *usr_dir, *boot_dir, *etc_dir; ++ ++ usr_dir = prefix_roota(root_directory, "/home"); ++ boot_dir = prefix_roota(root_directory, "/boot"); ++ boot_dir = strjoina("-", boot_dir); ++ etc_dir = prefix_roota(root_directory, "/etc"); ++ ++ r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ++ ? STRV_MAKE(usr_dir, boot_dir, etc_dir) ++ : STRV_MAKE(usr_dir, boot_dir), READONLY); + if (r < 0) + return r; + } +@@ -496,12 +539,20 @@ int setup_namespace( + drop_duplicates(mounts, &n); + } + +- if (n > 0) { ++ if (n > 0 || root_directory) { + /* Remount / as SLAVE so that nothing now mounted in the namespace + shows up in the parent */ + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) + return -errno; ++ } ++ ++ if (root_directory) { ++ /* Turn directory into bind mount */ ++ if (mount(root_directory, root_directory, NULL, MS_BIND|MS_REC, NULL) < 0) ++ return -errno; ++ } + ++ if (n > 0) { + for (m = mounts; m < mounts + n; ++m) { + r = apply_mount(m, tmp_dir, var_tmp_dir); + if (r < 0) +@@ -515,12 +566,21 @@ int setup_namespace( + } + } + ++ if (root_directory) { ++ /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */ ++ r = mount_move_root(root_directory); ++ ++ /* at this point, we cannot rollback */ ++ if (r < 0) ++ return r; ++ } ++ + /* Remount / as the desired mode. Not that this will not + * reestablish propagation from our side to the host, since + * what's disconnected is disconnected. */ + if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) { +- r = -errno; +- goto fail; ++ /* at this point, we cannot rollback */ ++ return -errno; + } + + return 0; +diff --git a/src/core/namespace.h b/src/core/namespace.h +index 42b92e780..00ab22bf2 100644 +--- a/src/core/namespace.h ++++ b/src/core/namespace.h +@@ -41,7 +41,8 @@ typedef enum ProtectSystem { + _PROTECT_SYSTEM_INVALID = -1 + } ProtectSystem; + +-int setup_namespace(char **read_write_dirs, ++int setup_namespace(const char *chroot, ++ char **read_write_dirs, + char **read_only_dirs, + char **inaccessible_dirs, + const char *tmp_dir, +diff --git a/src/test/test-ns.c b/src/test/test-ns.c +index 7cd7b7715..72a0004e3 100644 +--- a/src/test/test-ns.c ++++ b/src/test/test-ns.c +@@ -42,10 +42,12 @@ int main(int argc, char *argv[]) { + NULL + }; + +- const char * const inaccessible[] = { ++ const char *inaccessible[] = { + "/home/lennart/projects", + NULL + }; ++ char *root_directory; ++ char *projects_directory; + + int r; + char tmp_dir[] = "/tmp/systemd-private-XXXXXX", +@@ -54,7 +56,20 @@ int main(int argc, char *argv[]) { + assert_se(mkdtemp(tmp_dir)); + assert_se(mkdtemp(var_tmp_dir)); + +- r = setup_namespace((char **) writable, ++ root_directory = getenv("TEST_NS_CHROOT"); ++ projects_directory = getenv("TEST_NS_PROJECTS"); ++ ++ if (projects_directory) ++ inaccessible[0] = projects_directory; ++ ++ log_info("Inaccessible directory: '%s'", inaccessible[0]); ++ if (root_directory) ++ log_info("Chroot: '%s'", root_directory); ++ else ++ log_info("Not chrooted"); ++ ++ r = setup_namespace(root_directory, ++ (char **) writable, + (char **) readonly, + (char **) inaccessible, + tmp_dir, +@@ -66,6 +81,11 @@ int main(int argc, char *argv[]) { + 0); + if (r < 0) { + log_error_errno(r, "Failed to setup namespace: %m"); ++ ++ log_info("Usage:\n" ++ " sudo TEST_NS_PROJECTS=/home/lennart/projects ./test-ns\n" ++ " sudo TEST_NS_CHROOT=/home/alban/debian-tree TEST_NS_PROJECTS=/home/alban/debian-tree/home/alban/Documents ./test-ns"); ++ + return 1; + } + diff --git a/SOURCES/0448-core-if-the-start-command-vanishes-during-runtime-do.patch b/SOURCES/0448-core-if-the-start-command-vanishes-during-runtime-do.patch new file mode 100644 index 00000000..ff06ca3b --- /dev/null +++ b/SOURCES/0448-core-if-the-start-command-vanishes-during-runtime-do.patch @@ -0,0 +1,38 @@ +From a66f97acac8b99a49aac58adf6d652cad7e4be38 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 21 Oct 2016 12:27:46 +0200 +Subject: [PATCH] core: if the start command vanishes during runtime don't hit + an assert + +This can happen when the configuration is changed and reloaded while we are +executing a service. Let's not hit an assert in this case. + +Fixes: #4444 + +Cherry-picked from: 47fffb3530af3e3ad4048570611685635fde062e +Resolves: #1421658 +--- + src/core/service.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 6e7baa76c..84e00573f 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -1563,7 +1563,15 @@ static void service_enter_start(Service *s) { + } + + if (!c) { +- assert(s->type == SERVICE_ONESHOT); ++ if (s->type != SERVICE_ONESHOT) { ++ /* There's no command line configured for the main command? Hmm, that is strange. This can only ++ * happen if the configuration changes at runtime. In this case, let's enter a failure ++ * state. */ ++ log_unit_error(UNIT(s), "There's no 'start' task anymore we could start: %m"); ++ r = -ENXIO; ++ goto fail; ++ } ++ + service_enter_start_post(s); + return; + } diff --git a/SOURCES/0449-systemctl-make-sure-that-now-is-carried-out-5209.patch b/SOURCES/0449-systemctl-make-sure-that-now-is-carried-out-5209.patch new file mode 100644 index 00000000..d9b80ce7 --- /dev/null +++ b/SOURCES/0449-systemctl-make-sure-that-now-is-carried-out-5209.patch @@ -0,0 +1,46 @@ +From 10bf9c070764d09a4b39aa65ccba8b7501918a34 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 8 Feb 2017 20:57:08 +0100 +Subject: [PATCH] systemctl: make sure that --now is carried out (#5209) + +When services are already enabled/disabled/masked, make sure +that --now still enforces start/stop. +(cherry picked from commit 6bc30691b109302d386007c6bdabcc27d04991bc) +Resolves: #1417459 +--- + src/systemctl/systemctl.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index ff8b4e978..0333599c8 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -5549,16 +5549,20 @@ static int enable_unit(sd_bus *bus, char **args) { + "3) A unit may be started when needed via activation (socket, path, timer,\n" + " D-Bus, udev, scripted systemctl call, ...).\n"); + +- if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) { +- char *new_args[n_changes + 2]; +- unsigned i; ++ if (arg_now && STR_IN_SET(args[0], "enable", "disable", "mask")) { ++ unsigned len, i; + +- new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop"; +- for (i = 0; i < n_changes; i++) +- new_args[i + 1] = basename(changes[i].path); +- new_args[i + 1] = NULL; ++ len = strv_length(names); ++ { ++ char *new_args[len + 2]; + +- r = start_unit(bus, new_args); ++ new_args[0] = (char*) (streq(args[0], "enable") ? "start" : "stop"); ++ for (i = 0; i < len; i++) ++ new_args[i + 1] = basename(names[i]); ++ new_args[i + 1] = NULL; ++ ++ r = start_unit(bus, new_args); ++ } + } + + finish: diff --git a/SOURCES/0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch b/SOURCES/0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch new file mode 100644 index 00000000..651a0f5e --- /dev/null +++ b/SOURCES/0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch @@ -0,0 +1,47 @@ +From fa37e91818c1de70977462d170df08f441170db5 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 25 Aug 2016 08:18:42 +0200 +Subject: [PATCH] udev: inform systemd how many workers we can potentially + spawn (#4036) + +(cherry picked from commit 1ef72b55ba6d38f879d7ac9f0237cf8a2b53f0e6) +Resolves: #1361601 +--- + src/udev/udevd.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 82c7a5425..1d21182fb 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -697,6 +697,10 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) { + if (i >= 0) { + log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i); + arg_children_max = i; ++ ++ (void) sd_notifyf(false, ++ "READY=1\n" ++ "STATUS=Processing with %u children at max", arg_children_max); + } + + if (udev_ctrl_get_ping(ctrl_msg) > 0) +@@ -1271,8 +1275,6 @@ int main(int argc, char *argv[]) { + setsid(); + + write_string_file("/proc/self/oom_score_adj", "-1000"); +- } else { +- sd_notify(1, "READY=1"); + } + + if (arg_children_max <= 0) { +@@ -1321,6 +1323,10 @@ int main(int argc, char *argv[]) { + ep_netlink.data.fd = fd_netlink; + ep_worker.data.fd = fd_worker; + ++ (void) sd_notifyf(false, ++ "READY=1\n" ++ "STATUS=Processing with %u children at max", arg_children_max); ++ + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + log_error_errno(errno, "error creating epoll fd: %m"); diff --git a/SOURCES/0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch b/SOURCES/0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch new file mode 100644 index 00000000..db0bcebc --- /dev/null +++ b/SOURCES/0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch @@ -0,0 +1,24 @@ +From 01cfafc9f1d79f751405239046db827b6eb73f1e Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 20 Feb 2017 12:32:42 +0100 +Subject: [PATCH] service: log_unit consumes id of unit not a unit + +rhel-only +Related: #1421658 +--- + src/core/service.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 84e00573f..3bd6c3338 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -1567,7 +1567,7 @@ static void service_enter_start(Service *s) { + /* There's no command line configured for the main command? Hmm, that is strange. This can only + * happen if the configuration changes at runtime. In this case, let's enter a failure + * state. */ +- log_unit_error(UNIT(s), "There's no 'start' task anymore we could start: %m"); ++ log_unit_error(UNIT(s)->id, "There's no 'start' task anymore we could start: %m"); + r = -ENXIO; + goto fail; + } diff --git a/SOURCES/0452-automount-add-expire-support.patch b/SOURCES/0452-automount-add-expire-support.patch new file mode 100644 index 00000000..29485fa2 --- /dev/null +++ b/SOURCES/0452-automount-add-expire-support.patch @@ -0,0 +1,578 @@ +From c38c0e05767c5fd526368b63cebcdd5617332940 Mon Sep 17 00:00:00 2001 +From: Michael Olbrich +Date: Tue, 14 Apr 2015 22:01:48 +0200 +Subject: [PATCH] automount: add expire support + +(cherry picked from commit deb0a77cf0b409141c4b116ae30becb3d878e1ad) +Resolves: #1354410 +--- + man/systemd.automount.xml | 8 ++ + man/systemd.mount.xml | 9 ++ + src/core/automount.c | 224 ++++++++++++++++++++++++++++++++-- + src/core/automount.h | 6 +- + src/core/dbus-automount.c | 1 + + src/core/load-fragment-gperf.gperf.m4 | 1 + + src/core/mount.c | 20 +-- + src/fstab-generator/fstab-generator.c | 28 +++++ + 8 files changed, 269 insertions(+), 28 deletions(-) + +diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml +index b5b5885cd..9561590c5 100644 +--- a/man/systemd.automount.xml ++++ b/man/systemd.automount.xml +@@ -135,6 +135,14 @@ + creating these directories. Takes an access mode in octal + notation. Defaults to 0755. + ++ ++ TimeoutIdleSec= ++ Configures an idleness timeout. Once the mount has been ++ idle for the specified time, systemd will attempt to unmount. Takes a ++ unit-less value in seconds, or a time span value such as "5min 20s". ++ Pass 0 to disable the timeout logic. The timeout is disabled by ++ default. ++ + + + +diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml +index 8e652e133..04ed1e1cf 100644 +--- a/man/systemd.mount.xml ++++ b/man/systemd.mount.xml +@@ -177,6 +177,15 @@ + for details. + + ++ ++ ++ ++ Configures the idleness timeout of the ++ automount unit. See TimeoutIdleSec= in ++ systemd.automount5 ++ for details. ++ ++ + + + +diff --git a/src/core/automount.c b/src/core/automount.c +index b391f6198..4e066613d 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -42,6 +42,7 @@ + #include "dbus-automount.h" + #include "bus-util.h" + #include "bus-error.h" ++#include "async.h" + + static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_DEAD] = UNIT_INACTIVE, +@@ -50,6 +51,22 @@ static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_FAILED] = UNIT_FAILED + }; + ++struct expire_data { ++ int dev_autofs_fd; ++ int ioctl_fd; ++}; ++ ++static inline void expire_data_free(struct expire_data *data) { ++ if (!data) ++ return; ++ ++ safe_close(data->dev_autofs_fd); ++ safe_close(data->ioctl_fd); ++ free(data); ++} ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free); ++ + static int open_dev_autofs(Manager *m); + static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata); + +@@ -81,13 +98,16 @@ static void repeat_unmount(const char *path) { + } + } + ++static int automount_send_ready(Automount *a, Set *tokens, int status); ++ + static void unmount_autofs(Automount *a) { + assert(a); + + if (a->pipe_fd < 0) + return; + +- automount_send_ready(a, -EHOSTDOWN); ++ 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); +@@ -112,6 +132,10 @@ static void automount_done(Unit *u) { + + set_free(a->tokens); + a->tokens = NULL; ++ set_free(a->expire_tokens); ++ a->expire_tokens = NULL; ++ ++ a->expire_event_source = sd_event_source_unref(a->expire_event_source); + } + + static int automount_add_mount_links(Automount *a) { +@@ -265,6 +289,7 @@ static int automount_coldplug(Unit *u, Hashmap *deferred_work) { + } + + static void automount_dump(Unit *u, FILE *f, const char *prefix) { ++ char time_string[FORMAT_TIMESPAN_MAX]; + Automount *a = AUTOMOUNT(u); + + assert(a); +@@ -273,11 +298,13 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) { + "%sAutomount State: %s\n" + "%sResult: %s\n" + "%sWhere: %s\n" +- "%sDirectoryMode: %04o\n", ++ "%sDirectoryMode: %04o\n" ++ "%sTimeoutIdleUSec: %s\n", + prefix, automount_state_to_string(a->state), + prefix, automount_result_to_string(a->result), + prefix, a->where, +- prefix, a->directory_mode); ++ prefix, a->directory_mode, ++ prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC)); + } + + static void automount_enter_dead(Automount *a, AutomountResult f) { +@@ -367,7 +394,7 @@ static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) { + return 0; + } + +-static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) { ++static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, usec_t usec) { + struct autofs_dev_ioctl param; + + assert(dev_autofs_fd >= 0); +@@ -375,7 +402,9 @@ static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) { + + init_autofs_dev_ioctl(¶m); + param.ioctlfd = ioctl_fd; +- param.timeout.timeout = sec; ++ ++ /* Convert to seconds, rounding up. */ ++ param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_SEC; + + if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, ¶m) < 0) + return -errno; +@@ -404,7 +433,7 @@ static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, in + return 0; + } + +-int automount_send_ready(Automount *a, int status) { ++static int automount_send_ready(Automount *a, Set *tokens, int status) { + _cleanup_close_ int ioctl_fd = -1; + unsigned token; + int r; +@@ -412,7 +441,7 @@ int automount_send_ready(Automount *a, int status) { + assert(a); + assert(status <= 0); + +- if (set_isempty(a->tokens)) ++ if (set_isempty(tokens)) + return 0; + + ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id); +@@ -427,7 +456,7 @@ int automount_send_ready(Automount *a, int status) { + r = 0; + + /* Autofs thankfully does not hand out 0 as a token */ +- while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) { ++ while ((token = PTR_TO_UINT(set_steal_first(tokens)))) { + int k; + + /* Autofs fun fact II: +@@ -446,6 +475,55 @@ int automount_send_ready(Automount *a, int status) { + return r; + } + ++int automount_update_mount(Automount *a, MountState old_state, MountState state) { ++ _cleanup_close_ int ioctl_fd = -1; ++ ++ assert(a); ++ ++ switch (state) { ++ case MOUNT_MOUNTED: ++ case MOUNT_REMOUNTING: ++ automount_send_ready(a, a->tokens, 0); ++ break; ++ case MOUNT_DEAD: ++ case MOUNT_UNMOUNTING: ++ case MOUNT_MOUNTING_SIGTERM: ++ case MOUNT_MOUNTING_SIGKILL: ++ case MOUNT_REMOUNTING_SIGTERM: ++ case MOUNT_REMOUNTING_SIGKILL: ++ case MOUNT_UNMOUNTING_SIGTERM: ++ case MOUNT_UNMOUNTING_SIGKILL: ++ case MOUNT_FAILED: ++ if (old_state != state) ++ automount_send_ready(a, a->tokens, -ENODEV); ++ break; ++ default: ++ break; ++ } ++ ++ switch (state) { ++ case MOUNT_DEAD: ++ automount_send_ready(a, a->expire_tokens, 0); ++ break; ++ case MOUNT_MOUNTING: ++ case MOUNT_MOUNTING_DONE: ++ case MOUNT_MOUNTING_SIGTERM: ++ case MOUNT_MOUNTING_SIGKILL: ++ case MOUNT_REMOUNTING_SIGTERM: ++ case MOUNT_REMOUNTING_SIGKILL: ++ case MOUNT_UNMOUNTING_SIGTERM: ++ case MOUNT_UNMOUNTING_SIGKILL: ++ case MOUNT_FAILED: ++ if (old_state != state) ++ automount_send_ready(a, a->expire_tokens, -ENODEV); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ + static void automount_enter_waiting(Automount *a) { + _cleanup_close_ int ioctl_fd = -1; + int p[2] = { -1, -1 }; +@@ -505,7 +583,7 @@ static void automount_enter_waiting(Automount *a) { + if (r < 0) + goto fail; + +- r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300); ++ r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, a->timeout_idle_usec); + if (r < 0) + goto fail; + +@@ -537,6 +615,83 @@ fail: + automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); + } + ++static void *expire_thread(void *p) { ++ struct autofs_dev_ioctl param; ++ _cleanup_(expire_data_freep) struct expire_data *data = (struct expire_data*)p; ++ int r; ++ ++ assert(data->dev_autofs_fd >= 0); ++ assert(data->ioctl_fd >= 0); ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = data->ioctl_fd; ++ ++ do { ++ r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, ¶m); ++ } while (r >= 0); ++ ++ if (errno != EAGAIN) ++ log_warning_errno(errno, "Failed to expire automount, ignoring: %m"); ++ ++ 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; ++ int r; ++ ++ assert(a); ++ assert(source == a->expire_event_source); ++ ++ data = new0(struct expire_data, 1); ++ if (!data) ++ return log_oom(); ++ ++ data->ioctl_fd = -1; ++ ++ data->dev_autofs_fd = fcntl(UNIT(a)->manager->dev_autofs_fd, F_DUPFD_CLOEXEC, 3); ++ if (data->dev_autofs_fd < 0) ++ return log_unit_error_errno(UNIT(a)->id, errno, "Failed to duplicate autofs fd: %m"); ++ ++ data->ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id); ++ if (data->ioctl_fd < 0) ++ return log_unit_error_errno(UNIT(a)->id, data->ioctl_fd, "Couldn't open autofs ioctl fd: %m"); ++ ++ r = asynchronous_job(expire_thread, data); ++ if (r < 0) ++ return log_unit_error_errno(UNIT(a)->id, r, "Failed to start expire job: %m"); ++ ++ data = NULL; ++ ++ return automount_start_expire(a); ++} ++ ++static int automount_start_expire(Automount *a) { ++ int r; ++ usec_t timeout; ++ ++ assert(a); ++ ++ timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/10, USEC_PER_SEC); ++ ++ if (a->expire_event_source) { ++ r = sd_event_source_set_time(a->expire_event_source, timeout); ++ if (r < 0) ++ return r; ++ ++ return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT); ++ } ++ ++ return sd_event_add_time( ++ UNIT(a)->manager->event, ++ &a->expire_event_source, ++ CLOCK_MONOTONIC, timeout, 0, ++ automount_dispatch_expire, a); ++} ++ + static void automount_enter_runnning(Automount *a) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + struct stat st; +@@ -549,7 +704,8 @@ static void automount_enter_runnning(Automount *a) { + if (unit_stop_pending(UNIT(a))) { + log_unit_debug(UNIT(a)->id, + "Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id); +- automount_send_ready(a, -EHOSTDOWN); ++ automount_send_ready(a, a->tokens, -EHOSTDOWN); ++ automount_send_ready(a, a->expire_tokens, -EHOSTDOWN); + return; + } + +@@ -576,6 +732,10 @@ static void automount_enter_runnning(Automount *a) { + } + } + ++ r = automount_start_expire(a); ++ if (r < 0) ++ log_unit_warning_errno(UNIT(a)->id, r, "Failed to start expiration timer, ignoring: %m"); ++ + automount_set_state(a, AUTOMOUNT_RUNNING); + return; + +@@ -629,6 +789,8 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { + + SET_FOREACH(p, a->tokens, i) + unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p)); ++ SET_FOREACH(p, a->expire_tokens, i) ++ unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p)); + + if (a->pipe_fd >= 0) { + int copy; +@@ -688,6 +850,22 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu + if (r < 0) + return r; + } ++ } else if (streq(key, "expire-token")) { ++ unsigned token; ++ ++ if (safe_atou(value, &token) < 0) ++ log_unit_debug(u->id, "Failed to parse token value %s", value); ++ else { ++ r = set_ensure_allocated(&a->expire_tokens, NULL); ++ if (r < 0) { ++ log_oom(); ++ return 0; ++ } ++ ++ r = set_put(a->expire_tokens, UINT_TO_PTR(token)); ++ if (r < 0) ++ log_unit_error_errno(u->id, r, "Failed to add expire token to set: %m"); ++ } + } else if (streq(key, "pipe-fd")) { + int fd; + +@@ -725,6 +903,7 @@ static bool automount_check_gc(Unit *u) { + } + + static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) { ++ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + union autofs_v5_packet_union packet; + Automount *a = AUTOMOUNT(userdata); + ssize_t l; +@@ -777,6 +956,31 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo + automount_enter_runnning(a); + break; + ++ case autofs_ptype_expire_direct: ++ log_unit_debug(UNIT(a)->id, "Got direct umount request on %s", a->where); ++ ++ (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); ++ ++ r = set_ensure_allocated(&a->expire_tokens, NULL); ++ if (r < 0) { ++ log_unit_error(UNIT(a)->id, "Failed to allocate token set."); ++ goto fail; ++ } ++ ++ r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token)); ++ if (r < 0) { ++ 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); ++ if (r < 0) { ++ log_unit_warning(UNIT(a)->id, ++ "%s failed to queue umount startup job: %s", ++ UNIT(a)->id, bus_error_message(&error, r)); ++ goto fail; ++ } ++ break; ++ + default: + log_unit_error(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type); + break; +diff --git a/src/core/automount.h b/src/core/automount.h +index 60f552238..2a50fef68 100644 +--- a/src/core/automount.h ++++ b/src/core/automount.h +@@ -47,6 +47,7 @@ struct Automount { + AutomountState state, deserialized_state; + + char *where; ++ usec_t timeout_idle_usec; + + int pipe_fd; + sd_event_source *pipe_event_source; +@@ -54,13 +55,16 @@ struct Automount { + dev_t dev_id; + + Set *tokens; ++ Set *expire_tokens; ++ ++ sd_event_source *expire_event_source; + + AutomountResult result; + }; + + extern const UnitVTable automount_vtable; + +-int automount_send_ready(Automount *a, int status); ++int automount_update_mount(Automount *a, MountState old_state, MountState state); + + const char* automount_state_to_string(AutomountState i) _const_; + AutomountState automount_state_from_string(const char *s) _pure_; +diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c +index b2a510ad0..c62ad8242 100644 +--- a/src/core/dbus-automount.c ++++ b/src/core/dbus-automount.c +@@ -32,5 +32,6 @@ const sd_bus_vtable bus_automount_vtable[] = { + SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), ++ SD_BUS_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END + }; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index f3a6e13d9..c866a9cd0 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -318,6 +318,7 @@ KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl + m4_dnl + Automount.Where, config_parse_path, 0, offsetof(Automount, where) + Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode) ++Automount.TimeoutIdleSec, config_parse_sec, 0, offsetof(Automount, timeout_idle_usec) + m4_dnl + Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) + Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) +diff --git a/src/core/mount.c b/src/core/mount.c +index 3fbdb7daf..7ca7f5a25 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -552,7 +552,7 @@ static int mount_load(Unit *u) { + return mount_verify(m); + } + +-static int mount_notify_automount(Mount *m, int status) { ++static int mount_notify_automount(Mount *m, MountState old_state, MountState state) { + Unit *p; + int r; + Iterator i; +@@ -561,7 +561,7 @@ static int mount_notify_automount(Mount *m, int status) { + + SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i) + if (p->type == UNIT_AUTOMOUNT) { +- r = automount_send_ready(AUTOMOUNT(p), status); ++ r = automount_update_mount(AUTOMOUNT(p), old_state, state); + if (r < 0) + return r; + } +@@ -592,21 +592,7 @@ static void mount_set_state(Mount *m, MountState state) { + m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + } + +- if (state == MOUNT_MOUNTED || +- state == MOUNT_REMOUNTING) +- mount_notify_automount(m, 0); +- else if (state == MOUNT_DEAD || +- state == MOUNT_UNMOUNTING || +- state == MOUNT_MOUNTING_SIGTERM || +- state == MOUNT_MOUNTING_SIGKILL || +- state == MOUNT_REMOUNTING_SIGTERM || +- state == MOUNT_REMOUNTING_SIGKILL || +- state == MOUNT_UNMOUNTING_SIGTERM || +- state == MOUNT_UNMOUNTING_SIGKILL || +- state == MOUNT_FAILED) { +- if (state != old_state) +- mount_notify_automount(m, -ENODEV); +- } ++ mount_notify_automount(m, old_state, state); + + if (state != old_state) + log_unit_debug(UNIT(m)->id, +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 029eb1638..a943393b0 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -213,6 +213,30 @@ static int write_requires_mounts_for(FILE *f, const char *opts) { + + return 0; + } ++ ++static int write_idle_timeout(FILE *f, const char *where, const char *opts, char **filtered) { ++ _cleanup_free_ char *timeout = NULL; ++ char timespan[FORMAT_TIMESPAN_MAX]; ++ usec_t u; ++ int r; ++ ++ r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, filtered); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to parse options: %m"); ++ if (r == 0) ++ return 0; ++ ++ r = parse_sec(timeout, &u); ++ if (r < 0) { ++ log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout); ++ return 0; ++ } ++ ++ fprintf(f, "TimeoutIdleSec=%s\n", format_timespan(timespan, sizeof(timespan), u, 0)); ++ ++ return 0; ++} ++ + static int add_mount( + const char *what, + const char *where, +@@ -374,6 +398,10 @@ static int add_mount( + "Where=%s\n", + where); + ++ r = write_idle_timeout(f, where, opts, &filtered); ++ if (r < 0) ++ return r; ++ + fflush(f); + if (ferror(f)) + return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit); diff --git a/SOURCES/0453-fstab-generator-fix-memleak.patch b/SOURCES/0453-fstab-generator-fix-memleak.patch new file mode 100644 index 00000000..c21b4659 --- /dev/null +++ b/SOURCES/0453-fstab-generator-fix-memleak.patch @@ -0,0 +1,45 @@ +From c6b00287b8847c550ab75947f52e37282632a2f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 2 May 2015 12:01:28 -0500 +Subject: [PATCH] fstab-generator: fix memleak + +filtered was used to store an allocated string twice. The first allocation was +thus lost. The string is not needed for anything, so simply skip the allocation. + +Fixup for deb0a77cf0b409141c4. + +(cherry picked from commit 336b5c615e9c101476784b32df1b86aaeac96431) +Related: #1354410 +--- + src/fstab-generator/fstab-generator.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index a943393b0..32aca2244 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -214,13 +214,13 @@ static int write_requires_mounts_for(FILE *f, const char *opts) { + return 0; + } + +-static int write_idle_timeout(FILE *f, const char *where, const char *opts, char **filtered) { ++static int write_idle_timeout(FILE *f, const char *where, const char *opts) { + _cleanup_free_ char *timeout = NULL; + char timespan[FORMAT_TIMESPAN_MAX]; + usec_t u; + int r; + +- r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, filtered); ++ r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, NULL); + if (r < 0) + return log_warning_errno(r, "Failed to parse options: %m"); + if (r == 0) +@@ -398,7 +398,7 @@ static int add_mount( + "Where=%s\n", + where); + +- r = write_idle_timeout(f, where, opts, &filtered); ++ r = write_idle_timeout(f, where, opts); + if (r < 0) + return r; + diff --git a/SOURCES/0454-remove-bus-proxyd.patch b/SOURCES/0454-remove-bus-proxyd.patch new file mode 100644 index 00000000..0caaa667 --- /dev/null +++ b/SOURCES/0454-remove-bus-proxyd.patch @@ -0,0 +1,5066 @@ +From 1425f8f9a084e962df43dcdead04104cf1b3b83d Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 12 Feb 2016 15:25:27 +0100 +Subject: [PATCH] remove bus-proxyd + +As kdbus won't land in the anticipated way, the bus-proxy is not needed in +its current form. It can be resurrected at any time thanks to the history, +but for now, let's remove it from the sources. If we'll have a similar tool +in the future, it will look quite differently anyway. + +Note that stdio-bridge is still available. It was restored from a version +prior to f252ff17, and refactored to make use of the current APIs. + +(cherry picked from commit 798c486fbcdce3346cd862c52e1a200bb8a2cb23) +Resolves: #1317518 +--- + .gitignore | 1 - + Makefile-man.am | 2 - + Makefile.am | 80 +- + README | 3 - + TODO | 4 - + man/busctl.xml | 1 - + man/systemd-bus-proxyd.xml | 109 --- + man/systemd-bus-proxyd@.service.xml | 81 -- + src/bus-proxyd/Makefile | 1 - + src/bus-proxyd/bus-proxyd.c | 346 -------- + src/bus-proxyd/bus-xml-policy.c | 1325 ------------------------------ + src/bus-proxyd/bus-xml-policy.h | 151 ---- + src/bus-proxyd/driver.c | 608 -------------- + src/bus-proxyd/driver.h | 27 - + src/bus-proxyd/proxy.c | 864 ------------------- + src/bus-proxyd/proxy.h | 53 -- + src/bus-proxyd/stdio-bridge.c | 263 ------ + src/bus-proxyd/synthesize.c | 228 ----- + src/bus-proxyd/synthesize.h | 34 - + src/bus-proxyd/test-bus-xml-policy.c | 182 ---- + src/stdio-bridge/stdio-bridge.c | 303 +++++++ + src/test/test-tables.c | 3 - + sysusers.d/systemd.conf.m4 | 3 - + units/.gitignore | 2 - + units/systemd-bus-proxyd.service.m4.in | 19 - + units/systemd-bus-proxyd.socket | 12 - + units/user/.gitignore | 2 - + units/user/systemd-bus-proxyd.service.in | 13 - + units/user/systemd-bus-proxyd.socket | 12 - + 29 files changed, 305 insertions(+), 4427 deletions(-) + delete mode 100644 man/systemd-bus-proxyd.xml + delete mode 100644 man/systemd-bus-proxyd@.service.xml + delete mode 120000 src/bus-proxyd/Makefile + delete mode 100644 src/bus-proxyd/bus-proxyd.c + delete mode 100644 src/bus-proxyd/bus-xml-policy.c + delete mode 100644 src/bus-proxyd/bus-xml-policy.h + delete mode 100644 src/bus-proxyd/driver.c + delete mode 100644 src/bus-proxyd/driver.h + delete mode 100644 src/bus-proxyd/proxy.c + delete mode 100644 src/bus-proxyd/proxy.h + delete mode 100644 src/bus-proxyd/stdio-bridge.c + delete mode 100644 src/bus-proxyd/synthesize.c + delete mode 100644 src/bus-proxyd/synthesize.h + delete mode 100644 src/bus-proxyd/test-bus-xml-policy.c + create mode 100644 src/stdio-bridge/stdio-bridge.c + delete mode 100644 units/systemd-bus-proxyd.service.m4.in + delete mode 100644 units/systemd-bus-proxyd.socket + delete mode 100644 units/user/systemd-bus-proxyd.service.in + delete mode 100644 units/user/systemd-bus-proxyd.socket + +diff --git a/.gitignore b/.gitignore +index 0360f7c6b..5ac188bfb 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -56,7 +56,6 @@ + /systemd-backlight + /systemd-binfmt + /systemd-bootchart +-/systemd-bus-proxyd + /systemd-cat + /systemd-cgls + /systemd-cgroups-agent +diff --git a/Makefile-man.am b/Makefile-man.am +index 7ec709c8b..734c80598 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -1762,8 +1762,6 @@ EXTRA_DIST += \ + man/systemd-backlight@.service.xml \ + man/systemd-binfmt.service.xml \ + man/systemd-bootchart.xml \ +- man/systemd-bus-proxyd.xml \ +- man/systemd-bus-proxyd@.service.xml \ + man/systemd-cat.xml \ + man/systemd-cgls.xml \ + man/systemd-cgtop.xml \ +diff --git a/Makefile.am b/Makefile.am +index b347aed7d..924b34b69 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -397,7 +397,6 @@ rootlibexec_PROGRAMS = \ + systemd-ac-power \ + systemd-sysctl \ + systemd-sleep \ +- systemd-bus-proxyd \ + systemd-socket-proxyd \ + systemd-update-done + +@@ -1421,7 +1420,6 @@ tests += \ + test-ratelimit \ + test-condition \ + test-uid-range \ +- test-bus-policy \ + test-locale-util \ + test-execute \ + test-copy \ +@@ -1792,14 +1790,11 @@ test_unaligned_SOURCES = \ + test_tables_SOURCES = \ + src/test/test-tables.c \ + src/shared/test-tables.h \ +- src/bus-proxyd/bus-xml-policy.c \ +- src/bus-proxyd/bus-xml-policy.h \ + src/journal/journald-server.c \ + src/journal/journald-server.h + + test_tables_CPPFLAGS = \ +- $(AM_CPPFLAGS) \ +- -I$(top_srcdir)/src/bus-proxyd ++ $(AM_CPPFLAGS) + + test_tables_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -2041,14 +2036,6 @@ test_conf_files_SOURCES = \ + test_conf_files_LDADD = \ + libsystemd-shared.la + +-test_bus_policy_SOURCES = \ +- src/bus-proxyd/test-bus-xml-policy.c +- +-test_bus_policy_LDADD = \ +- libsystemd-proxy.la \ +- libsystemd-internal.la \ +- libsystemd-shared.la +- + # ------------------------------------------------------------------------------ + ## .PHONY so it always rebuilds it + .PHONY: coverage lcov-run lcov-report coverage-sync +@@ -2704,75 +2691,12 @@ systemd_run_LDADD = \ + libsystemd-shared.la + + # ------------------------------------------------------------------------------ +-noinst_LTLIBRARIES += \ +- libsystemd-proxy.la +- +-libsystemd_proxy_la_SOURCES = \ +- src/bus-proxyd/bus-xml-policy.c \ +- src/bus-proxyd/bus-xml-policy.h \ +- src/bus-proxyd/driver.c \ +- src/bus-proxyd/driver.h \ +- src/bus-proxyd/proxy.c \ +- src/bus-proxyd/proxy.h \ +- src/bus-proxyd/synthesize.c \ +- src/bus-proxyd/synthesize.h +- +-libsystemd_proxy_la_CFLAGS = \ +- $(AM_CFLAGS) \ +- -pthread +- +-libsystemd_proxy_la_LIBADD = \ +- libsystemd-internal.la \ +- libsystemd-shared.la +- +-systemd_bus_proxyd_SOURCES = \ +- src/bus-proxyd/bus-proxyd.c +- +-systemd_bus_proxyd_CFLAGS = \ +- $(AM_CFLAGS) \ +- -pthread +- +-systemd_bus_proxyd_LDADD = \ +- libsystemd-proxy.la \ +- libsystemd-internal.la \ +- libsystemd-shared.la +- + systemd_stdio_bridge_SOURCES = \ +- src/bus-proxyd/stdio-bridge.c ++ src/stdio-bridge/stdio-bridge.c + + systemd_stdio_bridge_LDADD = \ +- libsystemd-proxy.la \ + libsystemd-internal.la \ + libsystemd-shared.la +- +-if ENABLE_KDBUS +-nodist_systemunit_DATA += \ +- units/systemd-bus-proxyd.service +- +-dist_systemunit_DATA += \ +- units/systemd-bus-proxyd.socket +- +-nodist_userunit_DATA += \ +- units/user/systemd-bus-proxyd.service +- +-dist_userunit_DATA += \ +- units/user/systemd-bus-proxyd.socket +-endif +- +-EXTRA_DIST += \ +- units/systemd-bus-proxyd.service.m4.in \ +- units/user/systemd-bus-proxyd.service.in +- +-CLEANFILES += \ +- units/systemd-bus-proxyd.service.m4 +- +-if HAVE_SMACK +-bus-proxyd-set-cap-hook: +- -$(SETCAP) cap_mac_admin+ei $(DESTDIR)$(rootlibexecdir)/systemd-bus-proxyd +- +-INSTALL_EXEC_HOOKS += bus-proxyd-set-cap-hook +-endif +- + # ------------------------------------------------------------------------------ + systemd_tty_ask_password_agent_SOURCES = \ + src/tty-ask-password-agent/tty-ask-password-agent.c +diff --git a/README b/README +index ffc2cf9f2..bf75909f8 100644 +--- a/README ++++ b/README +@@ -198,9 +198,6 @@ USERS AND GROUPS: + Similarly, the name resolution daemon requires the + "systemd-resolve" system user and group to exist. + +- Similarly, the kdbus dbus1 proxy daemon requires the +- "systemd-bus-proxy" system user and group to exist. +- + NSS: + systemd ships with three NSS modules: + +diff --git a/TODO b/TODO +index 498d82c21..99473078a 100644 +--- a/TODO ++++ b/TODO +@@ -431,10 +431,6 @@ Features: + - path escaping + - update systemd.special(7) to mention that dbus.socket is only about the compatibility socket now + - test bloom filter generation indexes +- - bus-proxy: when passing messages from kdbus, make sure we properly +- handle the case where a large number of fds is appended that we +- cannot pass into sendmsg() of the AF_UNIX sokcet (which only accepts +- 253 messages) + - kdbus: introduce a concept of "send-only" connections + - kdbus: add counter for refused unicast messages that is passed out via the RECV ioctl. SImilar to the counter for dropped multicast messages we already have. + +diff --git a/man/busctl.xml b/man/busctl.xml +index 0635280ea..c68fe236c 100644 +--- a/man/busctl.xml ++++ b/man/busctl.xml +@@ -468,7 +468,6 @@ o "/org/freedesktop/systemd1/job/42684" + kdbus, + sd-bus3, + systemd1, +- systemd-bus-proxyd8, + machinectl1, + wireshark1 + +diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml +deleted file mode 100644 +index e0efe9985..000000000 +--- a/man/systemd-bus-proxyd.xml ++++ /dev/null +@@ -1,109 +0,0 @@ +- +- +- +- +- +- +- +- +- systemd-bus-proxyd +- systemd +- +- +- +- Developer +- Lennart +- Poettering +- lennart@poettering.net +- +- +- +- +- +- systemd-bus-proxyd +- 8 +- +- +- +- systemd-bus-proxyd +- Connect STDIO or a socket to a given bus address +- +- +- +- +- /usr/lib/systemd/systemd-bus-proxyd +- OPTIONS +- PLACEHOLDER +- +- +- +- +- Description +- +- systemd-bus-proxyd will proxy D-Bus +- messages to and from a bus. The will be either the system bus or +- the bus specified with when that option +- is given. Messages will be proxied to/from standard input and +- output, or the socket received through socket activation. +- +- This program can be used to connect a program using classic +- D-Bus to kdbus. +- +- +- +- Options and Arguments +- +- The following options are understood: +- +- +- +- +- +- +- Connect to the bus specified by +- ADDRESS. Multiple colon-separated +- addresses can be specified, in which case +- systemd-bus-proxyd will attempt to +- connect to them in turn. +- +- +- +- +- +- +- +- PLACEHOLDER, if given, must be a string +- of x and will be used to display information about +- the process that systemd-bus-proxyd is forwarding +- messages for. +- +- +- +- See Also +- +- +- dbus-daemon1, +- D-Bus, +- kdbus +- +- +- +diff --git a/man/systemd-bus-proxyd@.service.xml b/man/systemd-bus-proxyd@.service.xml +deleted file mode 100644 +index dc4f07ff1..000000000 +--- a/man/systemd-bus-proxyd@.service.xml ++++ /dev/null +@@ -1,81 +0,0 @@ +- +- +- +- +- +- +- +- +- systemd-bus-proxyd@.service +- systemd +- +- +- +- Developer +- Lennart +- Poettering +- lennart@poettering.net +- +- +- +- +- +- systemd-bus-proxyd@.service +- 8 +- +- +- +- systemd-bus-proxyd@.service +- systemd-bus-proxyd.socket +- Proxy classic D-Bus clients to kdbus +- +- +- +- systemd-bus-proxyd@.service +- systemd-bus-proxyd.socket +- +- +- +- Description +- +- systemd-bus-proxyd.socket will launch +- systemd-bus-proxyd@.service for connections +- to the classic D-Bus socket in +- /var/run/dbus/system_bus_socket. +- +- systemd-bus-proxyd@.service is launched +- for an existing D-Bus connection and will use +- systemd-bus-proxyd to proxy messages from this +- connection to the system bus (either kdbus or classic D-Bus). +- +- +- +- +- See Also +- +- +- systemd-bus-proxyd8, +- dbus-daemon1, +- D-Bus, +- kdbus +- +- +- +diff --git a/src/bus-proxyd/Makefile b/src/bus-proxyd/Makefile +deleted file mode 120000 +index d0b0e8e00..000000000 +--- a/src/bus-proxyd/Makefile ++++ /dev/null +@@ -1 +0,0 @@ +-../Makefile +\ No newline at end of file +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +deleted file mode 100644 +index b6550ed3c..000000000 +--- a/src/bus-proxyd/bus-proxyd.c ++++ /dev/null +@@ -1,346 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2010 Lennart Poettering +- Copyright 2013 Daniel Mack +- Copyright 2014 Kay Sievers +- Copyright 2015 David Herrmann +- +- 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 +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "log.h" +-#include "util.h" +-#include "hashmap.h" +-#include "socket-util.h" +-#include "sd-daemon.h" +-#include "sd-bus.h" +-#include "bus-internal.h" +-#include "bus-message.h" +-#include "bus-util.h" +-#include "build.h" +-#include "strv.h" +-#include "def.h" +-#include "capability.h" +-#include "bus-control.h" +-#include "smack-util.h" +-#include "set.h" +-#include "bus-xml-policy.h" +-#include "driver.h" +-#include "proxy.h" +-#include "synthesize.h" +- +-static char *arg_address = NULL; +-static char **arg_configuration = NULL; +- +-typedef struct { +- int fd; +- SharedPolicy *policy; +- uid_t bus_uid; +-} ClientContext; +- +-static ClientContext *client_context_free(ClientContext *c) { +- if (!c) +- return NULL; +- +- safe_close(c->fd); +- free(c); +- +- return NULL; +-} +- +-DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free); +- +-static int client_context_new(ClientContext **out) { +- _cleanup_(client_context_freep) ClientContext *c = NULL; +- +- c = new0(ClientContext, 1); +- if (!c) +- return -ENOMEM; +- +- c->fd = -1; +- +- *out = c; +- c = NULL; +- return 0; +-} +- +-static void *run_client(void *userdata) { +- _cleanup_(client_context_freep) ClientContext *c = userdata; +- _cleanup_(proxy_freep) Proxy *p = NULL; +- char comm[16]; +- int r; +- +- r = proxy_new(&p, c->fd, c->fd, arg_address); +- if (r < 0) +- goto exit; +- +- c->fd = -1; +- +- /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */ +- r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid); +- if (r >= (ssize_t)sizeof(comm)) +- comm[sizeof(comm) - 2] = '*'; +- (void) prctl(PR_SET_NAME, comm); +- +- r = proxy_set_policy(p, c->policy, arg_configuration); +- if (r < 0) +- goto exit; +- +- r = proxy_hello_policy(p, c->bus_uid); +- if (r < 0) +- goto exit; +- +- r = proxy_run(p); +- +-exit: +- return NULL; +-} +- +-static int loop_clients(int accept_fd, uid_t bus_uid) { +- _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL; +- pthread_attr_t attr; +- int r; +- +- r = pthread_attr_init(&attr); +- if (r < 0) { +- return log_error_errno(errno, "Cannot initialize pthread attributes: %m"); +- } +- +- r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +- if (r < 0) { +- r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m"); +- goto finish; +- } +- +- r = shared_policy_new(&sp); +- if (r < 0) +- goto finish; +- +- for (;;) { +- ClientContext *c; +- pthread_t tid; +- int fd; +- +- fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC); +- if (fd < 0) { +- if (errno == EAGAIN || errno == EINTR) +- continue; +- +- r = log_error_errno(errno, "accept4() failed: %m"); +- goto finish; +- } +- +- r = client_context_new(&c); +- if (r < 0) { +- log_oom(); +- close(fd); +- continue; +- } +- +- c->fd = fd; +- c->policy = sp; +- c->bus_uid = bus_uid; +- +- r = pthread_create(&tid, &attr, run_client, c); +- if (r < 0) { +- log_error("Cannot spawn thread: %m"); +- client_context_free(c); +- continue; +- } +- } +- +-finish: +- pthread_attr_destroy(&attr); +- return r; +-} +- +-static int help(void) { +- +- printf("%s [OPTIONS...]\n\n" +- "DBus proxy server.\n\n" +- " -h --help Show this help\n" +- " --version Show package version\n" +- " --configuration=PATH Configuration file or directory\n" +- " --machine=MACHINE Connect to specified machine\n" +- " --address=ADDRESS Connect to the bus specified by ADDRESS\n" +- " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n", +- program_invocation_short_name); +- +- return 0; +-} +- +-static int parse_argv(int argc, char *argv[]) { +- +- enum { +- ARG_VERSION = 0x100, +- ARG_ADDRESS, +- ARG_CONFIGURATION, +- ARG_MACHINE, +- }; +- +- static const struct option options[] = { +- { "help", no_argument, NULL, 'h' }, +- { "version", no_argument, NULL, ARG_VERSION }, +- { "address", required_argument, NULL, ARG_ADDRESS }, +- { "configuration", required_argument, NULL, ARG_CONFIGURATION }, +- { "machine", required_argument, NULL, ARG_MACHINE }, +- {}, +- }; +- +- int c, r; +- +- assert(argc >= 0); +- assert(argv); +- +- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) +- +- switch (c) { +- +- case 'h': +- help(); +- return 0; +- +- case ARG_VERSION: +- puts(PACKAGE_STRING); +- puts(SYSTEMD_FEATURES); +- return 0; +- +- case ARG_ADDRESS: +- r = free_and_strdup(&arg_address, optarg); +- if (r < 0) +- return log_oom(); +- break; +- +- case ARG_CONFIGURATION: +- r = strv_extend(&arg_configuration, optarg); +- if (r < 0) +- return log_oom(); +- break; +- +- case ARG_MACHINE: { +- _cleanup_free_ char *e = NULL; +- char *a; +- +- e = bus_address_escape(optarg); +- if (!e) +- return log_oom(); +- +-#ifdef ENABLE_KDBUS +- a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); +-#else +- a = strjoin("x-machine-unix:machine=", e, NULL); +-#endif +- if (!a) +- return log_oom(); +- +- free(arg_address); +- arg_address = a; +- +- break; +- } +- +- case '?': +- return -EINVAL; +- +- default: +- assert_not_reached("Unhandled option"); +- } +- +- if (argc > optind) { +- log_error("Too many arguments"); +- return -EINVAL; +- } +- +- if (!arg_address) { +- arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); +- if (!arg_address) +- return log_oom(); +- } +- +- return 1; +-} +- +-int main(int argc, char *argv[]) { +- int r, accept_fd; +- uid_t uid, bus_uid; +- gid_t gid; +- +- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); +- log_parse_environment(); +- log_open(); +- +- bus_uid = getuid(); +- +- if (geteuid() == 0) { +- const char *user = "systemd-bus-proxy"; +- +- r = get_user_creds(&user, &uid, &gid, NULL, NULL); +- if (r < 0) { +- log_error_errno(r, "Cannot resolve user name %s: %m", user); +- goto finish; +- } +- +- r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER); +- if (r < 0) { +- log_error_errno(r, "Cannot drop privileges: %m"); +- goto finish; +- } +- } +- +- r = parse_argv(argc, argv); +- if (r <= 0) +- goto finish; +- +- r = sd_listen_fds(0); +- if (r != 1) { +- log_error("Illegal number of file descriptors passed"); +- goto finish; +- } +- +- accept_fd = SD_LISTEN_FDS_START; +- +- r = fd_nonblock(accept_fd, false); +- if (r < 0) { +- log_error_errno(r, "Cannot mark accept-fd non-blocking: %m"); +- goto finish; +- } +- +- r = loop_clients(accept_fd, bus_uid); +- +-finish: +- sd_notify(false, +- "STOPPING=1\n" +- "STATUS=Shutting down."); +- +- strv_free(arg_configuration); +- free(arg_address); +- +- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +-} +diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c +deleted file mode 100644 +index f6ac0c009..000000000 +--- a/src/bus-proxyd/bus-xml-policy.c ++++ /dev/null +@@ -1,1325 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2013 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 "xml.h" +-#include "fileio.h" +-#include "strv.h" +-#include "set.h" +-#include "conf-files.h" +-#include "bus-internal.h" +-#include "bus-message.h" +-#include "bus-xml-policy.h" +-#include "sd-login.h" +- +-static void policy_item_free(PolicyItem *i) { +- assert(i); +- +- free(i->interface); +- free(i->member); +- free(i->error); +- free(i->name); +- free(i->path); +- free(i); +-} +- +-DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free); +- +-static void item_append(PolicyItem *i, PolicyItem **list) { +- +- PolicyItem *tail; +- +- LIST_FIND_TAIL(items, *list, tail); +- LIST_INSERT_AFTER(items, *list, tail, i); +-} +- +-static int file_load(Policy *p, const char *path) { +- +- _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL; +- _cleanup_(policy_item_freep) PolicyItem *i = NULL; +- void *xml_state = NULL; +- unsigned n_other = 0; +- const char *q; +- int r; +- +- enum { +- STATE_OUTSIDE, +- STATE_BUSCONFIG, +- STATE_POLICY, +- STATE_POLICY_CONTEXT, +- STATE_POLICY_CONSOLE, +- STATE_POLICY_USER, +- STATE_POLICY_GROUP, +- STATE_POLICY_OTHER_ATTRIBUTE, +- STATE_ALLOW_DENY, +- STATE_ALLOW_DENY_INTERFACE, +- STATE_ALLOW_DENY_MEMBER, +- STATE_ALLOW_DENY_ERROR, +- STATE_ALLOW_DENY_PATH, +- STATE_ALLOW_DENY_MESSAGE_TYPE, +- STATE_ALLOW_DENY_NAME, +- STATE_ALLOW_DENY_OTHER_ATTRIBUTE, +- STATE_OTHER, +- } state = STATE_OUTSIDE; +- +- enum { +- POLICY_CATEGORY_NONE, +- POLICY_CATEGORY_DEFAULT, +- POLICY_CATEGORY_MANDATORY, +- POLICY_CATEGORY_ON_CONSOLE, +- POLICY_CATEGORY_NO_CONSOLE, +- POLICY_CATEGORY_USER, +- POLICY_CATEGORY_GROUP +- } policy_category = POLICY_CATEGORY_NONE; +- +- unsigned line = 0; +- +- assert(p); +- +- r = read_full_file(path, &c, NULL); +- if (r < 0) { +- if (r == -ENOENT) +- return 0; +- if (r == -EISDIR) +- return r; +- +- return log_error_errno(r, "Failed to load %s: %m", path); +- } +- +- q = c; +- for (;;) { +- _cleanup_free_ char *name = NULL; +- int t; +- +- t = xml_tokenize(&q, &name, &xml_state, &line); +- if (t < 0) +- return log_error_errno(t, "XML parse failure in %s: %m", path); +- +- switch (state) { +- +- case STATE_OUTSIDE: +- +- if (t == XML_TAG_OPEN) { +- if (streq(name, "busconfig")) +- state = STATE_BUSCONFIG; +- else { +- log_error("Unexpected tag %s at %s:%u.", name, path, line); +- return -EINVAL; +- } +- +- } else if (t == XML_END) +- return 0; +- else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { +- log_error("Unexpected token (1) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_BUSCONFIG: +- +- if (t == XML_TAG_OPEN) { +- if (streq(name, "policy")) { +- state = STATE_POLICY; +- policy_category = POLICY_CATEGORY_NONE; +- free(policy_user); +- free(policy_group); +- policy_user = policy_group = NULL; +- } else { +- state = STATE_OTHER; +- n_other = 0; +- } +- } else if (t == XML_TAG_CLOSE_EMPTY || +- (t == XML_TAG_CLOSE && streq(name, "busconfig"))) +- state = STATE_OUTSIDE; +- else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { +- log_error("Unexpected token (2) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_POLICY: +- +- if (t == XML_ATTRIBUTE_NAME) { +- if (streq(name, "context")) +- state = STATE_POLICY_CONTEXT; +- else if (streq(name, "at_console")) +- state = STATE_POLICY_CONSOLE; +- else if (streq(name, "user")) +- state = STATE_POLICY_USER; +- else if (streq(name, "group")) +- state = STATE_POLICY_GROUP; +- else { +- log_warning("Attribute %s of tag unknown at %s:%u, ignoring.", name, path, line); +- state = STATE_POLICY_OTHER_ATTRIBUTE; +- } +- } else if (t == XML_TAG_CLOSE_EMPTY || +- (t == XML_TAG_CLOSE && streq(name, "policy"))) +- state = STATE_BUSCONFIG; +- else if (t == XML_TAG_OPEN) { +- PolicyItemType it; +- +- if (streq(name, "allow")) +- it = POLICY_ITEM_ALLOW; +- else if (streq(name, "deny")) +- it = POLICY_ITEM_DENY; +- else { +- log_warning("Unknown tag %s in %s:%u.", name, path, line); +- return -EINVAL; +- } +- +- assert(!i); +- i = new0(PolicyItem, 1); +- if (!i) +- return log_oom(); +- +- i->type = it; +- state = STATE_ALLOW_DENY; +- +- } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { +- log_error("Unexpected token (3) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_POLICY_CONTEXT: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- if (streq(name, "default")) { +- policy_category = POLICY_CATEGORY_DEFAULT; +- state = STATE_POLICY; +- } else if (streq(name, "mandatory")) { +- policy_category = POLICY_CATEGORY_MANDATORY; +- state = STATE_POLICY; +- } else { +- log_error("context= parameter %s unknown for at %s:%u.", name, path, line); +- return -EINVAL; +- } +- } else { +- log_error("Unexpected token (4) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_POLICY_CONSOLE: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- if (streq(name, "true")) { +- policy_category = POLICY_CATEGORY_ON_CONSOLE; +- state = STATE_POLICY; +- } else if (streq(name, "false")) { +- policy_category = POLICY_CATEGORY_NO_CONSOLE; +- state = STATE_POLICY; +- } else { +- log_error("at_console= parameter %s unknown for at %s:%u.", name, path, line); +- return -EINVAL; +- } +- } else { +- log_error("Unexpected token (4.1) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_POLICY_USER: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- free(policy_user); +- policy_user = name; +- name = NULL; +- policy_category = POLICY_CATEGORY_USER; +- state = STATE_POLICY; +- } else { +- log_error("Unexpected token (5) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_POLICY_GROUP: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- free(policy_group); +- policy_group = name; +- name = NULL; +- policy_category = POLICY_CATEGORY_GROUP; +- state = STATE_POLICY; +- } else { +- log_error("Unexpected token (6) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_POLICY_OTHER_ATTRIBUTE: +- +- if (t == XML_ATTRIBUTE_VALUE) +- state = STATE_POLICY; +- else { +- log_error("Unexpected token (7) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY: +- +- assert(i); +- +- if (t == XML_ATTRIBUTE_NAME) { +- PolicyItemClass ic; +- +- if (startswith(name, "send_")) +- ic = POLICY_ITEM_SEND; +- else if (startswith(name, "receive_")) +- ic = POLICY_ITEM_RECV; +- else if (streq(name, "own")) +- ic = POLICY_ITEM_OWN; +- else if (streq(name, "own_prefix")) +- ic = POLICY_ITEM_OWN_PREFIX; +- else if (streq(name, "user")) +- ic = POLICY_ITEM_USER; +- else if (streq(name, "group")) +- ic = POLICY_ITEM_GROUP; +- else if (streq(name, "eavesdrop")) { +- log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); +- state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; +- break; +- } else { +- log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); +- state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; +- break; +- } +- +- if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) { +- log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line); +- return -EINVAL; +- } +- +- i->class = ic; +- +- if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) { +- const char *u; +- +- u = strchr(name, '_'); +- assert(u); +- +- u++; +- +- if (streq(u, "interface")) +- state = STATE_ALLOW_DENY_INTERFACE; +- else if (streq(u, "member")) +- state = STATE_ALLOW_DENY_MEMBER; +- else if (streq(u, "error")) +- state = STATE_ALLOW_DENY_ERROR; +- else if (streq(u, "path")) +- state = STATE_ALLOW_DENY_PATH; +- else if (streq(u, "type")) +- state = STATE_ALLOW_DENY_MESSAGE_TYPE; +- else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) || +- (streq(u, "sender") && ic == POLICY_ITEM_RECV)) +- state = STATE_ALLOW_DENY_NAME; +- else { +- if (streq(u, "requested_reply")) +- log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); +- else +- log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); +- state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; +- break; +- } +- } else +- state = STATE_ALLOW_DENY_NAME; +- +- } else if (t == XML_TAG_CLOSE_EMPTY || +- (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) { +- +- /* If the tag is fully empty so far, we consider it a recv */ +- if (i->class == _POLICY_ITEM_CLASS_UNSET) +- i->class = POLICY_ITEM_RECV; +- +- if (policy_category == POLICY_CATEGORY_DEFAULT) +- item_append(i, &p->default_items); +- else if (policy_category == POLICY_CATEGORY_MANDATORY) +- item_append(i, &p->mandatory_items); +- else if (policy_category == POLICY_CATEGORY_ON_CONSOLE) +- item_append(i, &p->on_console_items); +- else if (policy_category == POLICY_CATEGORY_NO_CONSOLE) +- item_append(i, &p->no_console_items); +- else if (policy_category == POLICY_CATEGORY_USER) { +- const char *u = policy_user; +- +- assert_cc(sizeof(uid_t) == sizeof(uint32_t)); +- +- r = hashmap_ensure_allocated(&p->user_items, NULL); +- if (r < 0) +- return log_oom(); +- +- if (!u) { +- log_error("User policy without name"); +- return -EINVAL; +- } +- +- r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); +- if (r < 0) { +- log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u); +- free(i); +- } else { +- PolicyItem *first; +- +- first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid)); +- item_append(i, &first); +- i->uid_valid = true; +- +- r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first); +- if (r < 0) { +- LIST_REMOVE(items, first, i); +- return log_oom(); +- } +- } +- +- } else if (policy_category == POLICY_CATEGORY_GROUP) { +- const char *g = policy_group; +- +- assert_cc(sizeof(gid_t) == sizeof(uint32_t)); +- +- r = hashmap_ensure_allocated(&p->group_items, NULL); +- if (r < 0) +- return log_oom(); +- +- if (!g) { +- log_error("Group policy without name"); +- return -EINVAL; +- } +- +- r = get_group_creds(&g, &i->gid); +- if (r < 0) { +- log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g); +- free(i); +- } else { +- PolicyItem *first; +- +- first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid)); +- item_append(i, &first); +- i->gid_valid = true; +- +- r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first); +- if (r < 0) { +- LIST_REMOVE(items, first, i); +- return log_oom(); +- } +- } +- } +- +- state = STATE_POLICY; +- i = NULL; +- +- } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { +- log_error("Unexpected token (8) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY_INTERFACE: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- assert(i); +- if (i->interface) { +- log_error("Duplicate interface at %s:%u.", path, line); +- return -EINVAL; +- } +- +- if (!streq(name, "*")) { +- i->interface = name; +- name = NULL; +- } +- state = STATE_ALLOW_DENY; +- } else { +- log_error("Unexpected token (9) at %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY_MEMBER: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- assert(i); +- if (i->member) { +- log_error("Duplicate member in %s:%u.", path, line); +- return -EINVAL; +- } +- +- if (!streq(name, "*")) { +- i->member = name; +- name = NULL; +- } +- state = STATE_ALLOW_DENY; +- } else { +- log_error("Unexpected token (10) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY_ERROR: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- assert(i); +- if (i->error) { +- log_error("Duplicate error in %s:%u.", path, line); +- return -EINVAL; +- } +- +- if (!streq(name, "*")) { +- i->error = name; +- name = NULL; +- } +- state = STATE_ALLOW_DENY; +- } else { +- log_error("Unexpected token (11) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY_PATH: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- assert(i); +- if (i->path) { +- log_error("Duplicate path in %s:%u.", path, line); +- return -EINVAL; +- } +- +- if (!streq(name, "*")) { +- i->path = name; +- name = NULL; +- } +- state = STATE_ALLOW_DENY; +- } else { +- log_error("Unexpected token (12) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY_MESSAGE_TYPE: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- assert(i); +- +- if (i->message_type != 0) { +- log_error("Duplicate message type in %s:%u.", path, line); +- return -EINVAL; +- } +- +- if (!streq(name, "*")) { +- r = bus_message_type_from_string(name, &i->message_type); +- if (r < 0) { +- log_error("Invalid message type in %s:%u.", path, line); +- return -EINVAL; +- } +- } +- +- state = STATE_ALLOW_DENY; +- } else { +- log_error("Unexpected token (13) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY_NAME: +- +- if (t == XML_ATTRIBUTE_VALUE) { +- assert(i); +- if (i->name) { +- log_error("Duplicate name in %s:%u.", path, line); +- return -EINVAL; +- } +- +- switch (i->class) { +- case POLICY_ITEM_USER: +- if (!streq(name, "*")) { +- const char *u = name; +- +- r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); +- if (r < 0) +- log_error_errno(r, "Failed to resolve user %s: %m", name); +- else +- i->uid_valid = true; +- } +- break; +- case POLICY_ITEM_GROUP: +- if (!streq(name, "*")) { +- const char *g = name; +- +- r = get_group_creds(&g, &i->gid); +- if (r < 0) +- log_error_errno(r, "Failed to resolve group %s: %m", name); +- else +- i->gid_valid = true; +- } +- break; +- +- case POLICY_ITEM_SEND: +- case POLICY_ITEM_RECV: +- +- if (streq(name, "*")) { +- free(name); +- name = NULL; +- } +- break; +- +- +- default: +- break; +- } +- +- i->name = name; +- name = NULL; +- +- state = STATE_ALLOW_DENY; +- } else { +- log_error("Unexpected token (14) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_ALLOW_DENY_OTHER_ATTRIBUTE: +- +- if (t == XML_ATTRIBUTE_VALUE) +- state = STATE_ALLOW_DENY; +- else { +- log_error("Unexpected token (15) in %s:%u.", path, line); +- return -EINVAL; +- } +- +- break; +- +- case STATE_OTHER: +- +- if (t == XML_TAG_OPEN) +- n_other++; +- else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) { +- +- if (n_other == 0) +- state = STATE_BUSCONFIG; +- else +- n_other--; +- } +- +- break; +- } +- } +-} +- +-enum { +- DENY, +- ALLOW, +- DUNNO, +-}; +- +-static const char *verdict_to_string(int v) { +- switch (v) { +- +- case DENY: +- return "DENY"; +- case ALLOW: +- return "ALLOW"; +- case DUNNO: +- return "DUNNO"; +- } +- +- return NULL; +-} +- +-struct policy_check_filter { +- PolicyItemClass class; +- uid_t uid; +- gid_t gid; +- int message_type; +- const char *name; +- const char *interface; +- const char *path; +- const char *member; +-}; +- +-static int is_permissive(PolicyItem *i) { +- +- assert(i); +- +- return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY; +-} +- +-static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) { +- +- assert(i); +- assert(filter); +- +- switch (i->class) { +- case POLICY_ITEM_SEND: +- case POLICY_ITEM_RECV: +- +- if (i->name && !streq_ptr(i->name, filter->name)) +- break; +- +- if ((i->message_type != 0) && (i->message_type != filter->message_type)) +- break; +- +- if (i->path && !streq_ptr(i->path, filter->path)) +- break; +- +- if (i->member && !streq_ptr(i->member, filter->member)) +- break; +- +- if (i->interface && !streq_ptr(i->interface, filter->interface)) +- break; +- +- return is_permissive(i); +- +- case POLICY_ITEM_OWN: +- assert(filter->name); +- +- if (streq(i->name, "*") || streq(i->name, filter->name)) +- return is_permissive(i); +- break; +- +- case POLICY_ITEM_OWN_PREFIX: +- assert(filter->name); +- +- if (streq(i->name, "*") || service_name_startswith(filter->name, i->name)) +- return is_permissive(i); +- break; +- +- case POLICY_ITEM_USER: +- if (filter->uid != UID_INVALID) +- if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid))) +- return is_permissive(i); +- break; +- +- case POLICY_ITEM_GROUP: +- if (filter->gid != GID_INVALID) +- if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid))) +- return is_permissive(i); +- break; +- +- case POLICY_ITEM_IGNORE: +- default: +- break; +- } +- +- return DUNNO; +-} +- +-static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) { +- +- PolicyItem *i; +- int verdict = DUNNO; +- +- assert(filter); +- +- /* Check all policies in a set - a broader one might be followed by a more specific one, +- * and the order of rules in policy definitions matters */ +- LIST_FOREACH(items, i, items) { +- int v; +- +- if (i->class != filter->class && +- !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN)) +- continue; +- +- v = check_policy_item(i, filter); +- if (v != DUNNO) +- verdict = v; +- } +- +- return verdict; +-} +- +-static int policy_check(Policy *p, const struct policy_check_filter *filter) { +- +- PolicyItem *items; +- int verdict, v; +- +- assert(p); +- assert(filter); +- +- assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP)); +- +- /* +- * The policy check is implemented by the following logic: +- * +- * 1. Check default items +- * 2. Check group items +- * 3. Check user items +- * 4. Check on/no_console items +- * 5. Check mandatory items +- * +- * Later rules override earlier rules. +- */ +- +- verdict = check_policy_items(p->default_items, filter); +- +- if (filter->gid != GID_INVALID) { +- items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid)); +- if (items) { +- v = check_policy_items(items, filter); +- if (v != DUNNO) +- verdict = v; +- } +- } +- +- if (filter->uid != UID_INVALID) { +- items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid)); +- if (items) { +- v = check_policy_items(items, filter); +- if (v != DUNNO) +- verdict = v; +- } +- } +- +- if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0) +- v = check_policy_items(p->on_console_items, filter); +- else +- v = check_policy_items(p->no_console_items, filter); +- if (v != DUNNO) +- verdict = v; +- +- v = check_policy_items(p->mandatory_items, filter); +- if (v != DUNNO) +- verdict = v; +- +- return verdict; +-} +- +-bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) { +- +- struct policy_check_filter filter = { +- .class = POLICY_ITEM_OWN, +- .uid = uid, +- .gid = gid, +- .name = name, +- }; +- +- int verdict; +- +- assert(p); +- assert(name); +- +- verdict = policy_check(p, &filter); +- +- log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), +- "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s", +- uid, gid, strna(name), strna(verdict_to_string(verdict))); +- +- return verdict == ALLOW; +-} +- +-bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) { +- +- struct policy_check_filter filter = { +- .uid = uid, +- .gid = gid, +- }; +- int verdict; +- +- assert(p); +- +- filter.class = POLICY_ITEM_USER; +- verdict = policy_check(p, &filter); +- +- if (verdict != DENY) { +- int v; +- +- filter.class = POLICY_ITEM_GROUP; +- v = policy_check(p, &filter); +- if (v != DUNNO) +- verdict = v; +- } +- +- log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), +- "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s", +- uid, gid, strna(verdict_to_string(verdict))); +- +- return verdict == ALLOW; +-} +- +-bool policy_check_one_recv(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- const char *name, +- const char *path, +- const char *interface, +- const char *member) { +- +- struct policy_check_filter filter = { +- .class = POLICY_ITEM_RECV, +- .uid = uid, +- .gid = gid, +- .message_type = message_type, +- .name = name, +- .interface = interface, +- .path = path, +- .member = member, +- }; +- +- assert(p); +- +- return policy_check(p, &filter) == ALLOW; +-} +- +-bool policy_check_recv(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- Set *names, +- char **namesv, +- const char *path, +- const char *interface, +- const char *member, +- bool dbus_to_kernel) { +- +- char *n, **nv, *last = NULL; +- bool allow = false; +- Iterator i; +- +- assert(p); +- +- if (set_isempty(names) && strv_isempty(namesv)) { +- allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member); +- } else { +- SET_FOREACH(n, names, i) { +- last = n; +- allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member); +- if (allow) +- break; +- } +- if (!allow) { +- STRV_FOREACH(nv, namesv) { +- last = *nv; +- allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member); +- if (allow) +- break; +- } +- } +- } +- +- log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), +- "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", +- dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), +- strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); +- +- return allow; +-} +- +-bool policy_check_one_send(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- const char *name, +- const char *path, +- const char *interface, +- const char *member) { +- +- struct policy_check_filter filter = { +- .class = POLICY_ITEM_SEND, +- .uid = uid, +- .gid = gid, +- .message_type = message_type, +- .name = name, +- .interface = interface, +- .path = path, +- .member = member, +- }; +- +- assert(p); +- +- return policy_check(p, &filter) == ALLOW; +-} +- +-bool policy_check_send(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- Set *names, +- char **namesv, +- const char *path, +- const char *interface, +- const char *member, +- bool dbus_to_kernel, +- char **out_used_name) { +- +- char *n, **nv, *last = NULL; +- bool allow = false; +- Iterator i; +- +- assert(p); +- +- if (set_isempty(names) && strv_isempty(namesv)) { +- allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member); +- } else { +- SET_FOREACH(n, names, i) { +- last = n; +- allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member); +- if (allow) +- break; +- } +- if (!allow) { +- STRV_FOREACH(nv, namesv) { +- last = *nv; +- allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member); +- if (allow) +- break; +- } +- } +- } +- +- if (out_used_name) +- *out_used_name = last; +- +- log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), +- "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", +- dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), +- strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); +- +- return allow; +-} +- +-int policy_load(Policy *p, char **files) { +- char **i; +- int r; +- +- assert(p); +- +- STRV_FOREACH(i, files) { +- +- r = file_load(p, *i); +- if (r == -EISDIR) { +- _cleanup_strv_free_ char **l = NULL; +- char **j; +- +- r = conf_files_list(&l, ".conf", NULL, *i, NULL); +- if (r < 0) +- return log_error_errno(r, "Failed to get configuration file list: %m"); +- +- STRV_FOREACH(j, l) +- file_load(p, *j); +- } +- +- /* We ignore all errors but EISDIR, and just proceed. */ +- } +- +- return 0; +-} +- +-void policy_free(Policy *p) { +- PolicyItem *i, *first; +- +- if (!p) +- return; +- +- while ((i = p->default_items)) { +- LIST_REMOVE(items, p->default_items, i); +- policy_item_free(i); +- } +- +- while ((i = p->mandatory_items)) { +- LIST_REMOVE(items, p->mandatory_items, i); +- policy_item_free(i); +- } +- +- while ((i = p->on_console_items)) { +- LIST_REMOVE(items, p->on_console_items, i); +- policy_item_free(i); +- } +- +- while ((i = p->no_console_items)) { +- LIST_REMOVE(items, p->no_console_items, i); +- policy_item_free(i); +- } +- +- while ((first = hashmap_steal_first(p->user_items))) { +- +- while ((i = first)) { +- LIST_REMOVE(items, first, i); +- policy_item_free(i); +- } +- } +- +- while ((first = hashmap_steal_first(p->group_items))) { +- +- while ((i = first)) { +- LIST_REMOVE(items, first, i); +- policy_item_free(i); +- } +- } +- +- hashmap_free(p->user_items); +- hashmap_free(p->group_items); +- +- p->user_items = p->group_items = NULL; +-} +- +-static void dump_items(PolicyItem *items, const char *prefix) { +- +- PolicyItem *i; +- +- if (!items) +- return; +- +- if (!prefix) +- prefix = ""; +- +- LIST_FOREACH(items, i, items) { +- +- printf("%sType: %s\n" +- "%sClass: %s\n", +- prefix, policy_item_type_to_string(i->type), +- prefix, policy_item_class_to_string(i->class)); +- +- if (i->interface) +- printf("%sInterface: %s\n", +- prefix, i->interface); +- +- if (i->member) +- printf("%sMember: %s\n", +- prefix, i->member); +- +- if (i->error) +- printf("%sError: %s\n", +- prefix, i->error); +- +- if (i->path) +- printf("%sPath: %s\n", +- prefix, i->path); +- +- if (i->name) +- printf("%sName: %s\n", +- prefix, i->name); +- +- if (i->message_type != 0) +- printf("%sMessage Type: %s\n", +- prefix, bus_message_type_to_string(i->message_type)); +- +- if (i->uid_valid) { +- _cleanup_free_ char *user; +- +- user = uid_to_name(i->uid); +- +- printf("%sUser: %s ("UID_FMT")\n", +- prefix, strna(user), i->uid); +- } +- +- if (i->gid_valid) { +- _cleanup_free_ char *group; +- +- group = gid_to_name(i->gid); +- +- printf("%sGroup: %s ("GID_FMT")\n", +- prefix, strna(group), i->gid); +- } +- printf("%s-\n", prefix); +- } +-} +- +-static void dump_hashmap_items(Hashmap *h) { +- PolicyItem *i; +- Iterator j; +- void *k; +- +- HASHMAP_FOREACH_KEY(i, k, h, j) { +- printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k)); +- dump_items(i, "\t\t"); +- } +-} +- +-void policy_dump(Policy *p) { +- +- printf("%s Default Items:\n", draw_special_char(DRAW_ARROW)); +- dump_items(p->default_items, "\t"); +- +- printf("%s Group Items:\n", draw_special_char(DRAW_ARROW)); +- dump_hashmap_items(p->group_items); +- +- printf("%s User Items:\n", draw_special_char(DRAW_ARROW)); +- dump_hashmap_items(p->user_items); +- +- printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW)); +- dump_items(p->on_console_items, "\t"); +- +- printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW)); +- dump_items(p->no_console_items, "\t"); +- +- printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW)); +- dump_items(p->mandatory_items, "\t"); +- +- fflush(stdout); +-} +- +-int shared_policy_new(SharedPolicy **out) { +- SharedPolicy *sp; +- int r; +- +- sp = new0(SharedPolicy, 1); +- if (!sp) +- return log_oom(); +- +- r = pthread_mutex_init(&sp->lock, NULL); +- if (r < 0) { +- log_error_errno(r, "Cannot initialize shared policy mutex: %m"); +- goto exit_free; +- } +- +- r = pthread_rwlock_init(&sp->rwlock, NULL); +- if (r < 0) { +- log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); +- goto exit_mutex; +- } +- +- *out = sp; +- sp = NULL; +- return 0; +- +- /* pthread lock destruction is not fail-safe... meh! */ +-exit_mutex: +- pthread_mutex_destroy(&sp->lock); +-exit_free: +- free(sp); +- return r; +-} +- +-SharedPolicy *shared_policy_free(SharedPolicy *sp) { +- if (!sp) +- return NULL; +- +- policy_free(sp->policy); +- pthread_rwlock_destroy(&sp->rwlock); +- pthread_mutex_destroy(&sp->lock); +- strv_free(sp->configuration); +- free(sp); +- +- return NULL; +-} +- +-static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) { +- Policy old, buffer = {}; +- bool free_old; +- int r; +- +- assert(sp); +- +- r = policy_load(&buffer, configuration); +- if (r < 0) +- return log_error_errno(r, "Failed to load policy: %m"); +- +- log_debug("Reloading configuration"); +- /* policy_dump(&buffer); */ +- +- pthread_rwlock_wrlock(&sp->rwlock); +- memcpy(&old, &sp->buffer, sizeof(old)); +- memcpy(&sp->buffer, &buffer, sizeof(buffer)); +- free_old = !!sp->policy; +- sp->policy = &sp->buffer; +- pthread_rwlock_unlock(&sp->rwlock); +- +- if (free_old) +- policy_free(&old); +- +- return 0; +-} +- +-int shared_policy_reload(SharedPolicy *sp) { +- int r; +- +- assert(sp); +- +- pthread_mutex_lock(&sp->lock); +- r = shared_policy_reload_unlocked(sp, sp->configuration); +- pthread_mutex_unlock(&sp->lock); +- +- return r; +-} +- +-int shared_policy_preload(SharedPolicy *sp, char **configuration) { +- _cleanup_strv_free_ char **conf = NULL; +- int r = 0; +- +- assert(sp); +- +- conf = strv_copy(configuration); +- if (!conf) +- return log_oom(); +- +- pthread_mutex_lock(&sp->lock); +- if (!sp->policy) { +- r = shared_policy_reload_unlocked(sp, conf); +- if (r >= 0) { +- sp->configuration = conf; +- conf = NULL; +- } +- } +- pthread_mutex_unlock(&sp->lock); +- +- return r; +-} +- +-Policy *shared_policy_acquire(SharedPolicy *sp) { +- assert(sp); +- +- pthread_rwlock_rdlock(&sp->rwlock); +- if (sp->policy) +- return sp->policy; +- pthread_rwlock_unlock(&sp->rwlock); +- +- return NULL; +-} +- +-void shared_policy_release(SharedPolicy *sp, Policy *p) { +- assert(sp); +- assert(!p || sp->policy == p); +- +- if (p) +- pthread_rwlock_unlock(&sp->rwlock); +-} +- +-static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = { +- [_POLICY_ITEM_TYPE_UNSET] = "unset", +- [POLICY_ITEM_ALLOW] = "allow", +- [POLICY_ITEM_DENY] = "deny", +-}; +-DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType); +- +-static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = { +- [_POLICY_ITEM_CLASS_UNSET] = "unset", +- [POLICY_ITEM_SEND] = "send", +- [POLICY_ITEM_RECV] = "recv", +- [POLICY_ITEM_OWN] = "own", +- [POLICY_ITEM_OWN_PREFIX] = "own-prefix", +- [POLICY_ITEM_USER] = "user", +- [POLICY_ITEM_GROUP] = "group", +- [POLICY_ITEM_IGNORE] = "ignore", +-}; +-DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass); +diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h +deleted file mode 100644 +index f2ec1bbea..000000000 +--- a/src/bus-proxyd/bus-xml-policy.h ++++ /dev/null +@@ -1,151 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-#pragma once +- +-/*** +- This file is part of systemd. +- +- Copyright 2013 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 "list.h" +-#include "hashmap.h" +-#include "set.h" +- +-typedef enum PolicyItemType { +- _POLICY_ITEM_TYPE_UNSET = 0, +- POLICY_ITEM_ALLOW, +- POLICY_ITEM_DENY, +- _POLICY_ITEM_TYPE_MAX, +- _POLICY_ITEM_TYPE_INVALID = -1, +-} PolicyItemType; +- +-typedef enum PolicyItemClass { +- _POLICY_ITEM_CLASS_UNSET = 0, +- POLICY_ITEM_SEND, +- POLICY_ITEM_RECV, +- POLICY_ITEM_OWN, +- POLICY_ITEM_OWN_PREFIX, +- POLICY_ITEM_USER, +- POLICY_ITEM_GROUP, +- POLICY_ITEM_IGNORE, +- _POLICY_ITEM_CLASS_MAX, +- _POLICY_ITEM_CLASS_INVALID = -1, +-} PolicyItemClass; +- +-typedef struct PolicyItem PolicyItem; +- +-struct PolicyItem { +- PolicyItemType type; +- PolicyItemClass class; +- char *interface; +- char *member; +- char *error; +- char *path; +- char *name; +- uint8_t message_type; +- uid_t uid; +- gid_t gid; +- +- bool uid_valid, gid_valid; +- +- LIST_FIELDS(PolicyItem, items); +-}; +- +-typedef struct Policy { +- LIST_HEAD(PolicyItem, default_items); +- LIST_HEAD(PolicyItem, mandatory_items); +- LIST_HEAD(PolicyItem, on_console_items); +- LIST_HEAD(PolicyItem, no_console_items); +- Hashmap *user_items; +- Hashmap *group_items; +-} Policy; +- +-typedef struct SharedPolicy { +- char **configuration; +- pthread_mutex_t lock; +- pthread_rwlock_t rwlock; +- Policy buffer; +- Policy *policy; +-} SharedPolicy; +- +-/* policy */ +- +-int policy_load(Policy *p, char **files); +-void policy_free(Policy *p); +- +-bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name); +-bool policy_check_hello(Policy *p, uid_t uid, gid_t gid); +-bool policy_check_one_recv(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- const char *name, +- const char *path, +- const char *interface, +- const char *member); +-bool policy_check_recv(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- Set *names, +- char **namesv, +- const char *path, +- const char *interface, +- const char *member, +- bool dbus_to_kernel); +-bool policy_check_one_send(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- const char *name, +- const char *path, +- const char *interface, +- const char *member); +-bool policy_check_send(Policy *p, +- uid_t uid, +- gid_t gid, +- int message_type, +- Set *names, +- char **namesv, +- const char *path, +- const char *interface, +- const char *member, +- bool dbus_to_kernel, +- char **out_used_name); +- +-void policy_dump(Policy *p); +- +-const char* policy_item_type_to_string(PolicyItemType t) _const_; +-PolicyItemType policy_item_type_from_string(const char *s) _pure_; +- +-const char* policy_item_class_to_string(PolicyItemClass t) _const_; +-PolicyItemClass policy_item_class_from_string(const char *s) _pure_; +- +-/* shared policy */ +- +-int shared_policy_new(SharedPolicy **out); +-SharedPolicy *shared_policy_free(SharedPolicy *sp); +- +-int shared_policy_reload(SharedPolicy *sp); +-int shared_policy_preload(SharedPolicy *sp, char **configuration); +-Policy *shared_policy_acquire(SharedPolicy *sp); +-void shared_policy_release(SharedPolicy *sp, Policy *p); +- +-DEFINE_TRIVIAL_CLEANUP_FUNC(SharedPolicy*, shared_policy_free); +diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c +deleted file mode 100644 +index bc2c0c86f..000000000 +--- a/src/bus-proxyd/driver.c ++++ /dev/null +@@ -1,608 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2010 Lennart Poettering +- Copyright 2013 Daniel Mack +- Copyright 2014 Kay Sievers +- +- 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 +- +-#include "log.h" +-#include "util.h" +-#include "sd-bus.h" +-#include "bus-internal.h" +-#include "bus-message.h" +-#include "bus-util.h" +-#include "build.h" +-#include "strv.h" +-#include "def.h" +-#include "capability.h" +-#include "bus-control.h" +-#include "set.h" +-#include "driver.h" +-#include "synthesize.h" +- +-static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { +- _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; +- int r; +- +- assert(bus); +- assert(name); +- assert(_creds); +- +- r = sd_bus_get_name_creds(bus, name, mask, &c); +- if (r == -ESRCH || r == -ENXIO) +- return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name); +- if (r < 0) +- return r; +- +- if ((c->mask & mask) != mask) +- return -ENOTSUP; +- +- *_creds = c; +- c = NULL; +- +- return 0; +-} +- +-static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { +- const char *name; +- int r; +- +- assert(bus); +- assert(m); +- assert(_creds); +- +- r = sd_bus_message_read(m, "s", &name); +- if (r < 0) +- return r; +- +- return get_creds_by_name(bus, name, mask, _creds, error); +-} +- +-int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) { +- int r; +- +- assert(a); +- assert(b); +- assert(m); +- +- if (!a->is_kernel) +- return 0; +- +- if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus")) +- return 0; +- +- /* The "Hello()" call is is handled in process_hello() */ +- +- if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { +- +- if (!sd_bus_message_has_signature(m, "")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- return synthetic_reply_method_return(m, "s", +- "\n" +- "\n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- "\n"); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) { +- const char *match; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "s", &match); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_add_match(a, NULL, match, NULL, NULL); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- return synthetic_reply_method_return(m, NULL); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) { +- const char *match; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "s", &match); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = bus_remove_match_by_string(a, match, NULL, NULL); +- if (r == 0) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found")); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- return synthetic_reply_method_return(m, NULL); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) { +- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, &error); +- +- return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label)); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) { +- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, &error); +- +- return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) { +- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, &error); +- +- return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) { +- sd_id128_t server_id; +- char buf[SD_ID128_STRING_MAX]; +- +- if (!sd_bus_message_has_signature(m, "")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_get_bus_id(a, &server_id); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf)); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) { +- const char *name; +- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "s", &name); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- if (streq(name, "org.freedesktop.DBus")) +- return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus"); +- +- r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, &error); +- +- return synthetic_reply_method_return(m, "s", creds->unique_name); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) { +- _cleanup_strv_free_ char **names = NULL; +- +- if (!sd_bus_message_has_signature(m, "")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_list_names(a, NULL, &names); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- /* Let's sort the names list to make it stable */ +- strv_sort(names); +- +- return synthetic_reply_method_return_strv(m, names); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) { +- _cleanup_strv_free_ char **names = NULL; +- +- if (!sd_bus_message_has_signature(m, "")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_list_names(a, &names, NULL); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = strv_extend(&names, "org.freedesktop.DBus"); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- /* Let's sort the names list to make it stable */ +- strv_sort(names); +- +- return synthetic_reply_method_return_strv(m, names); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) { +- struct kdbus_cmd_list cmd = { +- .flags = KDBUS_LIST_QUEUED, +- .size = sizeof(cmd), +- }; +- struct kdbus_info *name_list, *name; +- _cleanup_strv_free_ char **owners = NULL; +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- char *arg0; +- int err = 0; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "s", &arg0); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_get_name_creds(a, arg0, 0, NULL); +- if (r == -ESRCH || r == -ENXIO) { +- sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0); +- return synthetic_reply_method_errno(m, r, &error); +- } +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd); +- if (r < 0) +- return synthetic_reply_method_errno(m, -errno, NULL); +- +- name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset); +- +- KDBUS_FOREACH(name, name_list, cmd.list_size) { +- const char *entry_name = NULL; +- struct kdbus_item *item; +- char *n; +- +- KDBUS_ITEM_FOREACH(item, name, items) +- if (item->type == KDBUS_ITEM_OWNED_NAME) +- entry_name = item->name.name; +- +- if (!streq_ptr(entry_name, arg0)) +- continue; +- +- if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) { +- err = -ENOMEM; +- break; +- } +- +- r = strv_consume(&owners, n); +- if (r < 0) { +- err = r; +- break; +- } +- } +- +- r = bus_kernel_cmd_free(a, cmd.offset); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- if (err < 0) +- return synthetic_reply_method_errno(m, err, NULL); +- +- return synthetic_reply_method_return_strv(m, owners); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) { +- const char *name; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "s", &name); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- if (streq(name, "org.freedesktop.DBus")) +- return synthetic_reply_method_return(m, "b", true); +- +- r = sd_bus_get_name_creds(a, name, 0, NULL); +- if (r < 0 && r != -ESRCH && r != -ENXIO) +- return synthetic_reply_method_errno(m, r, NULL); +- +- return synthetic_reply_method_return(m, "b", r >= 0); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) { +- const char *name; +- +- if (!sd_bus_message_has_signature(m, "s")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "s", &name); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_release_name(a, name); +- if (r < 0) { +- if (r == -ESRCH) +- return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT); +- if (r == -EADDRINUSE) +- return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER); +- +- return synthetic_reply_method_errno(m, r, NULL); +- } +- +- set_remove(owned_names, (char*) name); +- +- return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) { +- if (!sd_bus_message_has_signature(m, "")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = shared_policy_reload(sp); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- return synthetic_reply_method_return(m, NULL); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) { +- const char *name; +- uint32_t flags, param; +- bool in_queue; +- +- if (!sd_bus_message_has_signature(m, "su")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "su", &name, &flags); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- if (sp) { +- Policy *policy; +- bool denied; +- +- policy = shared_policy_acquire(sp); +- denied = !policy_check_own(policy, ucred->uid, ucred->gid, name); +- shared_policy_release(sp, policy); +- if (denied) +- return synthetic_reply_method_errno(m, -EPERM, NULL); +- } +- +- if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0) +- return synthetic_reply_method_errno(m, -EINVAL, NULL); +- +- param = 0; +- if (flags & BUS_NAME_ALLOW_REPLACEMENT) +- param |= SD_BUS_NAME_ALLOW_REPLACEMENT; +- if (flags & BUS_NAME_REPLACE_EXISTING) +- param |= SD_BUS_NAME_REPLACE_EXISTING; +- if (!(flags & BUS_NAME_DO_NOT_QUEUE)) +- param |= SD_BUS_NAME_QUEUE; +- +- r = set_put_strdup(owned_names, name); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_request_name(a, name, param); +- if (r < 0) { +- if (r == -EALREADY) +- return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER); +- +- set_remove(owned_names, (char*) name); +- +- if (r == -EEXIST) +- return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS); +- return synthetic_reply_method_errno(m, r, NULL); +- } +- +- in_queue = (r == 0); +- +- if (in_queue) +- return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE); +- +- return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) { +- _cleanup_bus_message_unref_ sd_bus_message *msg = NULL; +- const char *name; +- uint32_t flags; +- +- if (!sd_bus_message_has_signature(m, "su")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_read(m, "su", &name, &flags); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- if (flags != 0) +- return synthetic_reply_method_errno(m, -EINVAL, NULL); +- +- r = sd_bus_get_name_creds(a, name, 0, NULL); +- if (r >= 0 || streq(name, "org.freedesktop.DBus")) +- return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING); +- if (r != -ESRCH) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_message_new_method_call( +- a, +- &msg, +- name, +- "/", +- "org.freedesktop.DBus.Peer", +- "Ping"); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_send(a, msg, NULL); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS); +- +- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) { +- _cleanup_bus_message_unref_ sd_bus_message *msg = NULL; +- _cleanup_strv_free_ char **args = NULL; +- +- if (!sd_bus_message_has_signature(m, "a{ss}")) +- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); +- +- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}"); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) { +- _cleanup_free_ char *s = NULL; +- const char *key; +- const char *value; +- +- r = sd_bus_message_read(m, "ss", &key, &value); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- s = strjoin(key, "=", value, NULL); +- if (!s) +- return synthetic_reply_method_errno(m, -ENOMEM, NULL); +- +- r = strv_extend(&args, s); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_message_exit_container(m); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- } +- +- r = sd_bus_message_exit_container(m); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- if (!args) +- return synthetic_reply_method_errno(m, -EINVAL, NULL); +- +- r = sd_bus_message_new_method_call( +- a, +- &msg, +- "org.freedesktop.systemd1", +- "/org/freedesktop/systemd1", +- "org.freedesktop.systemd1.Manager", +- "SetEnvironment"); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_message_append_strv(msg, args); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- r = sd_bus_call(a, msg, 0, NULL, NULL); +- if (r < 0) +- return synthetic_reply_method_errno(m, r, NULL); +- +- return synthetic_reply_method_return(m, NULL); +- +- } else { +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- +- r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member); +- +- return synthetic_reply_method_errno(m, r, &error); +- } +-} +diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h +deleted file mode 100644 +index b8cedf5ce..000000000 +--- a/src/bus-proxyd/driver.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-#pragma once +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 Lennart Poettering +- +- systemd is free software; you can redistribute it and/or modify it +- under the terms of the GNU Lesser General Public License as published by +- the Free Software Foundation; either version 2.1 of the License, or +- (at your option) any later version. +- +- systemd is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public License +- along with systemd; If not, see . +-***/ +- +-#include "sd-bus.h" +-#include "bus-xml-policy.h" +- +-int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names); +diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c +deleted file mode 100644 +index e13cf5e2e..000000000 +--- a/src/bus-proxyd/proxy.c ++++ /dev/null +@@ -1,864 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2010 Lennart Poettering +- Copyright 2013 Daniel Mack +- Copyright 2014 Kay Sievers +- Copyright 2014 David Herrmann +- +- 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 +-#include +-#include +-#include +-#include +-#include +- +-#include "log.h" +-#include "util.h" +-#include "socket-util.h" +-#include "sd-daemon.h" +-#include "sd-bus.h" +-#include "bus-internal.h" +-#include "bus-message.h" +-#include "bus-util.h" +-#include "build.h" +-#include "strv.h" +-#include "def.h" +-#include "capability.h" +-#include "bus-control.h" +-#include "smack-util.h" +-#include "set.h" +-#include "bus-xml-policy.h" +-#include "driver.h" +-#include "proxy.h" +-#include "synthesize.h" +- +-static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) { +- _cleanup_bus_close_unref_ sd_bus *b = NULL; +- int r; +- +- r = sd_bus_new(&b); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate bus: %m"); +- +- r = sd_bus_set_description(b, "sd-proxy"); +- if (r < 0) +- return log_error_errno(r, "Failed to set bus name: %m"); +- +- r = sd_bus_set_address(b, destination); +- if (r < 0) +- return log_error_errno(r, "Failed to set address to connect to: %m"); +- +- r = sd_bus_negotiate_fds(b, negotiate_fds); +- if (r < 0) +- return log_error_errno(r, "Failed to set FD negotiation: %m"); +- +- r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT); +- if (r < 0) +- return log_error_errno(r, "Failed to set credential negotiation: %m"); +- +- if (p->local_creds.pid > 0) { +- b->fake_pids.pid = p->local_creds.pid; +- b->fake_pids_valid = true; +- +- b->fake_creds.uid = UID_INVALID; +- b->fake_creds.euid = p->local_creds.uid; +- b->fake_creds.suid = UID_INVALID; +- b->fake_creds.fsuid = UID_INVALID; +- b->fake_creds.gid = GID_INVALID; +- b->fake_creds.egid = p->local_creds.gid; +- b->fake_creds.sgid = GID_INVALID; +- b->fake_creds.fsgid = GID_INVALID; +- b->fake_creds_valid = true; +- } +- +- if (local_sec) { +- b->fake_label = strdup(local_sec); +- if (!b->fake_label) +- return log_oom(); +- } +- +- b->manual_peer_interface = true; +- +- r = sd_bus_start(b); +- if (r < 0) +- return log_error_errno(r, "Failed to start bus client: %m"); +- +- p->destination_bus = b; +- b = NULL; +- return 0; +-} +- +-static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) { +- _cleanup_bus_close_unref_ sd_bus *b = NULL; +- sd_id128_t server_id; +- int r; +- +- r = sd_bus_new(&b); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate bus: %m"); +- +- r = sd_bus_set_fd(b, in_fd, out_fd); +- if (r < 0) +- return log_error_errno(r, "Failed to set fds: %m"); +- +- r = sd_bus_get_bus_id(p->destination_bus, &server_id); +- if (r < 0) +- return log_error_errno(r, "Failed to get server ID: %m"); +- +- r = sd_bus_set_server(b, 1, server_id); +- if (r < 0) +- return log_error_errno(r, "Failed to set server mode: %m"); +- +- r = sd_bus_negotiate_fds(b, negotiate_fds); +- if (r < 0) +- return log_error_errno(r, "Failed to set FD negotiation: %m"); +- +- r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT); +- if (r < 0) +- return log_error_errno(r, "Failed to set credential negotiation: %m"); +- +- r = sd_bus_set_anonymous(b, true); +- if (r < 0) +- return log_error_errno(r, "Failed to set anonymous authentication: %m"); +- +- b->manual_peer_interface = true; +- +- r = sd_bus_start(b); +- if (r < 0) +- return log_error_errno(r, "Failed to start bus client: %m"); +- +- p->local_bus = b; +- b = NULL; +- return 0; +-} +- +-static int proxy_prepare_matches(Proxy *p) { +- _cleanup_free_ char *match = NULL; +- const char *unique; +- int r; +- +- if (!p->destination_bus->is_kernel) +- return 0; +- +- r = sd_bus_get_unique_name(p->destination_bus, &unique); +- if (r < 0) +- return log_error_errno(r, "Failed to get unique name: %m"); +- +- match = strjoin("type='signal'," +- "sender='org.freedesktop.DBus'," +- "path='/org/freedesktop/DBus'," +- "interface='org.freedesktop.DBus'," +- "member='NameOwnerChanged'," +- "arg1='", +- unique, +- "'", +- NULL); +- if (!match) +- return log_oom(); +- +- r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL); +- if (r < 0) +- return log_error_errno(r, "Failed to add match for NameLost: %m"); +- +- free(match); +- match = strjoin("type='signal'," +- "sender='org.freedesktop.DBus'," +- "path='/org/freedesktop/DBus'," +- "interface='org.freedesktop.DBus'," +- "member='NameOwnerChanged'," +- "arg2='", +- unique, +- "'", +- NULL); +- if (!match) +- return log_oom(); +- +- r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL); +- if (r < 0) +- return log_error_errno(r, "Failed to add match for NameAcquired: %m"); +- +- return 0; +-} +- +-int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { +- _cleanup_(proxy_freep) Proxy *p = NULL; +- _cleanup_free_ char *local_sec = NULL; +- bool is_unix; +- int r; +- +- p = new0(Proxy, 1); +- if (!p) +- return log_oom(); +- +- p->local_in = in_fd; +- p->local_out = out_fd; +- +- p->owned_names = set_new(&string_hash_ops); +- if (!p->owned_names) +- return log_oom(); +- +- is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && +- sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; +- +- if (is_unix) { +- (void) getpeercred(in_fd, &p->local_creds); +- (void) getpeersec(in_fd, &local_sec); +- } +- +- r = proxy_create_destination(p, destination, local_sec, is_unix); +- if (r < 0) +- return r; +- +- r = proxy_create_local(p, in_fd, out_fd, is_unix); +- if (r < 0) +- return r; +- +- r = proxy_prepare_matches(p); +- if (r < 0) +- return r; +- +- *out = p; +- p = NULL; +- return 0; +-} +- +-Proxy *proxy_free(Proxy *p) { +- if (!p) +- return NULL; +- +- sd_bus_close_unrefp(&p->local_bus); +- sd_bus_close_unrefp(&p->destination_bus); +- set_free_free(p->owned_names); +- free(p); +- +- return NULL; +-} +- +-int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) { +- _cleanup_strv_free_ char **strv = NULL; +- Policy *policy; +- int r; +- +- assert(p); +- assert(sp); +- +- /* no need to load legacy policy if destination is not kdbus */ +- if (!p->destination_bus->is_kernel) +- return 0; +- +- p->policy = sp; +- +- policy = shared_policy_acquire(sp); +- if (policy) { +- /* policy already pre-loaded */ +- shared_policy_release(sp, policy); +- return 0; +- } +- +- if (!configuration) { +- const char *scope; +- +- r = sd_bus_get_scope(p->destination_bus, &scope); +- if (r < 0) +- return log_error_errno(r, "Couldn't determine bus scope: %m"); +- +- if (streq(scope, "system")) +- strv = strv_new("/etc/dbus-1/system.conf", +- "/etc/dbus-1/system.d/", +- "/etc/dbus-1/system-local.conf", +- NULL); +- else if (streq(scope, "user")) +- strv = strv_new("/etc/dbus-1/session.conf", +- "/etc/dbus-1/session.d/", +- "/etc/dbus-1/session-local.conf", +- NULL); +- else +- return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope); +- +- if (!strv) +- return log_oom(); +- +- configuration = strv; +- } +- +- return shared_policy_preload(sp, configuration); +-} +- +-int proxy_hello_policy(Proxy *p, uid_t original_uid) { +- Policy *policy; +- int r = 0; +- +- assert(p); +- +- if (!p->policy) +- return 0; +- +- policy = shared_policy_acquire(p->policy); +- +- if (p->local_creds.uid == original_uid) +- log_debug("Permitting access, since bus owner matches bus client."); +- else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid)) +- log_debug("Permitting access due to XML policy."); +- else +- r = log_error_errno(EPERM, "Policy denied connection."); +- +- shared_policy_release(p->policy, policy); +- +- return r; +-} +- +-static int proxy_wait(Proxy *p) { +- uint64_t timeout_destination, timeout_local, t; +- int events_destination, events_local, fd; +- struct timespec _ts, *ts; +- struct pollfd *pollfd; +- int r; +- +- assert(p); +- +- fd = sd_bus_get_fd(p->destination_bus); +- if (fd < 0) +- return log_error_errno(fd, "Failed to get fd: %m"); +- +- events_destination = sd_bus_get_events(p->destination_bus); +- if (events_destination < 0) +- return log_error_errno(events_destination, "Failed to get events mask: %m"); +- +- r = sd_bus_get_timeout(p->destination_bus, &timeout_destination); +- if (r < 0) +- return log_error_errno(r, "Failed to get timeout: %m"); +- +- events_local = sd_bus_get_events(p->local_bus); +- if (events_local < 0) +- return log_error_errno(events_local, "Failed to get events mask: %m"); +- +- r = sd_bus_get_timeout(p->local_bus, &timeout_local); +- if (r < 0) +- return log_error_errno(r, "Failed to get timeout: %m"); +- +- t = timeout_destination; +- if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination)) +- t = timeout_local; +- +- if (t == (uint64_t) -1) +- ts = NULL; +- else { +- usec_t nw; +- +- nw = now(CLOCK_MONOTONIC); +- if (t > nw) +- t -= nw; +- else +- t = 0; +- +- ts = timespec_store(&_ts, t); +- } +- +- pollfd = (struct pollfd[3]) { +- { .fd = fd, .events = events_destination, }, +- { .fd = p->local_in, .events = events_local & POLLIN, }, +- { .fd = p->local_out, .events = events_local & POLLOUT, }, +- }; +- +- r = ppoll(pollfd, 3, ts, NULL); +- if (r < 0) +- return log_error_errno(errno, "ppoll() failed: %m"); +- +- return 0; +-} +- +-static int handle_policy_error(sd_bus_message *m, int r) { +- if (r == -ESRCH || r == -ENXIO) +- return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination); +- +- return r; +-} +- +-static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) { +- int r; +- +- assert(from); +- assert(to); +- assert(m); +- +- if (!policy) +- return 0; +- +- /* +- * dbus-1 distinguishes expected and non-expected replies by tracking +- * method-calls and timeouts. By default, DENY rules are *NEVER* applied +- * on expected replies, unless explicitly specified. But we dont track +- * method-calls, thus, we cannot know whether a reply is expected. +- * Fortunately, the kdbus forbids non-expected replies, so we can safely +- * ignore any policy on those and let the kernel deal with it. +- * +- * TODO: To be correct, we should only ignore policy-tags that are +- * applied on non-expected replies. However, so far we don't parse those +- * tags so we let everything pass. I haven't seen a DENY policy tag on +- * expected-replies, ever, so don't bother.. +- */ +- if (m->reply_cookie > 0) +- return 0; +- +- if (from->is_kernel) { +- uid_t sender_uid = UID_INVALID; +- gid_t sender_gid = GID_INVALID; +- char **sender_names = NULL; +- +- /* Driver messages are always OK */ +- if (streq_ptr(m->sender, "org.freedesktop.DBus")) +- return 0; +- +- /* The message came from the kernel, and is sent to our legacy client. */ +- (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names); +- +- (void) sd_bus_creds_get_euid(&m->creds, &sender_uid); +- (void) sd_bus_creds_get_egid(&m->creds, &sender_gid); +- +- if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) { +- _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL; +- +- /* If the message came from another legacy +- * client, then the message creds will be +- * missing, simply because on legacy clients +- * per-message creds were unknown. In this +- * case, query the creds of the peer +- * instead. */ +- +- r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds); +- if (r < 0) +- return handle_policy_error(m, r); +- +- (void) sd_bus_creds_get_euid(sender_creds, &sender_uid); +- (void) sd_bus_creds_get_egid(sender_creds, &sender_gid); +- } +- +- /* First check whether the sender can send the message to our name */ +- if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) && +- policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false)) +- return 0; +- +- /* Return an error back to the caller */ +- if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) +- return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy."); +- +- /* Return 1, indicating that the message shall not be processed any further */ +- return 1; +- } +- +- if (to->is_kernel) { +- _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL; +- uid_t destination_uid = UID_INVALID; +- gid_t destination_gid = GID_INVALID; +- const char *destination_unique = NULL; +- char **destination_names = NULL; +- char *n; +- +- /* Driver messages are always OK */ +- if (streq_ptr(m->destination, "org.freedesktop.DBus")) +- return 0; +- +- /* The message came from the legacy client, and is sent to kdbus. */ +- if (m->destination) { +- r = bus_get_name_creds_kdbus(to, m->destination, +- SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME| +- SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID, +- true, &destination_creds); +- if (r < 0) +- return handle_policy_error(m, r); +- +- r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique); +- if (r < 0) +- return handle_policy_error(m, r); +- +- (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names); +- +- (void) sd_bus_creds_get_euid(destination_creds, &destination_uid); +- (void) sd_bus_creds_get_egid(destination_creds, &destination_gid); +- } +- +- /* First check if we (the sender) can send to this name */ +- if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) { +- if (n) { +- /* If we made a receiver decision, then remember which +- * name's policy we used, and to which unique ID it +- * mapped when we made the decision. Then, let's pass +- * this to the kernel when sending the message, so that +- * it refuses the operation should the name and unique +- * ID not map to each other anymore. */ +- +- r = free_and_strdup(&m->destination_ptr, n); +- if (r < 0) +- return r; +- +- r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id); +- if (r < 0) +- return r; +- } +- +- if (sd_bus_message_is_signal(m, NULL, NULL)) { +- /* If we forward a signal from dbus-1 to kdbus, +- * we have no idea who the recipient is. +- * Therefore, we cannot apply any dbus-1 +- * receiver policies that match on receiver +- * credentials. We know sd-bus always sets +- * KDBUS_MSG_SIGNAL, so the kernel applies +- * receiver policies to the message. Therefore, +- * skip policy checks in this case. */ +- return 0; +- } else if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) { +- return 0; +- } +- } +- +- /* Return an error back to the caller */ +- if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) +- return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy."); +- +- /* Return 1, indicating that the message shall not be processed any further */ +- return 1; +- } +- +- return 0; +-} +- +-static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) { +- Policy *policy; +- int r; +- +- assert(sp); +- +- policy = shared_policy_acquire(sp); +- r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names); +- shared_policy_release(sp, policy); +- +- return r; +-} +- +-static int process_hello(Proxy *p, sd_bus_message *m) { +- _cleanup_bus_message_unref_ sd_bus_message *n = NULL; +- bool is_hello; +- int r; +- +- assert(p); +- assert(m); +- +- /* As reaction to hello we need to respond with two messages: +- * the callback reply and the NameAcquired for the unique +- * name, since hello is otherwise obsolete on kdbus. */ +- +- is_hello = +- sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && +- streq_ptr(m->destination, "org.freedesktop.DBus"); +- +- if (!is_hello) { +- if (p->got_hello) +- return 0; +- +- return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member); +- } +- +- if (p->got_hello) +- return log_error_errno(EIO, "Got duplicate hello, aborting."); +- +- p->got_hello = true; +- +- if (!p->destination_bus->is_kernel) +- return 0; +- +- r = sd_bus_message_new_method_return(m, &n); +- if (r < 0) +- return log_error_errno(r, "Failed to generate HELLO reply: %m"); +- +- r = sd_bus_message_append(n, "s", p->destination_bus->unique_name); +- if (r < 0) +- return log_error_errno(r, "Failed to append unique name to HELLO reply: %m"); +- +- r = bus_message_append_sender(n, "org.freedesktop.DBus"); +- if (r < 0) +- return log_error_errno(r, "Failed to append sender to HELLO reply: %m"); +- +- r = bus_seal_synthetic_message(p->local_bus, n); +- if (r < 0) +- return log_error_errno(r, "Failed to seal HELLO reply: %m"); +- +- r = sd_bus_send(p->local_bus, n, NULL); +- if (r < 0) +- return log_error_errno(r, "Failed to send HELLO reply: %m"); +- +- n = sd_bus_message_unref(n); +- r = sd_bus_message_new_signal( +- p->local_bus, +- &n, +- "/org/freedesktop/DBus", +- "org.freedesktop.DBus", +- "NameAcquired"); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m"); +- +- r = sd_bus_message_append(n, "s", p->destination_bus->unique_name); +- if (r < 0) +- return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m"); +- +- r = bus_message_append_sender(n, "org.freedesktop.DBus"); +- if (r < 0) +- return log_error_errno(r, "Failed to append sender to NameAcquired message: %m"); +- +- r = bus_seal_synthetic_message(p->local_bus, n); +- if (r < 0) +- return log_error_errno(r, "Failed to seal NameAcquired message: %m"); +- +- r = sd_bus_send(p->local_bus, n, NULL); +- if (r < 0) +- return log_error_errno(r, "Failed to send NameAcquired message: %m"); +- +- return 1; +-} +- +-static int patch_sender(sd_bus *a, sd_bus_message *m) { +- char **well_known = NULL; +- sd_bus_creds *c; +- int r; +- +- assert(a); +- assert(m); +- +- if (!a->is_kernel) +- return 0; +- +- /* We will change the sender of messages from the bus driver +- * so that they originate from the bus driver. This is a +- * speciality originating from dbus1, where the bus driver did +- * not have a unique id, but only the well-known name. */ +- +- c = sd_bus_message_get_creds(m); +- if (!c) +- return 0; +- +- r = sd_bus_creds_get_well_known_names(c, &well_known); +- if (r < 0) +- return r; +- +- if (strv_contains(well_known, "org.freedesktop.DBus")) +- m->sender = "org.freedesktop.DBus"; +- +- return 0; +-} +- +-static int proxy_process_destination_to_local(Proxy *p) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; +- int r; +- +- assert(p); +- +- r = sd_bus_process(p->destination_bus, &m); +- if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */ +- return r; +- if (r < 0) { +- log_error_errno(r, "Failed to process destination bus: %m"); +- return r; +- } +- if (r == 0) +- return 0; +- if (!m) +- return 1; +- +- /* We officially got EOF, let's quit */ +- if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) +- return -ECONNRESET; +- +- r = synthesize_name_acquired(p->destination_bus, p->local_bus, m); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return r; +- if (r < 0) +- return log_error_errno(r, "Failed to synthesize message: %m"); +- +- patch_sender(p->destination_bus, m); +- +- if (p->policy) { +- r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return r; +- if (r < 0) +- return log_error_errno(r, "Failed to process policy: %m"); +- if (r > 0) +- return 1; +- } +- +- r = sd_bus_send(p->local_bus, m, NULL); +- if (r < 0) { +- if (r == -ECONNRESET || r == -ENOTCONN) +- return r; +- +- /* If the peer tries to send a reply and it is +- * rejected with EPERM by the kernel, we ignore the +- * error. This catches cases where the original +- * method-call didn't had EXPECT_REPLY set, but the +- * proxy-peer still sends a reply. This is allowed in +- * dbus1, but not in kdbus. We don't want to track +- * reply-windows in the proxy, so we simply ignore +- * EPERM for all replies. The only downside is, that +- * callers are no longer notified if their replies are +- * dropped. However, this is equivalent to the +- * caller's timeout to expire, so this should be +- * acceptable. Nobody sane sends replies without a +- * matching method-call, so nobody should care. */ +- if (r == -EPERM && m->reply_cookie > 0) +- return 1; +- +- /* Return the error to the client, if we can */ +- synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m"); +- if (r == -ENOBUFS) { +- /* if local dbus1 peer does not dispatch its queue, warn only once */ +- if (!p->queue_overflow) +- log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid); +- p->queue_overflow = true; +- } else +- log_error_errno(r, +- "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m", +- p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type), +- strna(m->destination), strna(m->path), strna(m->interface), strna(m->member)); +- +- return 1; +- } +- +- p->queue_overflow = false; +- return 1; +-} +- +-static int proxy_process_local_to_destination(Proxy *p) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; +- int r; +- +- assert(p); +- +- r = sd_bus_process(p->local_bus, &m); +- if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */ +- return r; +- if (r < 0) { +- log_error_errno(r, "Failed to process local bus: %m"); +- return r; +- } +- if (r == 0) +- return 0; +- if (!m) +- return 1; +- +- /* We officially got EOF, let's quit */ +- if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) +- return -ECONNRESET; +- +- r = process_hello(p, m); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return r; +- if (r < 0) +- return log_error_errno(r, "Failed to process HELLO: %m"); +- if (r > 0) +- return 1; +- +- r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return r; +- if (r < 0) +- return log_error_errno(r, "Failed to process driver calls: %m"); +- if (r > 0) +- return 1; +- +- for (;;) { +- if (p->policy) { +- r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return r; +- if (r < 0) +- return log_error_errno(r, "Failed to process policy: %m"); +- if (r > 0) +- return 1; +- } +- +- r = sd_bus_send(p->destination_bus, m, NULL); +- if (r < 0) { +- if (r == -ECONNRESET || r == -ENOTCONN) +- return r; +- +- /* The name database changed since the policy check, hence let's check again */ +- if (r == -EREMCHG) +- continue; +- +- /* see above why EPERM is ignored for replies */ +- if (r == -EPERM && m->reply_cookie > 0) +- return 1; +- +- synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m"); +- log_error_errno(r, +- "Failed to forward message we got from local: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m", +- p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type), +- strna(m->destination), strna(m->path), strna(m->interface), strna(m->member)); +- return 1; +- } +- +- break; +- } +- +- return 1; +-} +- +-int proxy_run(Proxy *p) { +- int r; +- +- assert(p); +- +- for (;;) { +- bool busy = false; +- +- if (p->got_hello) { +- /* Read messages from bus, to pass them on to our client */ +- r = proxy_process_destination_to_local(p); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return 0; +- if (r < 0) +- return r; +- if (r > 0) +- busy = true; +- } +- +- /* Read messages from our client, to pass them on to the bus */ +- r = proxy_process_local_to_destination(p); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return 0; +- if (r < 0) +- return r; +- if (r > 0) +- busy = true; +- +- if (!busy) { +- r = proxy_wait(p); +- if (r == -ECONNRESET || r == -ENOTCONN) +- return 0; +- if (r < 0) +- return r; +- } +- } +- +- return 0; +-} +diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h +deleted file mode 100644 +index 782c4e60b..000000000 +--- a/src/bus-proxyd/proxy.h ++++ /dev/null +@@ -1,53 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-#pragma once +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 David Herrmann +- +- 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 "sd-bus.h" +-#include "bus-xml-policy.h" +-#include "util.h" +- +-typedef struct Proxy Proxy; +- +-struct Proxy { +- sd_bus *local_bus; +- struct ucred local_creds; +- int local_in; +- int local_out; +- +- sd_bus *destination_bus; +- +- Set *owned_names; +- SharedPolicy *policy; +- +- bool got_hello : 1; +- bool queue_overflow : 1; +-}; +- +-int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest); +-Proxy *proxy_free(Proxy *p); +- +-int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration); +-int proxy_hello_policy(Proxy *p, uid_t original_uid); +-int proxy_run(Proxy *p); +- +-DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free); +diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c +deleted file mode 100644 +index 9fb3e9fc4..000000000 +--- a/src/bus-proxyd/stdio-bridge.c ++++ /dev/null +@@ -1,263 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2010 Lennart Poettering +- Copyright 2013 Daniel Mack +- Copyright 2014 Kay Sievers +- +- 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 +-#include +-#include +-#include +-#include +-#include +- +-#include "log.h" +-#include "util.h" +-#include "socket-util.h" +-#include "sd-daemon.h" +-#include "sd-bus.h" +-#include "bus-internal.h" +-#include "bus-message.h" +-#include "bus-util.h" +-#include "build.h" +-#include "strv.h" +-#include "def.h" +-#include "capability.h" +-#include "bus-control.h" +-#include "smack-util.h" +-#include "set.h" +-#include "bus-xml-policy.h" +-#include "driver.h" +-#include "proxy.h" +-#include "synthesize.h" +- +-static char *arg_address = NULL; +-static char *arg_command_line_buffer = NULL; +- +-static int help(void) { +- +- printf("%s [OPTIONS...]\n\n" +- "Connect STDIO to a given bus address.\n\n" +- " -h --help Show this help\n" +- " --version Show package version\n" +- " --machine=MACHINE Connect to specified machine\n" +- " --address=ADDRESS Connect to the bus specified by ADDRESS\n" +- " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n", +- program_invocation_short_name); +- +- return 0; +-} +- +-static int parse_argv(int argc, char *argv[]) { +- +- enum { +- ARG_VERSION = 0x100, +- ARG_ADDRESS, +- ARG_MACHINE, +- }; +- +- static const struct option options[] = { +- { "help", no_argument, NULL, 'h' }, +- { "version", no_argument, NULL, ARG_VERSION }, +- { "address", required_argument, NULL, ARG_ADDRESS }, +- { "machine", required_argument, NULL, ARG_MACHINE }, +- {}, +- }; +- +- int c; +- +- assert(argc >= 0); +- assert(argv); +- +- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) +- +- switch (c) { +- +- case 'h': +- help(); +- return 0; +- +- case ARG_VERSION: +- puts(PACKAGE_STRING); +- puts(SYSTEMD_FEATURES); +- return 0; +- +- case ARG_ADDRESS: { +- char *a; +- +- a = strdup(optarg); +- if (!a) +- return log_oom(); +- +- free(arg_address); +- arg_address = a; +- break; +- } +- +- case ARG_MACHINE: { +- _cleanup_free_ char *e = NULL; +- char *a; +- +- e = bus_address_escape(optarg); +- if (!e) +- return log_oom(); +- +-#ifdef ENABLE_KDBUS +- a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); +-#else +- a = strjoin("x-machine-unix:machine=", e, NULL); +-#endif +- if (!a) +- return log_oom(); +- +- free(arg_address); +- arg_address = a; +- +- break; +- } +- +- case '?': +- return -EINVAL; +- +- default: +- assert_not_reached("Unhandled option"); +- } +- +- /* If the first command line argument is only "x" characters +- * we'll write who we are talking to into it, so that "ps" is +- * explanatory */ +- arg_command_line_buffer = argv[optind]; +- if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) { +- log_error("Too many arguments"); +- return -EINVAL; +- } +- +- if (!arg_address) { +- arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); +- if (!arg_address) +- return log_oom(); +- } +- +- return 1; +-} +- +-static int rename_service(sd_bus *a, sd_bus *b) { +- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; +- _cleanup_free_ char *p = NULL, *name = NULL; +- const char *comm; +- char **cmdline; +- uid_t uid; +- pid_t pid; +- int r; +- +- assert(a); +- assert(b); +- +- r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds); +- if (r < 0) +- return r; +- +- r = sd_bus_creds_get_euid(creds, &uid); +- if (r < 0) +- return r; +- +- r = sd_bus_creds_get_pid(creds, &pid); +- if (r < 0) +- return r; +- +- r = sd_bus_creds_get_cmdline(creds, &cmdline); +- if (r < 0) +- return r; +- +- r = sd_bus_creds_get_comm(creds, &comm); +- if (r < 0) +- return r; +- +- name = uid_to_name(uid); +- if (!name) +- return -ENOMEM; +- +- p = strv_join(cmdline, " "); +- if (!p) +- return -ENOMEM; +- +- /* The status string gets the full command line ... */ +- sd_notifyf(false, +- "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)", +- pid, p, +- uid, name); +- +- /* ... and the argv line only the short comm */ +- if (arg_command_line_buffer) { +- size_t m, w; +- +- m = strlen(arg_command_line_buffer); +- w = snprintf(arg_command_line_buffer, m, +- "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]", +- pid, comm, +- uid, name); +- +- if (m > w) +- memzero(arg_command_line_buffer + w, m - w); +- } +- +- log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s", +- pid, p, +- uid, name, +- a->unique_name); +- +- return 0; +-} +- +-int main(int argc, char *argv[]) { +- _cleanup_(proxy_freep) Proxy *p = NULL; +- int r; +- +- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); +- log_parse_environment(); +- log_open(); +- +- r = parse_argv(argc, argv); +- if (r <= 0) +- goto finish; +- +- r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address); +- if (r < 0) +- goto finish; +- +- r = rename_service(p->destination_bus, p->local_bus); +- if (r < 0) +- log_debug_errno(r, "Failed to rename process: %m"); +- +- r = proxy_run(p); +- +-finish: +- sd_notify(false, +- "STOPPING=1\n" +- "STATUS=Shutting down."); +- +- free(arg_address); +- +- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +-} +diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c +deleted file mode 100644 +index e1b0fd353..000000000 +--- a/src/bus-proxyd/synthesize.c ++++ /dev/null +@@ -1,228 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2010 Lennart Poettering +- Copyright 2013 Daniel Mack +- Copyright 2014 Kay Sievers +- +- 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 +- +-#include "log.h" +-#include "util.h" +-#include "sd-bus.h" +-#include "bus-internal.h" +-#include "bus-message.h" +-#include "bus-util.h" +-#include "strv.h" +-#include "def.h" +-#include "bus-control.h" +-#include "synthesize.h" +- +-static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) { +- int r; +- +- assert(b); +- assert(m); +- +- r = bus_message_append_sender(m, "org.freedesktop.DBus"); +- if (r < 0) +- return r; +- +- r = bus_seal_synthetic_message(b, m); +- if (r < 0) +- return r; +- +- return sd_bus_send(b, m, NULL); +-} +- +-int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; +- int r; +- +- assert(call); +- +- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) +- return 0; +- +- r = sd_bus_message_new_method_error(call, &m, e); +- if (r < 0) +- return r; +- +- return synthetic_driver_send(call->bus, m); +-} +- +-int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) { +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- va_list ap; +- +- va_start(ap, format); +- bus_error_setfv(&error, name, format, ap); +- va_end(ap); +- +- return synthetic_reply_method_error(call, &error); +-} +- +-int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) { +- _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; +- +- assert(call); +- +- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) +- return 0; +- +- if (sd_bus_error_is_set(p)) +- return synthetic_reply_method_error(call, p); +- +- sd_bus_error_set_errno(&berror, error); +- +- return synthetic_reply_method_error(call, &berror); +-} +- +-int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) { +- _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; +- va_list ap; +- +- assert(call); +- +- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) +- return 0; +- +- va_start(ap, format); +- sd_bus_error_set_errnofv(&berror, error, format, ap); +- va_end(ap); +- +- return synthetic_reply_method_error(call, &berror); +-} +- +-int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; +- int r; +- +- assert(call); +- +- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) +- return 0; +- +- r = sd_bus_message_new_method_return(call, &m); +- if (r < 0) +- return r; +- +- if (!isempty(types)) { +- va_list ap; +- +- va_start(ap, types); +- r = bus_message_append_ap(m, types, ap); +- va_end(ap); +- if (r < 0) +- return r; +- } +- +- return synthetic_driver_send(call->bus, m); +-} +- +-int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; +- int r; +- +- assert(call); +- +- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) +- return 0; +- +- r = sd_bus_message_new_method_return(call, &m); +- if (r < 0) +- return synthetic_reply_method_errno(call, r, NULL); +- +- r = sd_bus_message_append_strv(m, l); +- if (r < 0) +- return synthetic_reply_method_errno(call, r, NULL); +- +- return synthetic_driver_send(call->bus, m); +-} +- +-int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) { +- _cleanup_bus_message_unref_ sd_bus_message *n = NULL; +- const char *name, *old_owner, *new_owner; +- int r; +- +- assert(a); +- assert(b); +- assert(m); +- +- /* If we get NameOwnerChanged for our own name, we need to +- * synthesize NameLost/NameAcquired, since socket clients need +- * that, even though it is obsoleted on kdbus */ +- +- if (!a->is_kernel) +- return 0; +- +- if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") || +- !streq_ptr(m->path, "/org/freedesktop/DBus") || +- !streq_ptr(m->sender, "org.freedesktop.DBus")) +- return 0; +- +- r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner); +- if (r < 0) +- return r; +- +- r = sd_bus_message_rewind(m, true); +- if (r < 0) +- return r; +- +- if (streq(old_owner, a->unique_name)) { +- +- r = sd_bus_message_new_signal( +- b, +- &n, +- "/org/freedesktop/DBus", +- "org.freedesktop.DBus", +- "NameLost"); +- +- } else if (streq(new_owner, a->unique_name)) { +- +- r = sd_bus_message_new_signal( +- b, +- &n, +- "/org/freedesktop/DBus", +- "org.freedesktop.DBus", +- "NameAcquired"); +- } else +- return 0; +- +- if (r < 0) +- return r; +- +- r = sd_bus_message_append(n, "s", name); +- if (r < 0) +- return r; +- +- r = bus_message_append_sender(n, "org.freedesktop.DBus"); +- if (r < 0) +- return r; +- +- r = bus_seal_synthetic_message(b, n); +- if (r < 0) +- return r; +- +- return sd_bus_send(b, n, NULL); +-} +diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h +deleted file mode 100644 +index a55f171cb..000000000 +--- a/src/bus-proxyd/synthesize.h ++++ /dev/null +@@ -1,34 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-#pragma once +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 Lennart Poettering +- +- systemd is free software; you can redistribute it and/or modify it +- under the terms of the GNU Lesser General Public License as published by +- the Free Software Foundation; either version 2.1 of the License, or +- (at your option) any later version. +- +- systemd is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public License +- along with systemd; If not, see . +-***/ +- +-#include "sd-bus.h" +- +-int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...); +-int synthetic_reply_method_return_strv(sd_bus_message *call, char **l); +- +-int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e); +-int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4); +-int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p); +-int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4); +- +-int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m); +diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c +deleted file mode 100644 +index 421487e03..000000000 +--- a/src/bus-proxyd/test-bus-xml-policy.c ++++ /dev/null +@@ -1,182 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 Daniel Mack +- +- 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 +-#include +-#include +-#include +-#include +-#include +- +-#include "log.h" +-#include "util.h" +-#include "sd-bus.h" +-#include "bus-internal.h" +-#include "bus-message.h" +-#include "bus-util.h" +-#include "build.h" +-#include "strv.h" +-#include "def.h" +-#include "capability.h" +-#include "bus-xml-policy.h" +- +-static int test_policy_load(Policy *p, const char *name) { +- _cleanup_free_ char *path = NULL; +- int r = 0; +- +- path = strjoin(TEST_DIR, "/bus-policy/", name, NULL); +- assert_se(path); +- +- if (access(path, R_OK) == 0) +- r = policy_load(p, STRV_MAKE(path)); +- else +- r = -ENOENT; +- +- return r; +-} +- +-static int show_policy(const char *fn) { +- Policy p = {}; +- int r; +- +- r = policy_load(&p, STRV_MAKE(fn)); +- if (r < 0) { +- log_error_errno(r, "Failed to load policy %s: %m", fn); +- return r; +- } +- +- policy_dump(&p); +- policy_free(&p); +- +- return 0; +-} +- +-int main(int argc, char *argv[]) { +- +- Policy p = {}; +- +- printf("Showing session policy BEGIN\n"); +- show_policy("/etc/dbus-1/session.conf"); +- printf("Showing session policy END\n"); +- +- printf("Showing system policy BEGIN\n"); +- show_policy("/etc/dbus-1/system.conf"); +- printf("Showing system policy END\n"); +- +- /* Ownership tests */ +- assert_se(test_policy_load(&p, "ownerships.conf") == 0); +- +- assert_se(policy_check_own(&p, 0, 0, "org.test.test1") == true); +- assert_se(policy_check_own(&p, 1, 0, "org.test.test1") == true); +- +- assert_se(policy_check_own(&p, 0, 0, "org.test.test2") == true); +- assert_se(policy_check_own(&p, 1, 0, "org.test.test2") == false); +- +- assert_se(policy_check_own(&p, 0, 0, "org.test.test3") == false); +- assert_se(policy_check_own(&p, 1, 0, "org.test.test3") == false); +- +- assert_se(policy_check_own(&p, 0, 0, "org.test.test4") == false); +- assert_se(policy_check_own(&p, 1, 0, "org.test.test4") == true); +- +- policy_free(&p); +- +- /* Signaltest */ +- assert_se(test_policy_load(&p, "signals.conf") == 0); +- +- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true); +- assert_se(policy_check_one_send(&p, 1, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false); +- +- policy_free(&p); +- +- /* Method calls */ +- assert_se(test_policy_load(&p, "methods.conf") == 0); +- policy_dump(&p); +- +- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false); +- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false); +- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true); +- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true); +- +- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true); +- +- policy_free(&p); +- +- /* User and groups */ +- assert_se(test_policy_load(&p, "hello.conf") == 0); +- policy_dump(&p); +- +- assert_se(policy_check_hello(&p, 0, 0) == true); +- assert_se(policy_check_hello(&p, 1, 0) == false); +- assert_se(policy_check_hello(&p, 0, 1) == false); +- +- policy_free(&p); +- +- /* dbus1 test file: ownership */ +- +- assert_se(test_policy_load(&p, "check-own-rules.conf") >= 0); +- policy_dump(&p); +- +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop") == false); +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystem") == false); +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems") == true); +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo") == true); +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo.bar") == true); +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2") == false); +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo") == false); +- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo.bar") == false); +- +- policy_free(&p); +- +- /* dbus1 test file: many rules */ +- +- assert_se(test_policy_load(&p, "many-rules.conf") >= 0); +- policy_dump(&p); +- policy_free(&p); +- +- /* dbus1 test file: generic test */ +- +- assert_se(test_policy_load(&p, "test.conf") >= 0); +- policy_dump(&p); +- +- assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService") == true); +- assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService2") == false); +- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false); +- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); +- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); +- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false); +- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); +- +- assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService") == false); +- assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService2") == false); +- assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false); +- assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); +- assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); +- assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false); +- assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); +- +- policy_free(&p); +- +- return EXIT_SUCCESS; +-} +diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c +new file mode 100644 +index 000000000..791e545ab +--- /dev/null ++++ b/src/stdio-bridge/stdio-bridge.c +@@ -0,0 +1,303 @@ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2010 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 ++#include ++ ++#include "sd-bus.h" ++#include "sd-daemon.h" ++ ++#include "bus-internal.h" ++#include "bus-util.h" ++#include "build.h" ++#include "log.h" ++#include "util.h" ++ ++#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket" ++ ++const char *arg_bus_path = DEFAULT_BUS_PATH; ++ ++static int help(void) { ++ ++ printf("%s [OPTIONS...]\n\n" ++ "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n" ++ " -h --help Show this help\n" ++ " --version Show package version\n" ++ " --bus-path=PATH Path to the kernel bus (default: %s)\n", ++ program_invocation_short_name, DEFAULT_BUS_PATH); ++ ++ return 0; ++} ++ ++static int parse_argv(int argc, char *argv[]) { ++ ++ enum { ++ ARG_VERSION = 0x100, ++ }; ++ ++ static const struct option options[] = { ++ { "help", no_argument, NULL, 'h' }, ++ { "bus-path", required_argument, NULL, 'p' }, ++ { NULL, 0, NULL, 0 } ++ }; ++ ++ int c; ++ ++ assert(argc >= 0); ++ assert(argv); ++ ++ while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) { ++ ++ switch (c) { ++ ++ case 'h': ++ help(); ++ return 0; ++ ++ case ARG_VERSION: ++ puts(PACKAGE_STRING); ++ puts(SYSTEMD_FEATURES); ++ return 0; ++ ++ case '?': ++ return -EINVAL; ++ ++ case 'p': ++ arg_bus_path = optarg; ++ break; ++ ++ default: ++ log_error("Unknown option code %c", c); ++ return -EINVAL; ++ } ++ } ++ ++ return 1; ++} ++ ++int main(int argc, char *argv[]) { ++ _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL; ++ sd_id128_t server_id; ++ bool is_unix; ++ int r, in_fd, out_fd; ++ ++ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); ++ log_parse_environment(); ++ log_open(); ++ ++ r = parse_argv(argc, argv); ++ if (r <= 0) ++ goto finish; ++ ++ r = sd_listen_fds(0); ++ if (r == 0) { ++ in_fd = STDIN_FILENO; ++ out_fd = STDOUT_FILENO; ++ } else if (r == 1) { ++ in_fd = SD_LISTEN_FDS_START; ++ out_fd = SD_LISTEN_FDS_START; ++ } else { ++ log_error("Illegal number of file descriptors passed\n"); ++ goto finish; ++ } ++ ++ is_unix = ++ sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && ++ sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; ++ ++ r = sd_bus_new(&a); ++ if (r < 0) { ++ log_error_errno(r, "Failed to allocate bus: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_set_address(a, arg_bus_path); ++ if (r < 0) { ++ log_error_errno(r, "Failed to set address to connect to: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_negotiate_fds(a, is_unix); ++ if (r < 0) { ++ log_error_errno(r, "Failed to set FD negotiation: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_start(a); ++ if (r < 0) { ++ log_error_errno(r, "Failed to start bus client: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_get_bus_id(a, &server_id); ++ if (r < 0) { ++ log_error_errno(r, "Failed to get server ID: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_new(&b); ++ if (r < 0) { ++ log_error_errno(r, "Failed to allocate bus: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_set_fd(b, in_fd, out_fd); ++ if (r < 0) { ++ log_error_errno(r, "Failed to set fds: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_set_server(b, 1, server_id); ++ if (r < 0) { ++ log_error_errno(r, "Failed to set server mode: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_negotiate_fds(b, is_unix); ++ if (r < 0) { ++ log_error_errno(r, "Failed to set FD negotiation: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_set_anonymous(b, true); ++ if (r < 0) { ++ log_error_errno(r, "Failed to set anonymous authentication: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_start(b); ++ if (r < 0) { ++ log_error_errno(r, "Failed to start bus client: %m"); ++ goto finish; ++ } ++ ++ for (;;) { ++ _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; ++ int events_a, events_b, fd; ++ uint64_t timeout_a, timeout_b, t; ++ struct timespec _ts, *ts; ++ ++ r = sd_bus_process(a, &m); ++ if (r < 0) { ++ log_error_errno(r, "Failed to process bus a: %m"); ++ goto finish; ++ } ++ ++ if (m) { ++ r = sd_bus_send(b, m, NULL); ++ if (r < 0) { ++ log_error_errno(r, "Failed to send message: %m"); ++ goto finish; ++ } ++ } ++ ++ if (r > 0) ++ continue; ++ ++ r = sd_bus_process(b, &m); ++ if (r < 0) { ++ /* treat 'connection reset by peer' as clean exit condition */ ++ if (r == -ECONNRESET) ++ r = 0; ++ ++ goto finish; ++ } ++ ++ if (m) { ++ r = sd_bus_send(a, m, NULL); ++ if (r < 0) { ++ log_error_errno(r, "Failed to send message: %m"); ++ goto finish; ++ } ++ } ++ ++ if (r > 0) ++ continue; ++ ++ fd = sd_bus_get_fd(a); ++ if (fd < 0) { ++ log_error_errno(r, "Failed to get fd: %m"); ++ goto finish; ++ } ++ ++ events_a = sd_bus_get_events(a); ++ if (events_a < 0) { ++ log_error_errno(r, "Failed to get events mask: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_get_timeout(a, &timeout_a); ++ if (r < 0) { ++ log_error_errno(r, "Failed to get timeout: %m"); ++ goto finish; ++ } ++ ++ events_b = sd_bus_get_events(b); ++ if (events_b < 0) { ++ log_error_errno(r, "Failed to get events mask: %m"); ++ goto finish; ++ } ++ ++ r = sd_bus_get_timeout(b, &timeout_b); ++ if (r < 0) { ++ log_error_errno(r, "Failed to get timeout: %m"); ++ goto finish; ++ } ++ ++ t = timeout_a; ++ if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a)) ++ t = timeout_b; ++ ++ if (t == (uint64_t) -1) ++ ts = NULL; ++ else { ++ usec_t nw; ++ ++ nw = now(CLOCK_MONOTONIC); ++ if (t > nw) ++ t -= nw; ++ else ++ t = 0; ++ ++ ts = timespec_store(&_ts, t); ++ } ++ ++ { ++ struct pollfd p[3] = { ++ {.fd = fd, .events = events_a, }, ++ {.fd = STDIN_FILENO, .events = events_b & POLLIN, }, ++ {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }}; ++ ++ r = ppoll(p, ELEMENTSOF(p), ts, NULL); ++ } ++ if (r < 0) { ++ log_error("ppoll() failed: %m"); ++ goto finish; ++ } ++ } ++ ++ r = 0; ++ ++finish: ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} +diff --git a/src/test/test-tables.c b/src/test/test-tables.c +index e4097903c..afd4ab7fb 100644 +--- a/src/test/test-tables.c ++++ b/src/test/test-tables.c +@@ -46,7 +46,6 @@ + #include "util.h" + #include "architecture.h" + #include "link-config.h" +-#include "bus-xml-policy.h" + #include "busname.h" + #include "journald-server.h" + #include "locale-util.h" +@@ -86,8 +85,6 @@ int main(int argc, char **argv) { + test_table(path_result, PATH_RESULT); + test_table(path_state, PATH_STATE); + test_table(path_type, PATH_TYPE); +- test_table(policy_item_class, POLICY_ITEM_CLASS); +- test_table(policy_item_type, POLICY_ITEM_TYPE); + test_table(protect_home, PROTECT_HOME); + test_table(protect_system, PROTECT_SYSTEM); + test_table(rlimit, RLIMIT); +diff --git a/sysusers.d/systemd.conf.m4 b/sysusers.d/systemd.conf.m4 +index 23175de1f..3d3e2374e 100644 +--- a/sysusers.d/systemd.conf.m4 ++++ b/sysusers.d/systemd.conf.m4 +@@ -6,9 +6,6 @@ + # (at your option) any later version. + + g systemd-journal - - +-m4_ifdef(`ENABLE_KDBUS', +-u systemd-bus-proxy - "systemd Bus Proxy" +-)m4_dnl + m4_ifdef(`ENABLE_NETWORKD', + u systemd-network - "systemd Network Management" + )m4_dnl +diff --git a/units/.gitignore b/units/.gitignore +index 7f3e0d093..48c8f7217 100644 +--- a/units/.gitignore ++++ b/units/.gitignore +@@ -1,4 +1,3 @@ +-/systemd-bus-proxyd.service.m4 + /user@.service.m4 + /console-getty.service + /console-getty.service.m4 +@@ -24,7 +23,6 @@ + /systemd-backlight@.service + /systemd-binfmt.service + /systemd-bootchart.service +-/systemd-bus-proxyd.service + /systemd-firstboot.service + /systemd-fsck-root.service + /systemd-fsck@.service +diff --git a/units/systemd-bus-proxyd.service.m4.in b/units/systemd-bus-proxyd.service.m4.in +deleted file mode 100644 +index ffaf0bdc8..000000000 +--- a/units/systemd-bus-proxyd.service.m4.in ++++ /dev/null +@@ -1,19 +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=Legacy D-Bus Protocol Compatibility Daemon +- +-[Service] +-ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/0-system/bus +-NotifyAccess=main +-CapabilityBoundingSet=CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP m4_ifdef(`HAVE_SMACK', CAP_MAC_ADMIN ) +-PrivateTmp=yes +-PrivateDevices=yes +-PrivateNetwork=yes +-ProtectSystem=full +-ProtectHome=yes +diff --git a/units/systemd-bus-proxyd.socket b/units/systemd-bus-proxyd.socket +deleted file mode 100644 +index 3f80a1d54..000000000 +--- a/units/systemd-bus-proxyd.socket ++++ /dev/null +@@ -1,12 +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=Legacy D-Bus Protocol Compatibility Socket +- +-[Socket] +-ListenStream=/var/run/dbus/system_bus_socket +diff --git a/units/user/.gitignore b/units/user/.gitignore +index 6111b10cc..41a74f546 100644 +--- a/units/user/.gitignore ++++ b/units/user/.gitignore +@@ -1,3 +1 @@ + /systemd-exit.service +-/systemd-bus-proxyd.service +-/systemd-consoled.service +diff --git a/units/user/systemd-bus-proxyd.service.in b/units/user/systemd-bus-proxyd.service.in +deleted file mode 100644 +index e1e399dc3..000000000 +--- a/units/user/systemd-bus-proxyd.service.in ++++ /dev/null +@@ -1,13 +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=Legacy D-Bus Protocol Compatibility Daemon +- +-[Service] +-ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/%U-user/bus +-NotifyAccess=main +diff --git a/units/user/systemd-bus-proxyd.socket b/units/user/systemd-bus-proxyd.socket +deleted file mode 100644 +index b9efc0e7c..000000000 +--- a/units/user/systemd-bus-proxyd.socket ++++ /dev/null +@@ -1,12 +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=Legacy D-Bus Protocol Compatibility Socket +- +-[Socket] +-ListenStream=%t/bus diff --git a/SOURCES/0455-execute-Add-new-PassEnvironment-directive.patch b/SOURCES/0455-execute-Add-new-PassEnvironment-directive.patch new file mode 100644 index 00000000..0465b700 --- /dev/null +++ b/SOURCES/0455-execute-Add-new-PassEnvironment-directive.patch @@ -0,0 +1,391 @@ +From 88d2ec272d3e503412e477d9abaebfe2ca199e78 Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Sun, 6 Sep 2015 23:06:53 -0700 +Subject: [PATCH] execute: Add new PassEnvironment= directive + +This directive allows passing environment variables from the system +manager to spawned services. Variables in the system manager can be set +inside a container by passing `--set-env=...` options to systemd-spawn. + +Tested with an on-disk test.service unit. Tested using multiple variable +names on a single line, with an empty setting to clear the current list +of variables, with non-existing variables. + +Tested using `systemd-run -p PassEnvironment=VARNAME` to confirm it +works with transient units. + +Confirmed that `systemctl show` will display the PassEnvironment +settings. + +Checked that man pages are generated correctly. + +No regressions in `make check`. + +(cherry picked from commit b4c14404b3e8753c41bac0b1d49369230a15c544) + +Resolves: #1426214 +--- + man/systemd.exec.xml | 27 +++++++++++++++ + shell-completion/bash/systemd-run | 2 +- + src/core/dbus-execute.c | 34 ++++++++++++++++++ + src/core/execute.c | 44 ++++++++++++++++++++++-- + src/core/execute.h | 1 + + src/core/load-fragment-gperf.gperf.m4 | 1 + + src/core/load-fragment.c | 65 +++++++++++++++++++++++++++++++++++ + src/core/load-fragment.h | 1 + + src/libsystemd/sd-bus/bus-util.c | 2 +- + src/shared/env-util.c | 15 ++++++++ + src/shared/env-util.h | 1 + + 11 files changed, 189 insertions(+), 4 deletions(-) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index c5199d3a5..aa5831cc2 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -293,6 +293,33 @@ + earlier setting. + + ++ ++ PassEnvironment= ++ ++ Pass environment variables from the systemd system ++ manager to executed processes. Takes a space-separated list of variable ++ names. This option may be specified more than once, in which case all ++ listed variables will be set. If the empty string is assigned to this ++ option, the list of environment variables is reset, all prior ++ assignments have no effect. Variables that are not set in the system ++ manager will not be passed and will be silently ignored. ++ ++ Variables passed from this setting are overridden by those passed ++ from Environment= or ++ EnvironmentFile=. ++ ++ Example: ++ PassEnvironment=VAR1 VAR2 VAR3 ++ passes three variables VAR1, ++ VAR2, VAR3 ++ with the values set for those variables in PID1. ++ ++ ++ See ++ environ7 ++ for details about environment variables. ++ ++ + + StandardInput= + Controls where file descriptor 0 (STDIN) of +diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run +index 5145cd3f2..36ffa46db 100644 +--- a/shell-completion/bash/systemd-run ++++ b/shell-completion/bash/systemd-run +@@ -73,7 +73,7 @@ _systemd_run() { + KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= + LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= + LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= +- LimitNICE= LimitRTPRIO= LimitRTTIME=' ++ LimitNICE= LimitRTPRIO= LimitRTTIME= PassEnvironment=' + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index a9f7971cd..da8b10d2b 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -597,6 +597,7 @@ const sd_bus_vtable bus_exec_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), +@@ -963,6 +964,39 @@ int bus_exec_context_set_transient_property( + + return 1; + ++ } else if (streq(name, "PassEnvironment")) { ++ ++ _cleanup_strv_free_ char **l = NULL; ++ ++ r = sd_bus_message_read_strv(message, &l); ++ if (r < 0) ++ return r; ++ ++ if (!strv_env_name_is_valid(l)) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment block."); ++ ++ if (mode != UNIT_CHECK) { ++ if (strv_isempty(l)) { ++ strv_free(c->pass_environment); ++ c->pass_environment = NULL; ++ unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=\n"); ++ } else { ++ _cleanup_free_ char *joined = NULL; ++ ++ r = strv_extend_strv(&c->pass_environment, l); ++ if (r < 0) ++ return r; ++ ++ joined = strv_join_quoted(c->pass_environment); ++ if (!joined) ++ return -ENOMEM; ++ ++ unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined); ++ } ++ } ++ ++ return 1; ++ + } else if (rlimit_from_string(name) >= 0) { + uint64_t rl; + rlim_t x; +diff --git a/src/core/execute.c b/src/core/execute.c +index 863babd76..f72b20966 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1256,6 +1256,34 @@ static int build_environment( + return 0; + } + ++static int build_pass_environment(const ExecContext *c, char ***ret) { ++ _cleanup_strv_free_ char **pass_env = NULL; ++ size_t n_env = 0, n_bufsize = 0; ++ char **i; ++ ++ STRV_FOREACH(i, c->pass_environment) { ++ _cleanup_free_ char *x = NULL; ++ char *v; ++ ++ v = getenv(*i); ++ if (!v) ++ continue; ++ x = strjoin(*i, "=", v, NULL); ++ if (!x) ++ return -ENOMEM; ++ if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2)) ++ return -ENOMEM; ++ pass_env[n_env++] = x; ++ pass_env[n_env] = NULL; ++ x = NULL; ++ } ++ ++ *ret = pass_env; ++ pass_env = NULL; ++ ++ return 0; ++} ++ + static bool exec_needs_mount_namespace( + const ExecContext *context, + const ExecParameters *params, +@@ -1297,7 +1325,7 @@ static int exec_child( + char **files_env, + int *exit_status) { + +- _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; ++ _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; + _cleanup_free_ char *mac_selinux_context_net = NULL; + const char *username = NULL, *home = NULL, *shell = NULL; + unsigned n_dont_close = 0; +@@ -1805,9 +1833,16 @@ static int exec_child( + return r; + } + +- final_env = strv_env_merge(5, ++ r = build_pass_environment(context, &pass_env); ++ if (r < 0) { ++ *exit_status = EXIT_MEMORY; ++ return r; ++ } ++ ++ final_env = strv_env_merge(6, + params->environment, + our_env, ++ pass_env, + context->environment, + files_env, + pam_env, +@@ -1965,6 +2000,8 @@ void exec_context_done(ExecContext *c) { + + strv_free(c->environment_files); + c->environment_files = NULL; ++ strv_free(c->pass_environment); ++ c->pass_environment = NULL; + + for (l = 0; l < ELEMENTSOF(c->rlimit); l++) { + free(c->rlimit[l]); +@@ -2267,6 +2304,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { + STRV_FOREACH(e, c->environment_files) + fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e); + ++ STRV_FOREACH(e, c->pass_environment) ++ fprintf(f, "%sPassEnvironment: %s\n", prefix, *e); ++ + if (c->nice_set) + fprintf(f, + "%sNice: %i\n", +diff --git a/src/core/execute.h b/src/core/execute.h +index 6e0c9faa7..cadd0e6b4 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -96,6 +96,7 @@ struct ExecRuntime { + struct ExecContext { + char **environment; + char **environment_files; ++ char **pass_environment; + + struct rlimit *rlimit[_RLIMIT_MAX]; + char *working_directory, *root_directory; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index c866a9cd0..b50fe45b4 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -33,6 +33,7 @@ $1.CPUAffinity, config_parse_exec_cpu_affinity, 0, + $1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask) + $1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment) + $1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files) ++$1.PassEnvironment, config_parse_pass_environ, 0, offsetof($1, exec_context.pass_environment) + $1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input) + $1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output) + $1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 3a3c456da..c450fe2c7 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -2265,6 +2265,71 @@ int config_parse_environ(const char *unit, + return 0; + } + ++int config_parse_pass_environ(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 *whole_rvalue = rvalue; ++ char*** passenv = data; ++ _cleanup_strv_free_ char **n = NULL; ++ size_t nlen = 0, nbufsize = 0; ++ int r; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ if (isempty(rvalue)) { ++ /* Empty assignment resets the list */ ++ strv_free(*passenv); ++ *passenv = NULL; ++ return 0; ++ } ++ ++ for (;;) { ++ _cleanup_free_ char *word = NULL; ++ ++ r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); ++ if (r == 0) ++ break; ++ if (r == -ENOMEM) ++ return log_oom(); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, ++ "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue); ++ break; ++ } ++ ++ if (!env_name_is_valid(word)) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, ++ "Invalid environment name for %s, ignoring: %s", lvalue, word); ++ continue; ++ } ++ ++ if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) ++ return log_oom(); ++ n[nlen++] = word; ++ n[nlen] = NULL; ++ word = NULL; ++ } ++ ++ if (n) { ++ r = strv_extend_strv(passenv, n); ++ if (r < 0) ++ return r; ++ } ++ ++ return 0; ++} ++ + int config_parse_ip_tos(const char *unit, + const char *filename, + unsigned line, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 7c69e5369..9dd7d1bda 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -85,6 +85,7 @@ int config_parse_syscall_filter(const char *unit, const char *filename, unsigned + int config_parse_syscall_archs(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_syscall_errno(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_environ(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_pass_environ(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_unit_slice(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_cpu_shares(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_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index d35776087..ed0849b63 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1535,7 +1535,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + + r = sd_bus_message_append(m, "v", "i", i); + +- } else if (streq(field, "Environment")) { ++ } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) { + + r = sd_bus_message_append(m, "v", "as", 1, eq); + +diff --git a/src/shared/env-util.c b/src/shared/env-util.c +index e8da4c978..581d84a20 100644 +--- a/src/shared/env-util.c ++++ b/src/shared/env-util.c +@@ -136,6 +136,21 @@ bool strv_env_is_valid(char **e) { + return true; + } + ++bool strv_env_name_is_valid(char **l) { ++ char **p, **q; ++ ++ STRV_FOREACH(p, l) { ++ if (!env_name_is_valid(*p)) ++ return false; ++ ++ STRV_FOREACH(q, p + 1) ++ if (streq(*p, *q)) ++ return false; ++ } ++ ++ return true; ++} ++ + bool strv_env_name_or_assignment_is_valid(char **l) { + char **p, **q; + +diff --git a/src/shared/env-util.h b/src/shared/env-util.h +index 252d87be1..b8c2d81e4 100644 +--- a/src/shared/env-util.h ++++ b/src/shared/env-util.h +@@ -34,6 +34,7 @@ bool strv_env_is_valid(char **e); + #define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL) + char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata); + ++bool strv_env_name_is_valid(char **l); + bool strv_env_name_or_assignment_is_valid(char **l); + + char **strv_env_merge(unsigned n_lists, ...); diff --git a/SOURCES/0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch b/SOURCES/0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch new file mode 100644 index 00000000..ef805c90 --- /dev/null +++ b/SOURCES/0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch @@ -0,0 +1,130 @@ +From f35b737bdd6e508cf73f43a1beb3f5cb8c1ebb07 Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Sun, 8 Nov 2015 10:37:05 -0800 +Subject: [PATCH] test-execute: Add tests for new PassEnvironment= directive + +Check the base case, plus erasing the list, listing the same variable +name more than once and when variables are absent from the manager +execution environment. + +Confirmed that `sudo ./test-execute` passes and that modifying the test +cases (or the values of the set variables in test-execute.c) is enough +to make the test cases fail. + +(cherry picked from commit 4c80d201ace0377312c27143afab04e9c9f1ee64) + +Related: #1426214 +--- + Makefile.am | 4 ++++ + src/test/test-execute.c | 14 ++++++++++++++ + test/exec-passenvironment-absent.service | 7 +++++++ + test/exec-passenvironment-empty.service | 8 ++++++++ + test/exec-passenvironment-repeated.service | 8 ++++++++ + test/exec-passenvironment.service | 7 +++++++ + 6 files changed, 48 insertions(+) + create mode 100644 test/exec-passenvironment-absent.service + create mode 100644 test/exec-passenvironment-empty.service + create mode 100644 test/exec-passenvironment-repeated.service + create mode 100644 test/exec-passenvironment.service + +diff --git a/Makefile.am b/Makefile.am +index 924b34b69..e9ceac98a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1477,6 +1477,10 @@ EXTRA_DIST += \ + test/exec-environment-empty.service \ + test/exec-environment-multiple.service \ + test/exec-environment.service \ ++ test/exec-passenvironment-absent.service \ ++ test/exec-passenvironment-empty.service \ ++ test/exec-passenvironment-repeated.service \ ++ test/exec-passenvironment.service \ + test/exec-group.service \ + test/exec-ignoresigpipe-no.service \ + test/exec-ignoresigpipe-yes.service \ +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 5a02960e7..8def1946d 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -142,6 +142,19 @@ static void test_exec_environment(Manager *m) { + test(m, "exec-environment-empty.service", 0, CLD_EXITED); + } + ++static void test_exec_passenvironment(Manager *m) { ++ assert_se(setenv("VAR1", "word1 word2", 1) == 0); ++ assert_se(setenv("VAR2", "word3", 1) == 0); ++ assert_se(setenv("VAR3", "$word 5 6", 1) == 0); ++ test(m, "exec-passenvironment.service", 0, CLD_EXITED); ++ test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED); ++ test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED); ++ assert_se(unsetenv("VAR1") == 0); ++ assert_se(unsetenv("VAR2") == 0); ++ assert_se(unsetenv("VAR3") == 0); ++ test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED); ++} ++ + static void test_exec_umask(Manager *m) { + test(m, "exec-umask-default.service", 0, CLD_EXITED); + test(m, "exec-umask-0177.service", 0, CLD_EXITED); +@@ -165,6 +178,7 @@ int main(int argc, char *argv[]) { + test_exec_user, + test_exec_group, + test_exec_environment, ++ test_exec_passenvironment, + test_exec_umask, + test_exec_runtimedirectory, + NULL, +diff --git a/test/exec-passenvironment-absent.service b/test/exec-passenvironment-absent.service +new file mode 100644 +index 000000000..7d5e32a4e +--- /dev/null ++++ b/test/exec-passenvironment-absent.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for PassEnvironment with variables absent from the execution environment ++ ++[Service] ++ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' ++Type=oneshot ++PassEnvironment=VAR1 VAR2 VAR3 +diff --git a/test/exec-passenvironment-empty.service b/test/exec-passenvironment-empty.service +new file mode 100644 +index 000000000..c93c197c1 +--- /dev/null ++++ b/test/exec-passenvironment-empty.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for PassEnvironment and erasing the variable list ++ ++[Service] ++ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' ++Type=oneshot ++PassEnvironment=VAR1 VAR2 VAR3 ++PassEnvironment= +diff --git a/test/exec-passenvironment-repeated.service b/test/exec-passenvironment-repeated.service +new file mode 100644 +index 000000000..5e8c56f26 +--- /dev/null ++++ b/test/exec-passenvironment-repeated.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for PassEnvironment with a variable name repeated ++ ++[Service] ++ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' ++Type=oneshot ++PassEnvironment=VAR1 VAR2 ++PassEnvironment=VAR1 VAR3 +diff --git a/test/exec-passenvironment.service b/test/exec-passenvironment.service +new file mode 100644 +index 000000000..b4a990968 +--- /dev/null ++++ b/test/exec-passenvironment.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for PassEnvironment ++ ++[Service] ++ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' ++Type=oneshot ++PassEnvironment=VAR1 VAR2 VAR3 diff --git a/SOURCES/0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch b/SOURCES/0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch new file mode 100644 index 00000000..1791b46d --- /dev/null +++ b/SOURCES/0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch @@ -0,0 +1,69 @@ +From ddad59f50e67a5e36cd9c40e774d28240a6a7c0c Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Wed, 11 Nov 2015 09:24:34 -0800 +Subject: [PATCH] test-execute: Clarify interaction of PassEnvironment= and + MANAGER_USER + +@evverx brought up that test-execute runs under MANAGER_USER which +forwards all its environment variables to the services. It turns out it +only forwards those that were in the environment at the time of manager +creation, so this test was still working. + +It was still possible to attack it by running something like: + $ sudo VAR1=a VAR2=b VAR3=c ./test-execute + +Prevent that attack by unsetting the three variables explicitly before +creating the manager for the test case. + +Also add comments explaining the interactions with MANAGER_USER and, +while it has some caveats, this tests are still valid in that context. + +Tested by checking that the test running with the variables set from the +external environment will still pass. + +(cherry picked from commit e1abca2ee42e5938ee1f2542c3eba9e70edb0be2) + +Related: #1426214 +--- + src/test/test-execute.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 8def1946d..6e5567c3e 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -143,6 +143,17 @@ static void test_exec_environment(Manager *m) { + } + + static void test_exec_passenvironment(Manager *m) { ++ /* test-execute runs under MANAGER_USER which, by default, forwards all ++ * variables present in the environment, but only those that are ++ * present _at the time it is created_! ++ * ++ * So these PassEnvironment checks are still expected to work, since we ++ * are ensuring the variables are not present at manager creation (they ++ * are unset explicitly in main) and are only set here. ++ * ++ * This is still a good approximation of how a test for MANAGER_SYSTEM ++ * would work. ++ */ + assert_se(setenv("VAR1", "word1 word2", 1) == 0); + assert_se(setenv("VAR2", "word3", 1) == 0); + assert_se(setenv("VAR3", "$word 5 6", 1) == 0); +@@ -199,6 +210,16 @@ int main(int argc, char *argv[]) { + assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0); + assert_se(set_unit_path(TEST_DIR ":") >= 0); + ++ /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test ++ * cases, otherwise (and if they are present in the environment), ++ * `manager_default_environment` will copy them into the default ++ * environment which is passed to each created job, which will make the ++ * tests that expect those not to be present to fail. ++ */ ++ assert_se(unsetenv("VAR1") == 0); ++ assert_se(unsetenv("VAR2") == 0); ++ assert_se(unsetenv("VAR3") == 0); ++ + r = manager_new(SYSTEMD_USER, true, &m); + if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { + printf("Skipping test: manager_new: %s", strerror(-r)); diff --git a/SOURCES/0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch b/SOURCES/0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch new file mode 100644 index 00000000..81c54f2e --- /dev/null +++ b/SOURCES/0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch @@ -0,0 +1,46 @@ +From 2520d152da83096b42fe7d27cf0bf97a62b50fac Mon Sep 17 00:00:00 2001 +From: Michael Gebetsroither +Date: Thu, 17 Sep 2015 22:54:13 +0200 +Subject: [PATCH] load-fragment: resolve specifiers in RuntimeDirectory + +Cherry-picked from: 9b5864d +Resolves: #1428110 +--- + src/core/load-fragment.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index c450fe2c7..6fc4d745d 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3384,6 +3384,7 @@ int config_parse_runtime_directory( + void *userdata) { + + char***rt = data; ++ Unit *u = userdata; + const char *word, *state; + size_t l; + int r; +@@ -3401,12 +3402,19 @@ int config_parse_runtime_directory( + } + + FOREACH_WORD_QUOTED(word, l, rvalue, state) { +- _cleanup_free_ char *n; ++ _cleanup_free_ char *t = NULL, *n = NULL; + +- n = strndup(word, l); +- if (!n) ++ t = strndup(word, l); ++ if (!t) + return log_oom(); + ++ r = unit_name_printf(u, t, &n); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, -r, ++ "Failed to resolve specifiers, ignoring: %s", strerror(-r)); ++ continue; ++ } ++ + if (!filename_is_valid(n)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Runtime directory is not valid, ignoring assignment: %s", rvalue); diff --git a/SOURCES/0459-Add-microphone-mute-keymap-for-Dell-Precision.patch b/SOURCES/0459-Add-microphone-mute-keymap-for-Dell-Precision.patch new file mode 100644 index 00000000..efbd01b6 --- /dev/null +++ b/SOURCES/0459-Add-microphone-mute-keymap-for-Dell-Precision.patch @@ -0,0 +1,25 @@ +From 80d1022b06ca59190fab4bff0bb9c0acc57e9435 Mon Sep 17 00:00:00 2001 +From: "Chen-Han Hsiao (Stanley)" +Date: Thu, 10 Sep 2015 11:20:50 +0800 +Subject: [PATCH] Add microphone mute keymap for Dell Precision + +(cherry picked from commit 6e675e278c04bd5662914888a2b3cf856d743659) + +Resolves: #1413477 +--- + hwdb/60-keyboard.hwdb | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb +index 88906655e..a7ae2f867 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -263,6 +263,8 @@ keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr* + + # Dell Latitude microphone mute + keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude* ++# Dell Precision microphone mute ++keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision* + KEYBOARD_KEY_150=f20 # Mic mute toggle, should be micmute + + ########################################################### diff --git a/SOURCES/0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch b/SOURCES/0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch new file mode 100644 index 00000000..107b6ea9 --- /dev/null +++ b/SOURCES/0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch @@ -0,0 +1,26 @@ +From 96d51b2f972c0de259c4d52471894cfac5d85872 Mon Sep 17 00:00:00 2001 +From: nikolaof +Date: Wed, 11 Jan 2017 15:35:20 +0200 +Subject: [PATCH] hwdb: update micmute YCODE on device node at DELL LATITUDE + laptops for mic mute button. (#5012) + +(cherry picked from commit fc6e082622c73eb9a22ce16a278d8c4dd7594cbb) + +Related: #1413477 +--- + hwdb/60-keyboard.hwdb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb +index a7ae2f867..a9cd73b72 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -265,7 +265,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr* + keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude* + # Dell Precision microphone mute + keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision* +- KEYBOARD_KEY_150=f20 # Mic mute toggle, should be micmute ++ KEYBOARD_KEY_100150=f20 # Mic mute toggle, should be micmute + + ########################################################### + # Everex diff --git a/SOURCES/0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch b/SOURCES/0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch new file mode 100644 index 00000000..31a791d7 --- /dev/null +++ b/SOURCES/0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch @@ -0,0 +1,163 @@ +From b9146e4dab45e2f76ceca3772564c0f01e227a9f Mon Sep 17 00:00:00 2001 +From: Liu Yuan Yuan +Date: Fri, 13 Nov 2015 11:50:42 +0100 +Subject: [PATCH] udev/path_id: improve and enhance bus detection for Linux on + z Systems + +Improve and enhance the path_id udev builtin to correctly handle bus' +available on Linux on z Systems (s390). + +Previously, the CCW bus and, in particular, any FCP devices on it, have +been treated separately. This commit integrates the CCW bus into the +device chain loop. FCP devices and their associated SCSI disks are now +handled through the common SCSI handling functions in path_id. + +This implies also a change in the naming of the symbolic links created +by udev. So any backports of this commit to existing Linux distribution +must be done with care. If a backport is required, a udev rule must be +created to also create the "old-style" symbolic links. + +Apart from the CCW bus, this commit adds bus support for the: + +- ccwgroup bus which manages network devices, and +- ap bus which manages cryptographic adapters +- iucv bus which manages IUCV devices on z/VM + +Cherry-picked from: e7eb5a8d88367a755944fdda3023a308e5272953 +Resolves: #1274401 +--- + rules/40-redhat.rules | 25 ++++++++++++++++ + src/udev/udev-builtin-path_id.c | 63 +++++++++++++++++++++++------------------ + 2 files changed, 60 insertions(+), 28 deletions(-) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 0164dc921..c928d412b 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -15,3 +15,28 @@ SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_target", TEST!="[module/sg]", RUN+="/sbin + + # Rule for prandom character device node permissions + KERNEL=="prandom", MODE="0644" ++ ++ ++# Rules for creating the ID_PATH for SCSI devices based on the CCW bus ++# using the form: ccw--zfcp-: ++# ++ACTION=="remove", GOTO="zfcp_scsi_device_end" ++ ++# ++# Set environment variable "ID_ZFCP_BUS" to "1" if the devices ++# (both disk and partition) are SCSI devices based on FCP devices ++# ++KERNEL=="sd*", SUBSYSTEMS=="ccw", DRIVERS=="zfcp", ENV{.ID_ZFCP_BUS}="1" ++ ++# For SCSI disks ++KERNEL=="sd*[!0-9]", SUBSYSTEMS=="scsi", ++ ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="disk", ++ SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}" ++ ++ ++# For partitions on a SCSI disk ++KERNEL=="sd*[0-9]", SUBSYSTEMS=="scsi", ++ ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="partition", ++ SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}-part%n" ++ ++LABEL="zfcp_scsi_device_end" +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 88a812ff5..19447201b 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -615,27 +615,23 @@ static struct udev_device *handle_bcma(struct udev_device *parent, char **path) + return parent; + } + +-static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) { +- struct udev_device *scsi_dev; +- +- scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device"); +- if (scsi_dev != NULL) { +- const char *wwpn; +- const char *lun; +- const char *hba_id; +- +- hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id"); +- wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn"); +- lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun"); +- if (hba_id != NULL && lun != NULL && wwpn != NULL) { +- path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun); +- goto out; +- } +- } ++/* Handle devices of AP bus in System z platform. */ ++static struct udev_device *handle_ap(struct udev_device *parent, char **path) { ++ const char *type, *func; ++ ++ assert(parent); ++ assert(path); ++ ++ type = udev_device_get_sysattr_value(parent, "type"); ++ func = udev_device_get_sysattr_value(parent, "ap_functions"); + +- path_prepend(path, "ccw-%s", udev_device_get_sysname(parent)); ++ if (type != NULL && func != NULL) { ++ path_prepend(path, "ap-%s-%s", type, func); ++ goto out; ++ } ++ path_prepend(path, "ap-%s", udev_device_get_sysname(parent)); + out: +- parent = skip_subsystem(parent, "ccw"); ++ parent = skip_subsystem(parent, "ap"); + return parent; + } + +@@ -647,15 +643,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool + bool new_sas_path = false; + bool enable_new_sas_path = true; + +- /* S390 ccw bus */ +- parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL); +- if (parent != NULL) { +- handle_ccw(parent, dev, &path); +- goto out; +- } +- + restart: +- ; ++ + /* walk up the chain of devices and compose path */ + parent = dev; + while (parent != NULL) { +@@ -718,6 +707,25 @@ restart: + supported_parent = true; + supported_transport = true; + } ++ } else if (streq(subsys, "ccw")) { ++ path_prepend(&path, "ccw-%s", udev_device_get_sysname(parent)); ++ parent = skip_subsystem(parent, "ccw"); ++ supported_transport = true; ++ supported_parent = true; ++ } else if (streq(subsys, "ccwgroup")) { ++ path_prepend(&path, "ccwgroup-%s", udev_device_get_sysname(parent)); ++ parent = skip_subsystem(parent, "ccwgroup"); ++ supported_transport = true; ++ supported_parent = true; ++ } else if (streq(subsys, "ap")) { ++ parent = handle_ap(parent, &path); ++ supported_transport = true; ++ supported_parent = true; ++ } else if (streq(subsys, "iucv")) { ++ path_prepend(&path, "iucv-%s", udev_device_get_sysname(parent)); ++ parent = skip_subsystem(parent, "iucv"); ++ supported_transport = true; ++ supported_parent = true; + } + + parent = udev_device_get_parent(parent); +@@ -743,7 +751,6 @@ restart: + path = NULL; + } + +-out: + if (path != NULL) { + char tag[UTIL_NAME_SIZE]; + size_t i; diff --git a/SOURCES/0462-core-port-config_parse_bounding_set-to-extract_first.patch b/SOURCES/0462-core-port-config_parse_bounding_set-to-extract_first.patch new file mode 100644 index 00000000..b493f349 --- /dev/null +++ b/SOURCES/0462-core-port-config_parse_bounding_set-to-extract_first.patch @@ -0,0 +1,70 @@ +From f1801ded8014054752356123849f86b6746f2a49 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 30 Oct 2015 09:25:12 +0300 +Subject: [PATCH] core: port config_parse_bounding_set to extract_first_word + +Cherry-picked from: 9ef57298cc57b105c62e2f1dab9ef5837d910604 +Resolves: #1387398 +--- + src/core/load-fragment.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 6fc4d745d..4830d7ad6 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1028,10 +1028,10 @@ int config_parse_bounding_set(const char *unit, + + uint64_t *capability_bounding_set_drop = data; + uint64_t capability_bounding_set; +- const char *word, *state; +- size_t l; + bool invert = false; + uint64_t sum = 0; ++ const char *prev; ++ const char *cur; + + assert(filename); + assert(lvalue); +@@ -1048,25 +1048,32 @@ int config_parse_bounding_set(const char *unit, + * non-inverted everywhere to have a fully normalized + * interface. */ + +- FOREACH_WORD_QUOTED(word, l, rvalue, state) { +- _cleanup_free_ char *t = NULL; ++ prev = cur = rvalue; ++ for (;;) { ++ _cleanup_free_ char *word = NULL; + int cap; ++ int r; + +- t = strndup(word, l); +- if (!t) ++ r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES); ++ if (r == 0) ++ break; ++ if (r == -ENOMEM) + return log_oom(); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev); ++ break; ++ } + +- cap = capability_from_name(t); ++ cap = capability_from_name(word); + if (cap < 0) { +- log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t); ++ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word); ++ prev = cur; + continue; + } + + sum |= ((uint64_t) 1ULL) << (uint64_t) cap; ++ prev = cur; + } +- if (!isempty(state)) +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "Trailing garbage, ignoring."); + + capability_bounding_set = invert ? ~sum : sum; + if (*capability_bounding_set_drop && capability_bounding_set) diff --git a/SOURCES/0463-core-simplify-parsing-of-capability-bounding-set-set.patch b/SOURCES/0463-core-simplify-parsing-of-capability-bounding-set-set.patch new file mode 100644 index 00000000..abef70ac --- /dev/null +++ b/SOURCES/0463-core-simplify-parsing-of-capability-bounding-set-set.patch @@ -0,0 +1,100 @@ +From 044455df76969ad26dfdcfa186e5ce81beb5b527 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 10 Nov 2015 16:08:03 +0100 +Subject: [PATCH] core: simplify parsing of capability bounding set settings + +Let's generate a simple error, and that's it. Let's not try to be smart +and record the last word that failed. + +Also, let's make sure we don't compare numeric values with 0 by relying +on C's downgrade-to-bool feature, as suggested in CODING_STYLE. + +Cherry-picked from: 65dce26488030eff078c498673d5d93e3c87b6a1 +Resolves: #1387398 +--- + src/core/load-fragment.c | 42 +++++++++++++++++++----------------------- + 1 file changed, 19 insertions(+), 23 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 4830d7ad6..ab3b0c2e9 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1015,23 +1015,22 @@ int config_parse_exec_secure_bits(const char *unit, + return 0; + } + +-int config_parse_bounding_set(const char *unit, +- const char *filename, +- unsigned line, +- const char *section, +- unsigned section_line, +- const char *lvalue, +- int ltype, +- const char *rvalue, +- void *data, +- void *userdata) { ++int config_parse_bounding_set( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { + + uint64_t *capability_bounding_set_drop = data; +- uint64_t capability_bounding_set; ++ uint64_t capability_bounding_set, sum = 0; + bool invert = false; +- uint64_t sum = 0; +- const char *prev; +- const char *cur; ++ const char *p; + + assert(filename); + assert(lvalue); +@@ -1048,35 +1047,32 @@ int config_parse_bounding_set(const char *unit, + * non-inverted everywhere to have a fully normalized + * interface. */ + +- prev = cur = rvalue; ++ p = rvalue; + for (;;) { + _cleanup_free_ char *word = NULL; +- int cap; +- int r; ++ int cap, r; + +- r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES); ++ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev); ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue); + break; + } + + cap = capability_from_name(word); + if (cap < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word); +- prev = cur; + continue; + } + +- sum |= ((uint64_t) 1ULL) << (uint64_t) cap; +- prev = cur; ++ sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap; + } + + capability_bounding_set = invert ? ~sum : sum; +- if (*capability_bounding_set_drop && capability_bounding_set) ++ if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0) + *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); + else + *capability_bounding_set_drop = ~capability_bounding_set; diff --git a/SOURCES/0464-test-add-test-for-capability-bounding-set-parsing.patch b/SOURCES/0464-test-add-test-for-capability-bounding-set-parsing.patch new file mode 100644 index 00000000..7c441e88 --- /dev/null +++ b/SOURCES/0464-test-add-test-for-capability-bounding-set-parsing.patch @@ -0,0 +1,88 @@ +From cac429e0a75667c021782210045c8e365f5cc8b0 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Thu, 29 Oct 2015 14:12:22 +0300 +Subject: [PATCH] test: add test for capability bounding set parsing + +Cherry-picked from: a8107a54 +Resolves: #1387398 +--- + src/test/test-unit-file.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 038430505..0f00a8fff 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -545,6 +546,9 @@ static void test_install_printf(void) { + expect(i4, "%U", "0"); + } + ++static uint64_t make_cap(int cap) { ++ return ((uint64_t) 1ULL << (uint64_t) cap); ++} + + static void test_config_parse_rlimit(void) { + struct rlimit * rl[_RLIMIT_MAX] = {}; +@@ -661,6 +665,46 @@ static void test_config_parse_rlimit(void) { + free(rl[RLIMIT_RTTIME]); + } + ++static void test_config_parse_bounding_set(void) { ++ /* int config_parse_bounding_set( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) */ ++ int r; ++ uint64_t capability_bounding_set_drop = 0; ++ ++ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "CAP_NET_RAW", ++ &capability_bounding_set_drop, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW)); ++ ++ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", ++ &capability_bounding_set_drop, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); ++ ++ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "", ++ &capability_bounding_set_drop, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL)); ++ ++ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "~", ++ &capability_bounding_set_drop, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set_drop == (uint64_t) 0ULL); ++} ++ + int main(int argc, char *argv[]) { + int r; + +@@ -670,6 +714,7 @@ int main(int argc, char *argv[]) { + r = test_unit_file_get_set(); + test_config_parse_exec(); + test_config_parse_rlimit(); ++ test_config_parse_bounding_set(); + test_load_env_file_1(); + test_load_env_file_2(); + test_load_env_file_3(); diff --git a/SOURCES/0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch b/SOURCES/0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch new file mode 100644 index 00000000..16d72f1e --- /dev/null +++ b/SOURCES/0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch @@ -0,0 +1,473 @@ +From 201006fa521199ebf109016c9dd22812c435dfe9 Mon Sep 17 00:00:00 2001 +From: Ismo Puustinen +Date: Fri, 8 Jan 2016 00:00:04 +0200 +Subject: [PATCH] capabilities: keep bounding set in non-inverted format. + +Change the capability bounding set parser and logic so that the bounding +set is kept as a positive set internally. This means that the set +reflects those capabilities that we want to keep instead of drop. + +Resolves: #1387398 +--- + src/core/dbus-execute.c | 4 +- + src/core/execute.c | 9 ++-- + src/core/execute.h | 2 +- + src/core/load-fragment-gperf.gperf.m4 | 2 +- + src/core/load-fragment.c | 25 +++++----- + src/core/load-fragment.h | 2 +- + src/core/main.c | 10 ++-- + src/core/unit.c | 2 +- + src/import/import-common.c | 2 +- + src/nspawn/nspawn.c | 2 +- + src/shared/capability.c | 16 +++---- + src/shared/capability.h | 12 ++++- + src/test/test-unit-file.c | 89 +++++++++++++++++++---------------- + 13 files changed, 96 insertions(+), 81 deletions(-) + +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index da8b10d2b..a564c53fa 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -324,9 +324,7 @@ static int property_get_capability_bounding_set( + assert(reply); + assert(c); + +- /* We store this negated internally, to match the kernel, but +- * we expose it normalized. */ +- return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop); ++ return sd_bus_message_append(reply, "t", c->capability_bounding_set); + } + + static int property_get_capabilities( +diff --git a/src/core/execute.c b/src/core/execute.c +index f72b20966..40db11e28 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1733,8 +1733,8 @@ static int exec_child( + } + } + +- if (context->capability_bounding_set_drop) { +- r = capability_bounding_set_drop(context->capability_bounding_set_drop, false); ++ if (!cap_test_all(context->capability_bounding_set)) { ++ r = capability_bounding_set_drop(context->capability_bounding_set, false); + if (r < 0) { + *exit_status = EXIT_CAPABILITIES; + return r; +@@ -1988,6 +1988,7 @@ void exec_context_init(ExecContext *c) { + c->timer_slack_nsec = NSEC_INFINITY; + c->personality = 0xffffffffUL; + c->runtime_directory_mode = 0755; ++ c->capability_bounding_set = CAP_ALL; + } + + void exec_context_done(ExecContext *c) { +@@ -2419,12 +2420,12 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { + (c->secure_bits & 1<secure_bits & 1<capability_bounding_set_drop) { ++ if (c->capability_bounding_set != CAP_ALL) { + unsigned long l; + fprintf(f, "%sCapabilityBoundingSet:", prefix); + + for (l = 0; l <= cap_last_cap(); l++) +- if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) ++ if (c->capability_bounding_set & (UINT64_C(1) << l)) + fprintf(f, " %s", strna(capability_to_name(l))); + + fputs("\n", f); +diff --git a/src/core/execute.h b/src/core/execute.h +index cadd0e6b4..40f7b794c 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -150,7 +150,7 @@ struct ExecContext { + char **read_write_dirs, **read_only_dirs, **inaccessible_dirs; + unsigned long mount_flags; + +- uint64_t capability_bounding_set_drop; ++ uint64_t capability_bounding_set; + + cap_t capabilities; + int secure_bits; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index b50fe45b4..e4ce29210 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -47,7 +47,7 @@ $1.SyslogLevel, config_parse_log_level, 0, + $1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) + $1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) + $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) +-$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop) ++$1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set) + $1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec) + $1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context) + m4_ifdef(`HAVE_SECCOMP', +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index ab3b0c2e9..dbaaf2fee 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1015,7 +1015,7 @@ int config_parse_exec_secure_bits(const char *unit, + return 0; + } + +-int config_parse_bounding_set( ++int config_parse_capability_set( + const char *unit, + const char *filename, + unsigned line, +@@ -1027,8 +1027,8 @@ int config_parse_bounding_set( + void *data, + void *userdata) { + +- uint64_t *capability_bounding_set_drop = data; +- uint64_t capability_bounding_set, sum = 0; ++ uint64_t *capability_set = data; ++ uint64_t sum = 0, initial = 0; + bool invert = false; + const char *p; + +@@ -1042,10 +1042,8 @@ int config_parse_bounding_set( + rvalue++; + } + +- /* Note that we store this inverted internally, since the +- * kernel wants it like this. But we actually expose it +- * non-inverted everywhere to have a fully normalized +- * interface. */ ++ if (strcmp(lvalue, "CapabilityBoundingSet") == 0) ++ initial = CAP_ALL; /* initialized to all bits on */ + + p = rvalue; + for (;;) { +@@ -1071,11 +1069,14 @@ int config_parse_bounding_set( + sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap; + } + +- capability_bounding_set = invert ? ~sum : sum; +- if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0) +- *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); ++ sum = invert ? ~sum : sum; ++ ++ if (sum == 0 || *capability_set == initial) ++ /* "" or uninitialized data -> replace */ ++ *capability_set = sum; + else +- *capability_bounding_set_drop = ~capability_bounding_set; ++ /* previous data -> merge */ ++ *capability_set |= sum; + + return 0; + } +@@ -4050,7 +4051,7 @@ void unit_dump_config_items(FILE *f) { + { config_parse_log_level, "LEVEL" }, + { config_parse_exec_capabilities, "CAPABILITIES" }, + { config_parse_exec_secure_bits, "SECUREBITS" }, +- { config_parse_bounding_set, "BOUNDINGSET" }, ++ { config_parse_capability_set, "BOUNDINGSET" }, + { config_parse_limit, "LIMIT" }, + { config_parse_unit_deps, "UNIT [...]" }, + { config_parse_exec, "PATH [ARGUMENT [...]]" }, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 9dd7d1bda..2059353d3 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -54,7 +54,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit, const char *filename, uns + int config_parse_exec_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_exec_capabilities(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +-int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_capability_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/core/main.c b/src/core/main.c +index a0df1e5ce..cba992cea 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -108,7 +108,7 @@ static usec_t arg_runtime_watchdog = 0; + static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE; + static char **arg_default_environment = NULL; + static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {}; +-static uint64_t arg_capability_bounding_set_drop = 0; ++static uint64_t arg_capability_bounding_set = CAP_ALL; + static nsec_t arg_timer_slack_nsec = NSEC_INFINITY; + static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE; + static Set* arg_syscall_archs = NULL; +@@ -642,7 +642,7 @@ static int parse_config_file(void) { + { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, + { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, + { "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog }, +- { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop }, ++ { "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set }, + #ifdef HAVE_SECCOMP + { "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs }, + #endif +@@ -1622,14 +1622,14 @@ int main(int argc, char *argv[]) { + if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0) + log_error_errno(errno, "Failed to adjust timer slack: %m"); + +- if (arg_capability_bounding_set_drop) { +- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop); ++ if (!cap_test_all(arg_capability_bounding_set)) { ++ r = capability_bounding_set_drop_usermode(arg_capability_bounding_set); + if (r < 0) { + log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m"); + error_message = "Failed to drop capability bounding set of usermode helpers"; + goto finish; + } +- r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true); ++ r = capability_bounding_set_drop(arg_capability_bounding_set, true); + if (r < 0) { + log_emergency_errno(r, "Failed to drop capability bounding set: %m"); + error_message = "Failed to drop capability bounding set"; +diff --git a/src/core/unit.c b/src/core/unit.c +index 4eb0d78f4..103f92084 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3213,7 +3213,7 @@ int unit_patch_contexts(Unit *u) { + ec->no_new_privileges = true; + + if (ec->private_devices) +- ec->capability_bounding_set_drop |= (uint64_t) 1ULL << (uint64_t) CAP_MKNOD; ++ ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_MKNOD); + } + + cc = unit_get_cgroup_context(u); +diff --git a/src/import/import-common.c b/src/import/import-common.c +index f10a453ee..243e657c5 100644 +--- a/src/import/import-common.c ++++ b/src/import/import-common.c +@@ -526,7 +526,7 @@ int import_fork_tar(const char *path, pid_t *ret) { + if (unshare(CLONE_NEWNET) < 0) + log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m"); + +- r = capability_bounding_set_drop(~retain, true); ++ r = capability_bounding_set_drop(retain, true); + if (r < 0) + log_error_errno(r, "Failed to drop capabilities, ignoring: %m"); + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index a37b64094..d0003d379 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -1863,7 +1863,7 @@ static int setup_journal(const char *directory) { + } + + static int drop_capabilities(void) { +- return capability_bounding_set_drop(~arg_retain, false); ++ return capability_bounding_set_drop(arg_retain, false); + } + + static int register_machine(pid_t pid, int local_ifindex) { +diff --git a/src/shared/capability.c b/src/shared/capability.c +index 2b963fde3..3ed31df5a 100644 +--- a/src/shared/capability.c ++++ b/src/shared/capability.c +@@ -98,7 +98,7 @@ unsigned long cap_last_cap(void) { + return p; + } + +-int capability_bounding_set_drop(uint64_t drop, bool right_now) { ++int capability_bounding_set_drop(uint64_t keep, bool right_now) { + _cleanup_cap_free_ cap_t after_cap = NULL; + cap_flag_value_t fv; + unsigned long i; +@@ -139,7 +139,7 @@ int capability_bounding_set_drop(uint64_t drop, bool right_now) { + + for (i = 0; i <= cap_last_cap(); i++) { + +- if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { ++ if (!(keep & (UINT64_C(1) << i))) { + cap_value_t v; + + /* Drop it from the bounding set */ +@@ -178,7 +178,7 @@ finish: + return r; + } + +-static int drop_from_file(const char *fn, uint64_t drop) { ++static int drop_from_file(const char *fn, uint64_t keep) { + int r, k; + uint32_t hi, lo; + uint64_t current, after; +@@ -198,7 +198,7 @@ static int drop_from_file(const char *fn, uint64_t drop) { + return -EIO; + + current = (uint64_t) lo | ((uint64_t) hi << 32ULL); +- after = current & ~drop; ++ after = current & keep; + + if (current == after) + return 0; +@@ -215,14 +215,14 @@ static int drop_from_file(const char *fn, uint64_t drop) { + return r; + } + +-int capability_bounding_set_drop_usermode(uint64_t drop) { ++int capability_bounding_set_drop_usermode(uint64_t keep) { + int r; + +- r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop); ++ r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep); + if (r < 0) + return r; + +- r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop); ++ r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep); + if (r < 0) + return r; + +@@ -259,7 +259,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) { + return log_error_errno(errno, "Failed to disable keep capabilities flag: %m"); + + /* Drop all caps from the bounding set, except the ones we want */ +- r = capability_bounding_set_drop(~keep_capabilities, true); ++ r = capability_bounding_set_drop(keep_capabilities, true); + if (r < 0) + return log_error_errno(r, "Failed to drop capabilities: %m"); + +diff --git a/src/shared/capability.h b/src/shared/capability.h +index 6f2f6f997..04cd6e54e 100644 +--- a/src/shared/capability.h ++++ b/src/shared/capability.h +@@ -27,10 +27,12 @@ + + #include "util.h" + ++#define CAP_ALL (uint64_t) -1 ++ + unsigned long cap_last_cap(void); + int have_effective_cap(int value); +-int capability_bounding_set_drop(uint64_t drop, bool right_now); +-int capability_bounding_set_drop_usermode(uint64_t drop); ++int capability_bounding_set_drop(uint64_t keep, bool right_now); ++int capability_bounding_set_drop_usermode(uint64_t keep); + + int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites); + +@@ -44,3 +46,9 @@ static inline void cap_free_charpp(char **p) { + cap_free(*p); + } + #define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp) ++ ++static inline bool cap_test_all(uint64_t caps) { ++ uint64_t m; ++ m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1; ++ return (caps & m) == m; ++} +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 0f00a8fff..38ecfe972 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -550,6 +550,53 @@ static uint64_t make_cap(int cap) { + return ((uint64_t) 1ULL << (uint64_t) cap); + } + ++static void test_config_parse_capability_set(void) { ++ /* int config_parse_capability_set( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) */ ++ int r; ++ uint64_t capability_bounding_set = 0; ++ ++ r = config_parse_capability_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "CAP_NET_RAW", ++ &capability_bounding_set, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set == make_cap(CAP_NET_RAW)); ++ ++ r = config_parse_capability_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", ++ &capability_bounding_set, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); ++ ++ r = config_parse_capability_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "", ++ &capability_bounding_set, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set == UINT64_C(0)); ++ ++ r = config_parse_capability_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, "~", ++ &capability_bounding_set, NULL); ++ assert_se(r >= 0); ++ assert_se(cap_test_all(capability_bounding_set)); ++ ++ capability_bounding_set = 0; ++ r = config_parse_capability_set(NULL, "fake", 1, "section", 1, ++ "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage", ++ &capability_bounding_set, NULL); ++ assert_se(r >= 0); ++ assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); ++} ++ + static void test_config_parse_rlimit(void) { + struct rlimit * rl[_RLIMIT_MAX] = {}; + +@@ -665,46 +712,6 @@ static void test_config_parse_rlimit(void) { + free(rl[RLIMIT_RTTIME]); + } + +-static void test_config_parse_bounding_set(void) { +- /* int config_parse_bounding_set( +- const char *unit, +- const char *filename, +- unsigned line, +- const char *section, +- unsigned section_line, +- const char *lvalue, +- int ltype, +- const char *rvalue, +- void *data, +- void *userdata) */ +- int r; +- uint64_t capability_bounding_set_drop = 0; +- +- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, +- "CapabilityBoundingSet", 0, "CAP_NET_RAW", +- &capability_bounding_set_drop, NULL); +- assert_se(r >= 0); +- assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW)); +- +- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, +- "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", +- &capability_bounding_set_drop, NULL); +- assert_se(r >= 0); +- assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); +- +- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, +- "CapabilityBoundingSet", 0, "", +- &capability_bounding_set_drop, NULL); +- assert_se(r >= 0); +- assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL)); +- +- r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, +- "CapabilityBoundingSet", 0, "~", +- &capability_bounding_set_drop, NULL); +- assert_se(r >= 0); +- assert_se(capability_bounding_set_drop == (uint64_t) 0ULL); +-} +- + int main(int argc, char *argv[]) { + int r; + +@@ -713,8 +720,8 @@ int main(int argc, char *argv[]) { + + r = test_unit_file_get_set(); + test_config_parse_exec(); ++ test_config_parse_capability_set(); + test_config_parse_rlimit(); +- test_config_parse_bounding_set(); + test_load_env_file_1(); + test_load_env_file_2(); + test_load_env_file_3(); diff --git a/SOURCES/0466-capabilities-added-support-for-ambient-capabilities.patch b/SOURCES/0466-capabilities-added-support-for-ambient-capabilities.patch new file mode 100644 index 00000000..4df2b219 --- /dev/null +++ b/SOURCES/0466-capabilities-added-support-for-ambient-capabilities.patch @@ -0,0 +1,397 @@ +From ab2c6236a959fe53109cc36f3642b3a7a2051746 Mon Sep 17 00:00:00 2001 +From: Ismo Puustinen +Date: Thu, 31 Dec 2015 14:54:44 +0200 +Subject: [PATCH] capabilities: added support for ambient capabilities. + +This patch adds support for ambient capabilities in service files. The +idea with ambient capabilities is that the execed processes can run with +non-root user and get some inherited capabilities, without having any +need to add the capabilities to the executable file. + +You need at least Linux 4.3 to use ambient capabilities. SecureBit +keep-caps is automatically added when you use ambient capabilities and +wish to change the user. + +An example system service file might look like this: + +[Unit] +Description=Service for testing caps + +[Service] +ExecStart=/usr/bin/sleep 10000 +User=nobody +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW + +After starting the service it has these capabilities: + +CapInh: 0000000000003000 +CapPrm: 0000000000003000 +CapEff: 0000000000003000 +CapBnd: 0000003fffffffff +CapAmb: 0000000000003000 + +Cherry-picked from: 755d4b6 +Resolves: #1387398 +--- + src/core/dbus-execute.c | 19 ++++++++ + src/core/execute.c | 90 ++++++++++++++++++++++++++++------- + src/core/execute.h | 2 + + src/core/load-fragment-gperf.gperf.m4 | 1 + + src/core/load-fragment.c | 4 +- + src/shared/capability.c | 55 +++++++++++++++++++++ + src/shared/capability.h | 3 ++ + src/shared/missing.h | 16 +++++++ + src/test/test-unit-file.c | 1 + + 9 files changed, 174 insertions(+), 17 deletions(-) + +diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c +index a564c53fa..817ef80d1 100644 +--- a/src/core/dbus-execute.c ++++ b/src/core/dbus-execute.c +@@ -327,6 +327,24 @@ static int property_get_capability_bounding_set( + return sd_bus_message_append(reply, "t", c->capability_bounding_set); + } + ++static int property_get_ambient_capabilities( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ++ ExecContext *c = userdata; ++ ++ assert(bus); ++ assert(reply); ++ assert(c); ++ ++ return sd_bus_message_append(reply, "t", c->capability_ambient_set); ++} ++ + static int property_get_capabilities( + sd_bus *bus, + const char *path, +@@ -637,6 +655,7 @@ const sd_bus_vtable bus_exec_vtable[] = { + SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST), +diff --git a/src/core/execute.c b/src/core/execute.c +index 40db11e28..4265b9c34 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -696,12 +696,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) { + /* Sets (but doesn't lookup) the uid and make sure we keep the + * capabilities while doing so. */ + +- if (context->capabilities) { +- _cleanup_cap_free_ cap_t d = NULL; +- static const cap_value_t bits[] = { +- CAP_SETUID, /* Necessary so that we can run setresuid() below */ +- CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */ +- }; ++ if (context->capabilities || context->capability_ambient_set != 0) { + + /* First step: If we need to keep capabilities but + * drop privileges we need to make sure we keep our +@@ -717,16 +712,24 @@ static int enforce_user(const ExecContext *context, uid_t uid) { + /* Second step: set the capabilities. This will reduce + * the capabilities to the minimum we need. */ + +- d = cap_dup(context->capabilities); +- if (!d) +- return -errno; ++ if (context->capabilities) { ++ _cleanup_cap_free_ cap_t d = NULL; ++ static const cap_value_t bits[] = { ++ CAP_SETUID, /* Necessary so that we can run setresuid() below */ ++ CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */ ++ }; + +- if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 || +- cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) +- return -errno; ++ d = cap_dup(context->capabilities); ++ if (!d) ++ return -errno; + +- if (cap_set_proc(d) < 0) +- return -errno; ++ if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 || ++ cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) ++ return -errno; ++ ++ if (cap_set_proc(d) < 0) ++ return -errno; ++ } + } + + /* Third step: actually set the uids */ +@@ -1723,6 +1726,8 @@ static int exec_child( + + if (params->apply_permissions) { + ++ int secure_bits = context->secure_bits; ++ + for (i = 0; i < _RLIMIT_MAX; i++) { + if (!context->rlimit[i]) + continue; +@@ -1750,6 +1755,30 @@ static int exec_child( + } + } + #endif ++ /* This is done before enforce_user, but ambient set ++ * does not survive over setresuid() if keep_caps is not set. */ ++ if (context->capability_ambient_set != 0) { ++ r = capability_ambient_set_apply(context->capability_ambient_set, true); ++ if (r < 0) { ++ *exit_status = EXIT_CAPABILITIES; ++ return r; ++ } ++ ++ if (context->capabilities) { ++ ++ /* The capabilities in ambient set need to be also in the inherited ++ * set. If they aren't, trying to get them will fail. Add the ambient ++ * set inherited capabilities to the capability set in the context. ++ * This is needed because if capabilities are set (using "Capabilities=" ++ * keyword), they will override whatever we set now. */ ++ ++ r = capability_update_inherited_set(context->capabilities, context->capability_ambient_set); ++ if (r < 0) { ++ *exit_status = EXIT_CAPABILITIES; ++ return r; ++ } ++ } ++ } + + if (context->user) { + r = enforce_user(context, uid); +@@ -1757,14 +1786,32 @@ static int exec_child( + *exit_status = EXIT_USER; + return r; + } ++ if (context->capability_ambient_set != 0) { ++ ++ /* Fix the ambient capabilities after user change. */ ++ r = capability_ambient_set_apply(context->capability_ambient_set, false); ++ if (r < 0) { ++ *exit_status = EXIT_CAPABILITIES; ++ return r; ++ } ++ ++ /* If we were asked to change user and ambient capabilities ++ * were requested, we had to add keep-caps to the securebits ++ * so that we would maintain the inherited capability set ++ * through the setresuid(). Make sure that the bit is added ++ * also to the context secure_bits so that we don't try to ++ * drop the bit away next. */ ++ ++ secure_bits |= 1<secure_bits) +- if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) { ++ if (prctl(PR_GET_SECUREBITS) != secure_bits) ++ if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) { + *exit_status = EXIT_SECUREBITS; + return -errno; + } +@@ -2431,6 +2478,17 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { + fputs("\n", f); + } + ++ if (c->capability_ambient_set != 0) { ++ unsigned long l; ++ fprintf(f, "%sAmbientCapabilities:", prefix); ++ ++ for (l = 0; l <= cap_last_cap(); l++) ++ if (c->capability_ambient_set & (UINT64_C(1) << l)) ++ fprintf(f, " %s", strna(capability_to_name(l))); ++ ++ fputs("\n", f); ++ } ++ + if (c->user) + fprintf(f, "%sUser: %s\n", prefix, c->user); + if (c->group) +diff --git a/src/core/execute.h b/src/core/execute.h +index 40f7b794c..00bf99cbe 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -152,6 +152,8 @@ struct ExecContext { + + uint64_t capability_bounding_set; + ++ uint64_t capability_ambient_set; ++ + cap_t capabilities; + int secure_bits; + +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index e4ce29210..f996032cf 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -48,6 +48,7 @@ $1.SyslogLevelPrefix, config_parse_bool, 0, + $1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) + $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) + $1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set) ++$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set) + $1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec) + $1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context) + m4_ifdef(`HAVE_SECCOMP', +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index dbaaf2fee..7d1ac6c25 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -61,6 +61,7 @@ + #include "af-list.h" + #include "cap-list.h" + #include "bus-internal.h" ++#include "capability.h" + + #ifdef HAVE_SECCOMP + #include "seccomp-util.h" +@@ -1044,6 +1045,7 @@ int config_parse_capability_set( + + if (strcmp(lvalue, "CapabilityBoundingSet") == 0) + initial = CAP_ALL; /* initialized to all bits on */ ++ /* else "AmbientCapabilities" initialized to all bits off */ + + p = rvalue; + for (;;) { +@@ -1062,7 +1064,7 @@ int config_parse_capability_set( + + cap = capability_from_name(word); + if (cap < 0) { +- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word); ++ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word); + continue; + } + +diff --git a/src/shared/capability.c b/src/shared/capability.c +index 3ed31df5a..6e3d7d22e 100644 +--- a/src/shared/capability.c ++++ b/src/shared/capability.c +@@ -98,6 +98,61 @@ unsigned long cap_last_cap(void) { + return p; + } + ++int capability_update_inherited_set(cap_t caps, uint64_t set) { ++ unsigned long i; ++ ++ /* Add capabilities in the set to the inherited caps. Do not apply ++ * them yet. */ ++ ++ for (i = 0; i < cap_last_cap(); i++) { ++ ++ if (set & (UINT64_C(1) << i)) { ++ cap_value_t v; ++ ++ v = (cap_value_t) i; ++ ++ /* Make the capability inheritable. */ ++ if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0) ++ return -errno; ++ } ++ } ++ ++ return 0; ++} ++ ++int capability_ambient_set_apply(uint64_t set, bool also_inherit) { ++ unsigned long i; ++ _cleanup_cap_free_ cap_t caps = NULL; ++ ++ /* Add the capabilities to the ambient set. */ ++ ++ if (also_inherit) { ++ int r; ++ caps = cap_get_proc(); ++ if (!caps) ++ return -errno; ++ ++ r = capability_update_inherited_set(caps, set); ++ if (r < 0) ++ return -errno; ++ ++ if (cap_set_proc(caps) < 0) ++ return -errno; ++ } ++ ++ for (i = 0; i < cap_last_cap(); i++) { ++ ++ if (set & (UINT64_C(1) << i)) { ++ ++ /* Add the capability to the ambient set. */ ++ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) ++ return -errno; ++ } ++ } ++ ++ return 0; ++} ++ + int capability_bounding_set_drop(uint64_t keep, bool right_now) { + _cleanup_cap_free_ cap_t after_cap = NULL; + cap_flag_value_t fv; +diff --git a/src/shared/capability.h b/src/shared/capability.h +index 04cd6e54e..76a756856 100644 +--- a/src/shared/capability.h ++++ b/src/shared/capability.h +@@ -36,6 +36,9 @@ int capability_bounding_set_drop_usermode(uint64_t keep); + + int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites); + ++int capability_ambient_set_apply(uint64_t set, bool also_inherit); ++int capability_update_inherited_set(cap_t caps, uint64_t ambient_set); ++ + int drop_capability(cap_value_t cv); + + DEFINE_TRIVIAL_CLEANUP_FUNC(cap_t, cap_free); +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 4b36a9c93..a7771bc99 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -1004,3 +1004,19 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns + #ifndef KCMP_FILE + #define KCMP_FILE 0 + #endif ++ ++#ifndef PR_CAP_AMBIENT ++#define PR_CAP_AMBIENT 47 ++#endif ++ ++#ifndef PR_CAP_AMBIENT_IS_SET ++#define PR_CAP_AMBIENT_IS_SET 1 ++#endif ++ ++#ifndef PR_CAP_AMBIENT_RAISE ++#define PR_CAP_AMBIENT_RAISE 2 ++#endif ++ ++#ifndef PR_CAP_AMBIENT_CLEAR_ALL ++#define PR_CAP_AMBIENT_CLEAR_ALL 4 ++#endif +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 38ecfe972..cfa3d2316 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -38,6 +38,7 @@ + #include "strv.h" + #include "fileio.h" + #include "test-helper.h" ++#include "capability.h" + + static int test_unit_file_get_set(void) { + int r; diff --git a/SOURCES/0467-man-add-AmbientCapabilities-entry.patch b/SOURCES/0467-man-add-AmbientCapabilities-entry.patch new file mode 100644 index 00000000..f279e12b --- /dev/null +++ b/SOURCES/0467-man-add-AmbientCapabilities-entry.patch @@ -0,0 +1,51 @@ +From 734c3a184c3b196412e15e4db1b7419f13b901b4 Mon Sep 17 00:00:00 2001 +From: Ismo Puustinen +Date: Mon, 11 Jan 2016 09:36:14 +0200 +Subject: [PATCH] man: add AmbientCapabilities entry. + +Cherry-picked from: ece8797 +Resolves: #1387398 +--- + man/systemd.exec.xml | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index aa5831cc2..1b14ced78 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -766,6 +766,35 @@ + settings. + + ++ ++ AmbientCapabilities= ++ ++ Controls which capabilities to include in the ++ ambient capability set for the executed process. Takes a ++ whitespace-separated list of capability names as read by ++ cap_from_name3, ++ e.g. CAP_SYS_ADMIN, ++ CAP_DAC_OVERRIDE, ++ CAP_SYS_PTRACE. This option may appear more than ++ once in which case the ambient capability sets are merged. ++ If the list of capabilities is prefixed with ~, all ++ but the listed capabilities will be included, the effect of the ++ assignment inverted. If the empty string is ++ assigned to this option, the ambient capability set is reset to ++ the empty capability set, and all prior settings have no effect. ++ If set to ~ (without any further argument), the ++ ambient capability set is reset to the full set of available ++ capabilities, also undoing any previous settings. Note that adding ++ capabilities to ambient capability set adds them to the process's ++ inherited capability set. ++ ++ Ambient capability sets are useful if you want to execute a process ++ as a non-privileged user but still want to give it some capabilities. ++ Note that in this case option keep-caps is ++ automatically added to SecureBits= to retain the ++ capabilities over the user change. ++ ++ + + SecureBits= + Controls the secure bits set for the executed diff --git a/SOURCES/0468-test-capability-rebase-to-upstream-version.patch b/SOURCES/0468-test-capability-rebase-to-upstream-version.patch new file mode 100644 index 00000000..3c517249 --- /dev/null +++ b/SOURCES/0468-test-capability-rebase-to-upstream-version.patch @@ -0,0 +1,353 @@ +From 900251c41dab192ff863024e07864c09462e86d2 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 20 Mar 2017 12:24:09 +0100 +Subject: [PATCH] test-capability: rebase to upstream version + +Related: #1387398 +--- + src/test/test-capability.c | 80 +++++++++++++++++++--- + src/test/test-execute.c | 43 ++++++++++++ + ...ec-capabilityambientset-merge-nfsnobody.service | 9 +++ + test/exec-capabilityambientset-merge.service | 9 +++ + test/exec-capabilityambientset-nfsnobody.service | 8 +++ + test/exec-capabilityambientset.service | 8 +++ + test/exec-capabilityboundingset-invert.service | 7 ++ + test/exec-capabilityboundingset-merge.service | 8 +++ + test/exec-capabilityboundingset-reset.service | 8 +++ + test/exec-capabilityboundingset-simple.service | 7 ++ + 10 files changed, 179 insertions(+), 8 deletions(-) + create mode 100644 test/exec-capabilityambientset-merge-nfsnobody.service + create mode 100644 test/exec-capabilityambientset-merge.service + create mode 100644 test/exec-capabilityambientset-nfsnobody.service + create mode 100644 test/exec-capabilityambientset.service + create mode 100644 test/exec-capabilityboundingset-invert.service + create mode 100644 test/exec-capabilityboundingset-merge.service + create mode 100644 test/exec-capabilityboundingset-reset.service + create mode 100644 test/exec-capabilityboundingset-simple.service + +diff --git a/src/test/test-capability.c b/src/test/test-capability.c +index 43769923b..67a9ec2d1 100644 +--- a/src/test/test-capability.c ++++ b/src/test/test-capability.c +@@ -17,21 +17,22 @@ + along with systemd; If not, see . + ***/ + +-#include +-#include +-#include +-#include + #include + #include ++#include ++#include ++#include ++#include + #include + + #include "capability.h" +-#include "util.h" + #include "macro.h" ++#include "util.h" + + static uid_t test_uid = -1; + static gid_t test_gid = -1; +-// We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage ++ ++/* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */ + static uint64_t test_flags = 1ULL << CAP_DAC_OVERRIDE; + + static void fork_test(void (*test_func)(void)) { +@@ -65,8 +66,9 @@ static void show_capabilities(void) { + cap_free(text); + } + +-static int setup_tests(void) { ++static int setup_tests(bool *run_ambient) { + struct passwd *nobody; ++ int r; + + nobody = getpwnam("nobody"); + if (!nobody) { +@@ -76,6 +78,18 @@ static int setup_tests(void) { + test_uid = nobody->pw_uid; + test_gid = nobody->pw_gid; + ++ *run_ambient = false; ++ ++ r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); ++ ++ /* There's support for PR_CAP_AMBIENT if the prctl() call ++ * succeeded or error code was something else than EINVAL. The ++ * EINVAL check should be good enough to rule out false ++ * positives. */ ++ ++ if (r >= 0 || errno != EINVAL) ++ *run_ambient = true; ++ + return 0; + } + +@@ -139,8 +153,53 @@ static void test_have_effective_cap(void) { + assert_se(!have_effective_cap(CAP_CHOWN)); + } + ++static void test_update_inherited_set(void) { ++ cap_t caps; ++ uint64_t set = 0; ++ cap_flag_value_t fv; ++ ++ caps = cap_get_proc(); ++ assert_se(caps); ++ assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); ++ assert(fv == CAP_CLEAR); ++ ++ set = (UINT64_C(1) << CAP_CHOWN); ++ ++ assert_se(!capability_update_inherited_set(caps, set)); ++ assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); ++ assert(fv == CAP_SET); ++ ++ cap_free(caps); ++} ++ ++static void test_set_ambient_caps(void) { ++ cap_t caps; ++ uint64_t set = 0; ++ cap_flag_value_t fv; ++ ++ caps = cap_get_proc(); ++ assert_se(caps); ++ assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); ++ assert(fv == CAP_CLEAR); ++ cap_free(caps); ++ ++ assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0); ++ ++ set = (UINT64_C(1) << CAP_CHOWN); ++ ++ assert_se(!capability_ambient_set_apply(set, true)); ++ ++ caps = cap_get_proc(); ++ assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); ++ assert(fv == CAP_SET); ++ cap_free(caps); ++ ++ assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1); ++} ++ + int main(int argc, char *argv[]) { + int r; ++ bool run_ambient; + + log_parse_environment(); + log_open(); +@@ -148,14 +207,19 @@ int main(int argc, char *argv[]) { + if (getuid() != 0) + return EXIT_TEST_SKIP; + +- r = setup_tests(); ++ r = setup_tests(&run_ambient); + if (r < 0) + return -r; + + show_capabilities(); + + test_drop_privileges(); ++ test_update_inherited_set(); ++ + fork_test(test_have_effective_cap); + ++ if (run_ambient) ++ fork_test(test_set_ambient_caps); ++ + return 0; + } +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 6e5567c3e..8e70702cb 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -17,7 +17,11 @@ + along with systemd; If not, see . + ***/ + ++#include ++#include + #include ++#include ++#include + + #include "unit.h" + #include "manager.h" +@@ -25,6 +29,7 @@ + #include "macro.h" + #include "strv.h" + #include "mkdir.h" ++#include "path-util.h" + + typedef void (*test_function_t)(Manager *m); + +@@ -177,6 +182,42 @@ static void test_exec_runtimedirectory(Manager *m) { + test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + } + ++static void test_exec_capabilityboundingset(Manager *m) { ++ int r; ++ ++ r = find_binary("capsh", true, NULL); ++ if (r < 0) { ++ log_error_errno(r, "Skipping %s, could not find capsh binary: %m", __func__); ++ return; ++ } ++ ++ test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED); ++ test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED); ++ test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED); ++ test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED); ++} ++ ++static void test_exec_capabilityambientset(Manager *m) { ++ int r; ++ ++ /* Check if the kernel has support for ambient capabilities. Run ++ * the tests only if that's the case. Clearing all ambient ++ * capabilities is fine, since we are expecting them to be unset ++ * in the first place for the tests. */ ++ r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); ++ if (r >= 0 || errno != EINVAL) { ++ if (getpwnam("nobody")) { ++ test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); ++ test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); ++ } else if (getpwnam("nfsnobody")) { ++ test(m, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED); ++ test(m, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED); ++ } else ++ log_error_errno(errno, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__); ++ } else ++ log_error_errno(errno, "Skipping %s, the kernel does not support ambient capabilities: %m", __func__); ++} ++ + int main(int argc, char *argv[]) { + test_function_t tests[] = { + test_exec_workingdirectory, +@@ -192,6 +233,8 @@ int main(int argc, char *argv[]) { + test_exec_passenvironment, + test_exec_umask, + test_exec_runtimedirectory, ++ test_exec_capabilityboundingset, ++ test_exec_capabilityambientset, + NULL, + }; + test_function_t *test = NULL; +diff --git a/test/exec-capabilityambientset-merge-nfsnobody.service b/test/exec-capabilityambientset-merge-nfsnobody.service +new file mode 100644 +index 000000000..00bec581b +--- /dev/null ++++ b/test/exec-capabilityambientset-merge-nfsnobody.service +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Test for AmbientCapabilities ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' ++Type=oneshot ++User=nfsnobody ++AmbientCapabilities=CAP_NET_ADMIN ++AmbientCapabilities=CAP_NET_RAW +diff --git a/test/exec-capabilityambientset-merge.service b/test/exec-capabilityambientset-merge.service +new file mode 100644 +index 000000000..64964380e +--- /dev/null ++++ b/test/exec-capabilityambientset-merge.service +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Test for AmbientCapabilities ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' ++Type=oneshot ++User=nobody ++AmbientCapabilities=CAP_NET_ADMIN ++AmbientCapabilities=CAP_NET_RAW +diff --git a/test/exec-capabilityambientset-nfsnobody.service b/test/exec-capabilityambientset-nfsnobody.service +new file mode 100644 +index 000000000..614cfdd58 +--- /dev/null ++++ b/test/exec-capabilityambientset-nfsnobody.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for AmbientCapabilities ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' ++Type=oneshot ++User=nfsnobody ++AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW +diff --git a/test/exec-capabilityambientset.service b/test/exec-capabilityambientset.service +new file mode 100644 +index 000000000..d63f884ef +--- /dev/null ++++ b/test/exec-capabilityambientset.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for AmbientCapabilities ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' ++Type=oneshot ++User=nobody ++AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW +diff --git a/test/exec-capabilityboundingset-invert.service b/test/exec-capabilityboundingset-invert.service +new file mode 100644 +index 000000000..fd5d24870 +--- /dev/null ++++ b/test/exec-capabilityboundingset-invert.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for CapabilityBoundingSet ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "^Bounding set .*cap_chown"); test -z "$$c"' ++Type=oneshot ++CapabilityBoundingSet=~CAP_CHOWN +diff --git a/test/exec-capabilityboundingset-merge.service b/test/exec-capabilityboundingset-merge.service +new file mode 100644 +index 000000000..5c7fcaf43 +--- /dev/null ++++ b/test/exec-capabilityboundingset-merge.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for CapabilityBoundingSet ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_chown,cap_fowner,cap_kill"' ++Type=oneshot ++CapabilityBoundingSet=CAP_FOWNER ++CapabilityBoundingSet=CAP_KILL CAP_CHOWN +diff --git a/test/exec-capabilityboundingset-reset.service b/test/exec-capabilityboundingset-reset.service +new file mode 100644 +index 000000000..d7d332020 +--- /dev/null ++++ b/test/exec-capabilityboundingset-reset.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for CapabilityBoundingSet ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set ="' ++Type=oneshot ++CapabilityBoundingSet=CAP_FOWNER CAP_KILL ++CapabilityBoundingSet= +diff --git a/test/exec-capabilityboundingset-simple.service b/test/exec-capabilityboundingset-simple.service +new file mode 100644 +index 000000000..bf1a7f575 +--- /dev/null ++++ b/test/exec-capabilityboundingset-simple.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for CapabilityBoundingSet ++ ++[Service] ++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_fowner,cap_kill"' ++Type=oneshot ++CapabilityBoundingSet=CAP_FOWNER CAP_KILL diff --git a/SOURCES/0469-namespace-don-t-fail-on-masked-mounts.patch b/SOURCES/0469-namespace-don-t-fail-on-masked-mounts.patch new file mode 100644 index 00000000..e9671923 --- /dev/null +++ b/SOURCES/0469-namespace-don-t-fail-on-masked-mounts.patch @@ -0,0 +1,54 @@ +From 8d166597076d87aae9d5f98144103386c79d6446 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 31 Mar 2017 09:47:46 +0200 +Subject: [PATCH] namespace: don't fail on masked mounts + +Before this patch, a service file with ReadWriteDirectories=/file... +could fail if the file exists but is not a mountpoint, despite being +listed in /proc/self/mountinfo. It could happen with masked mounts. + +(cherry picked from commit 98df8089bea1b2407c46495b6c2eb76dda46c658) + +Resolves: #1433687 +--- + src/shared/util.c | 23 +++++++++++------------ + 1 file changed, 11 insertions(+), 12 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 1070e32c4..3e13cc1fd 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -7332,22 +7332,21 @@ int bind_remount_recursive(const char *prefix, bool ro) { + if (r < 0) + return r; + +- /* Try to reuse the original flag set, but +- * don't care for errors, in case of +- * obstructed mounts */ ++ /* Deal with mount points that are obstructed by a ++ * later mount */ ++ r = path_is_mount_point(x, 0); ++ if (r == -ENOENT || r == 0) ++ continue; ++ if (r < 0) ++ return r; ++ ++ /* Try to reuse the original flag set */ + orig_flags = 0; + (void) get_mount_flags(x, &orig_flags); + orig_flags &= ~MS_RDONLY; + +- if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { +- +- /* Deal with mount points that are +- * obstructed by a later mount */ +- +- if (errno != ENOENT) +- return -errno; +- } +- ++ if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) ++ return -errno; + } + } + } diff --git a/SOURCES/0470-sysv-generator-Provides-network-should-also-pull-net.patch b/SOURCES/0470-sysv-generator-Provides-network-should-also-pull-net.patch new file mode 100644 index 00000000..ff0d13c5 --- /dev/null +++ b/SOURCES/0470-sysv-generator-Provides-network-should-also-pull-net.patch @@ -0,0 +1,30 @@ +From 1649dac4656e8056e5fe5fa99e5753257efe1a42 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Thu, 30 Mar 2017 11:12:50 +0200 +Subject: [PATCH] sysv-generator: Provides: $network should also pull + network.target to transaction (#5652) + +network.target should be pulled in to the transaction +by the unit that provides network services, but currently +for initscripts it only pulls in network-online.target. + +Cherry-picked from: bd9ad4ff5bf2252f46ccf0cb91b3ed16def1c1a4 +Resolves: #1438749 +--- + src/sysv-generator/sysv-generator.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 7e0e7fc28..fe6fae151 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -500,6 +500,9 @@ static int load_sysv(SysvStub *s) { + r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET); + if (r < 0) + return log_oom(); ++ r = strv_extend(&s->wants, SPECIAL_NETWORK_TARGET); ++ if (r < 0) ++ return log_oom(); + } + } + diff --git a/SOURCES/0471-Install-correctly-report-symlink-creations.patch b/SOURCES/0471-Install-correctly-report-symlink-creations.patch new file mode 100644 index 00000000..3af8ca75 --- /dev/null +++ b/SOURCES/0471-Install-correctly-report-symlink-creations.patch @@ -0,0 +1,45 @@ +From b5eddaf0dea35bda7b68a401119c5f9f9104fb99 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Mon, 11 Apr 2016 21:03:29 +0200 +Subject: [PATCH] Install: correctly report symlink creations + +All callers of create_symlink(), such as install_info_symlink_wants(), expect +that to return > 0 if it actually did something, and then return that number. +unit_file_enable() uses that to determine if any action was done +(carries_install_info != 0) and if not, show a "The unit files have no +[Install] section" warning. + +Return 1 instead of 0 in the two code paths of create_symlink() when the link +was created or replaced with a new value. + +This fixes getting a bogus "No [Install] section" warning when enabling a unit +with full path, like "systemctl enable /some/path/myunit.service". + +(cherry picked from commit 3de1521427dee61000c1c124a521182b301a50de) +Resolves: #1435098 +--- + src/shared/install.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index bdfd7b96a..e73f0c95b 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -283,7 +283,7 @@ static int create_symlink( + + if (symlink(old_path, new_path) >= 0) { + unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); +- return 0; ++ return 1; + } + + if (errno != EEXIST) +@@ -306,7 +306,7 @@ static int create_symlink( + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); + unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); + +- return 0; ++ return 1; + } + + static int mark_symlink_for_removal( diff --git a/SOURCES/0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch b/SOURCES/0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch new file mode 100644 index 00000000..9a4a0b70 --- /dev/null +++ b/SOURCES/0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch @@ -0,0 +1,32 @@ +From 33d6abe2452c8222b926f917171d65ed934d0136 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 11 Apr 2017 15:15:00 +0200 +Subject: [PATCH] rules/40-redhat.rules: rules should be on one line + +rhel-only +Related: #1274401 +--- + rules/40-redhat.rules | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index c928d412b..34a1df9c4 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -29,14 +29,10 @@ ACTION=="remove", GOTO="zfcp_scsi_device_end" + KERNEL=="sd*", SUBSYSTEMS=="ccw", DRIVERS=="zfcp", ENV{.ID_ZFCP_BUS}="1" + + # For SCSI disks +-KERNEL=="sd*[!0-9]", SUBSYSTEMS=="scsi", +- ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="disk", +- SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}" ++KERNEL=="sd*[!0-9]", SUBSYSTEMS=="scsi", ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}" + + + # For partitions on a SCSI disk +-KERNEL=="sd*[0-9]", SUBSYSTEMS=="scsi", +- ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="partition", +- SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}-part%n" ++KERNEL=="sd*[0-9]", SUBSYSTEMS=="scsi", ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}-part%n" + + LABEL="zfcp_scsi_device_end" diff --git a/SOURCES/0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch b/SOURCES/0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch new file mode 100644 index 00000000..e5672b73 --- /dev/null +++ b/SOURCES/0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch @@ -0,0 +1,173 @@ +From f2d7881cf56b2d1448b9e09c46c076a14a05011d Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 11 Apr 2017 11:20:36 +0200 +Subject: [PATCH] tmpfiles: add new 'e' action which cleans up a dir without + creating it + +I wanted to add a config line that would empty a directory +without creating it if doesn't exist. Existing actions don't allow +this. + +v2: properly add 'e' to needs_glob() and takes_ownership() + +(cherry picked from commit df8dee85da5fa41e95dd7f536e67fcc6940a6488) +Resolves: #1225739 +--- + man/tmpfiles.d.xml | 9 ++++++++- + src/tmpfiles/tmpfiles.c | 51 +++++++++++++++---------------------------------- + 2 files changed, 23 insertions(+), 37 deletions(-) + +diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml +index fc1fe13ac..fc9db622e 100644 +--- a/man/tmpfiles.d.xml ++++ b/man/tmpfiles.d.xml +@@ -161,6 +161,13 @@ + Create or empty a directory. + + ++ ++ e ++ Clean directory contents based on the age argument. ++ Lines of this type accept shell-style globs in ++ place of normal path names. ++ ++ + + v + Create a subvolume if the path does not +@@ -467,7 +474,7 @@ + + The age field only applies to lines + starting with d, +- D, and ++ D, e and + x. If omitted or set to + -, no automatic clean-up is + done. +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index bda89df5b..df7676b57 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -79,6 +79,7 @@ typedef enum ItemType { + + /* These ones take globs */ + WRITE_FILE = 'w', ++ EMPTY_DIRECTORY = 'e', + SET_XATTR = 't', + RECURSIVE_SET_XATTR = 'T', + SET_ACL = 'a', +@@ -150,6 +151,7 @@ static bool needs_glob(ItemType t) { + IGNORE_PATH, + IGNORE_DIRECTORY_PATH, + REMOVE_PATH, ++ EMPTY_DIRECTORY, + RECURSIVE_REMOVE_PATH, + ADJUST_MODE, + RELABEL_PATH, +@@ -165,6 +167,7 @@ static bool takes_ownership(ItemType t) { + CREATE_FILE, + TRUNCATE_FILE, + CREATE_DIRECTORY, ++ EMPTY_DIRECTORY, + TRUNCATE_DIRECTORY, + CREATE_SUBVOLUME, + CREATE_FIFO, +@@ -1059,6 +1062,9 @@ static int create_item(Item *i) { + + log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path); + ++ /* fall through */ ++ ++ case EMPTY_DIRECTORY: + r = path_set_perms(i, i->path); + if (r < 0) + return r; +@@ -1285,43 +1291,19 @@ static int remove_item_instance(Item *i, const char *instance) { + } + + static int remove_item(Item *i) { +- int r = 0; +- + assert(i); + + log_debug("Running remove action for entry %c %s", (char) i->type, i->path); + + switch (i->type) { +- +- case CREATE_FILE: +- case TRUNCATE_FILE: +- case CREATE_DIRECTORY: +- case CREATE_SUBVOLUME: +- case CREATE_FIFO: +- case CREATE_SYMLINK: +- case CREATE_CHAR_DEVICE: +- case CREATE_BLOCK_DEVICE: +- case IGNORE_PATH: +- case IGNORE_DIRECTORY_PATH: +- case ADJUST_MODE: +- case RELABEL_PATH: +- case RECURSIVE_RELABEL_PATH: +- case WRITE_FILE: +- case COPY_FILES: +- case SET_XATTR: +- case RECURSIVE_SET_XATTR: +- case SET_ACL: +- case RECURSIVE_SET_ACL: +- break; +- + case REMOVE_PATH: + case TRUNCATE_DIRECTORY: + case RECURSIVE_REMOVE_PATH: +- r = glob_item(i, remove_item_instance, false); +- break; +- } ++ return glob_item(i, remove_item_instance, false); + +- return r; ++ default: ++ return 0; ++ } + } + + static int clean_item_instance(Item *i, const char* instance) { +@@ -1377,8 +1359,6 @@ static int clean_item_instance(Item *i, const char* instance) { + } + + static int clean_item(Item *i) { +- int r = 0; +- + assert(i); + + log_debug("Running clean action for entry %c %s", (char) i->type, i->path); +@@ -1386,19 +1366,17 @@ static int clean_item(Item *i) { + switch (i->type) { + case CREATE_DIRECTORY: + case CREATE_SUBVOLUME: ++ case EMPTY_DIRECTORY: + case TRUNCATE_DIRECTORY: + case IGNORE_PATH: + case COPY_FILES: + clean_item_instance(i, i->path); +- break; ++ return 0; + case IGNORE_DIRECTORY_PATH: +- r = glob_item(i, clean_item_instance, false); +- break; ++ return glob_item(i, clean_item_instance, false); + default: +- break; ++ return 0; + } +- +- return r; + } + + static int process_item_array(ItemArray *array); +@@ -1642,6 +1620,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + case TRUNCATE_FILE: + case CREATE_DIRECTORY: + case CREATE_SUBVOLUME: ++ case EMPTY_DIRECTORY: + case TRUNCATE_DIRECTORY: + case CREATE_FIFO: + case IGNORE_PATH: diff --git a/SOURCES/0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch b/SOURCES/0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch new file mode 100644 index 00000000..1ba2f79c --- /dev/null +++ b/SOURCES/0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch @@ -0,0 +1,28 @@ +From 32efad544d53f7c1745eb36eef0df95ef96d1c15 Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Tue, 9 Jun 2015 10:32:28 +0200 +Subject: [PATCH] util:bind_remount_recursive(): handle return 0 of + set_consume() + +set_consume() does not return -EEXIST, but 0, in case the key is already +in the Set. + +Cherry-picked from: 85d834ae8e7d9e2c28ef8c1388e2913ed8fd0e3b +Resolves: #1433687 +--- + src/shared/util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 3e13cc1fd..cadaddee3 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -7327,7 +7327,7 @@ int bind_remount_recursive(const char *prefix, bool ro) { + while ((x = set_steal_first(todo))) { + + r = set_consume(done, x); +- if (r == -EEXIST) ++ if (r == -EEXIST || r == 0) + continue; + if (r < 0) + return r; diff --git a/SOURCES/0475-core-add-support-for-the-pids-cgroup-controller.patch b/SOURCES/0475-core-add-support-for-the-pids-cgroup-controller.patch new file mode 100644 index 00000000..5fa27c08 --- /dev/null +++ b/SOURCES/0475-core-add-support-for-the-pids-cgroup-controller.patch @@ -0,0 +1,622 @@ +From 7d44d0d43465892d4753ff50592588f49d56cf95 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 10 Sep 2015 12:32:16 +0200 +Subject: [PATCH] core: add support for the "pids" cgroup controller + +This adds support for the new "pids" cgroup controller of 4.3 kernels. +It allows accounting the number of tasks in a cgroup and enforcing +limits on it. + +This adds two new setting TasksAccounting= and TasksMax= to each unit, +as well as a gloabl option DefaultTasksAccounting=. + +This also updated "cgtop" to optionally make use of the new +kernel-provided accounting. + +systemctl has been updated to show the number of tasks for each service +if it is available. + +This patch also adds correct support for undoing memory limits for units +using a MemoryLimit=infinity syntax. We do the same for TasksMax= now +and hence keep things in sync here. + +Cherry-picked from: 03a7b521e3ffb7f5d153d90480ba5d4bc29d1e8f +Resolves: #1337244 +--- + man/systemd-system.conf.xml | 22 ++++++------ + man/systemd.resource-control.xml | 63 ++++++++++++++++++++++++++++------- + src/core/cgroup.c | 44 ++++++++++++++++++++++++ + src/core/cgroup.h | 5 +++ + src/core/dbus-cgroup.c | 41 ++++++++++++++++++++++- + src/core/dbus-unit.c | 25 ++++++++++++++ + src/core/load-fragment-gperf.gperf.m4 | 2 ++ + src/core/load-fragment.c | 37 +++++++++++++++++--- + src/core/load-fragment.h | 1 + + src/core/main.c | 3 ++ + src/core/manager.h | 1 + + src/core/unit.c | 1 + + src/shared/cgroup-util.h | 1 + + src/systemctl/systemctl.c | 17 ++++++++++ + 14 files changed, 236 insertions(+), 27 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 57b3b90be..d367ccd13 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -51,14 +51,14 @@ + + + +- /etc/systemd/system.conf +- /etc/systemd/system.conf.d/*.conf +- /run/systemd/system.conf.d/*.conf +- /usr/lib/systemd/system.conf.d/*.conf +- /etc/systemd/user.conf +- /etc/systemd/user.conf.d/*.conf +- /run/systemd/user.conf.d/*.conf +- /usr/lib/systemd/user.conf.d/*.conf ++ /etc/systemd/system.conf, ++ /etc/systemd/system.conf.d/*.conf, ++ /run/systemd/system.conf.d/*.conf, ++ /usr/lib/systemd/system.conf.d/*.conf ++ /etc/systemd/user.conf, ++ /etc/systemd/user.conf.d/*.conf, ++ /run/systemd/user.conf.d/*.conf, ++ /usr/lib/systemd/user.conf.d/*.conf + + + +@@ -307,12 +307,14 @@ + DefaultCPUAccounting= + DefaultBlockIOAccounting= + DefaultMemoryAccounting= ++ DefaultTasksAccounting= + + Configure the default resource accounting + settings, as configured per-unit by + CPUAccounting=, +- BlockIOAccounting= and +- MemoryAccounting=. See ++ BlockIOAccounting=, ++ MemoryAccounting= and ++ TasksAccounting=. See + systemd.resource-control5 + for details on the per-unit settings. + +diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml +index 8f4e7a3f1..6b9329bbe 100644 +--- a/man/systemd.resource-control.xml ++++ b/man/systemd.resource-control.xml +@@ -103,10 +103,10 @@ + + Turn on CPU usage accounting for this unit. Takes a + boolean argument. Note that turning on CPU accounting for +- one unit might also implicitly turn it on for all units ++ one unit will also implicitly turn it on for all units + contained in the same slice and for all its parent slices + and the units contained therein. The system default for this +- setting maybe controlled with ++ setting may be controlled with + DefaultCPUAccounting= in + systemd-system.conf5. + +@@ -134,7 +134,7 @@ + prioritizing specific services at boot-up differently than + during normal runtime. + +- Those options imply ++ These options imply + CPUAccounting=true. + + +@@ -168,9 +168,10 @@ + + Turn on process and kernel memory accounting for this + unit. Takes a boolean argument. Note that turning on memory +- accounting for one unit might also implicitly turn it on for +- all its parent slices. The system default for this setting +- maybe controlled with ++ accounting for one unit will also implicitly turn it on for ++ all units contained in the same slice and for all its parent ++ slices and the units contained therein. The system default ++ for this setting may be controlled with + DefaultMemoryAccounting= in + systemd-system.conf5. + +@@ -186,26 +187,64 @@ + memory size in bytes. If the value is suffixed with K, M, G + or T, the specified memory size is parsed as Kilobytes, + Megabytes, Gigabytes, or Terabytes (with the base 1024), +- respectively. This controls the +- memory.limit_in_bytes control group +- attribute. For details about this control group attribute, +- see infinity no memory limit is applied. This ++ controls the memory.limit_in_bytes ++ control group attribute. For details about this control ++ group attribute, see memory.txt. + + Implies MemoryAccounting=true. + + + ++ ++ TasksAccounting= ++ ++ ++ Turn on task accounting for this unit. Takes a ++ boolean argument. If enabled, the system manager will keep ++ track of the number of tasks in the unit. The number of ++ tasks accounted this way includes both kernel threads and ++ userspace processes, with each thread counting ++ individually. Note that turning on tasks accounting for one ++ unit will also implicitly turn it on for all units contained ++ in the same slice and for all its parent slices and the ++ units contained therein. The system default for this setting ++ may be controlled with ++ DefaultTasksAccounting= in ++ systemd-system.conf5. ++ ++ ++ ++ ++ TasksMax=N ++ ++ ++ Specify the maximum number of tasks that may be ++ created in the unit. This ensures that the number of tasks ++ accounted for the unit (see above) stays below a specific ++ limit. If assigned the special value ++ infinity no tasks limit is applied. This ++ controls the pids.max control group ++ attribute. For details about this control group attribute, ++ see pids.txt. ++ ++ Implies TasksAccounting=true. ++ ++ ++ + + BlockIOAccounting= + + + Turn on Block IO accounting for this unit. Takes a + boolean argument. Note that turning on block IO accounting +- for one unit might also implicitly turn it on for all units ++ for one unit will also implicitly turn it on for all units + contained in the same slice and all for its parent slices + and the units contained therein. The system default for this +- setting maybe controlled with ++ setting may be controlled with + DefaultBlockIOAccounting= in + systemd-system.conf5. + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index b7f08fb42..d4a8f9cbe 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -40,6 +40,7 @@ void cgroup_context_init(CGroupContext *c) { + 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; + } +@@ -105,6 +106,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + "%sBlockIOWeight=%lu\n" + "%sStartupBlockIOWeight=%lu\n" + "%sMemoryLimit=%" PRIu64 "\n" ++ "%sTasksMax=%" PRIu64 "\n" + "%sDevicePolicy=%s\n" + "%sDelegate=%s\n", + prefix, yes_no(c->cpu_accounting), +@@ -116,6 +118,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + prefix, c->blockio_weight, + prefix, c->startup_blockio_weight, + prefix, c->memory_limit, ++ prefix, c->tasks_max, + prefix, cgroup_device_policy_to_string(c->device_policy), + prefix, yes_no(c->delegate)); + +@@ -456,6 +459,21 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha + log_debug("Ignoring device %s while writing cgroup attribute.", a->path); + } + } ++ ++ if ((mask & CGROUP_PIDS) && !is_root) { ++ ++ if (c->tasks_max != (uint64_t) -1) { ++ char buf[DECIMAL_STR_MAX(uint64_t) + 2]; ++ ++ sprintf(buf, "%" PRIu64 "\n", c->tasks_max); ++ r = cg_set_attribute("pids", path, "pids.max", buf); ++ } else ++ r = cg_set_attribute("pids", path, "pids.max", "max"); ++ ++ if (r < 0) ++ log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, ++ "Failed to set pids.max on %s: %m", path); ++ } + } + + CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) { +@@ -484,6 +502,10 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) { + c->device_policy != CGROUP_AUTO) + mask |= CGROUP_DEVICE; + ++ if (c->tasks_accounting || ++ c->tasks_max != (uint64_t) -1) ++ mask |= CGROUP_PIDS; ++ + return mask; + } + +@@ -1044,6 +1066,28 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { + return 0; + } + ++int unit_get_tasks_current(Unit *u, uint64_t *ret) { ++ _cleanup_free_ char *v = NULL; ++ int r; ++ ++ assert(u); ++ assert(ret); ++ ++ if (!u->cgroup_path) ++ return -ENODATA; ++ ++ if ((u->cgroup_realized_mask & CGROUP_PIDS) == 0) ++ return -ENODATA; ++ ++ r = cg_get_attribute("pids", u->cgroup_path, "pids.current", &v); ++ if (r == -ENOENT) ++ return -ENODATA; ++ if (r < 0) ++ return r; ++ ++ return safe_atou64(v, ret); ++} ++ + static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = { + [CGROUP_AUTO] = "auto", + [CGROUP_CLOSED] = "closed", +diff --git a/src/core/cgroup.h b/src/core/cgroup.h +index 8fa851de3..8af3eaa3a 100644 +--- a/src/core/cgroup.h ++++ b/src/core/cgroup.h +@@ -72,6 +72,7 @@ struct CGroupContext { + bool cpu_accounting; + bool blockio_accounting; + bool memory_accounting; ++ bool tasks_accounting; + + unsigned long cpu_shares; + unsigned long startup_cpu_shares; +@@ -88,6 +89,8 @@ struct CGroupContext { + LIST_HEAD(CGroupDeviceAllow, device_allow); + + bool delegate; ++ ++ uint64_t tasks_max; + }; + + #include "unit.h" +@@ -127,5 +130,7 @@ pid_t unit_search_main_pid(Unit *u); + + int manager_notify_cgroup_empty(Manager *m, const char *group); + ++int unit_get_tasks_current(Unit *u, uint64_t *ret); ++ + const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_; + CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_; +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index 4a9df0601..a4465dc7a 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -168,6 +168,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), + SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), + SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), ++ SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0), ++ SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0), + SD_BUS_VTABLE_END + }; + +@@ -551,7 +553,11 @@ int bus_cgroup_set_property( + if (mode != UNIT_CHECK) { + c->memory_limit = limit; + u->cgroup_realized_mask &= ~CGROUP_MEMORY; +- unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit); ++ ++ if (limit == (uint64_t) -1) ++ unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity"); ++ else ++ unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit); + } + + return 1; +@@ -667,6 +673,39 @@ int bus_cgroup_set_property( + + return 1; + ++ } else if (streq(name, "TasksAccounting")) { ++ int b; ++ ++ r = sd_bus_message_read(message, "b", &b); ++ if (r < 0) ++ return r; ++ ++ if (mode != UNIT_CHECK) { ++ c->tasks_accounting = b; ++ u->cgroup_realized_mask &= ~CGROUP_PIDS; ++ unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no"); ++ } ++ ++ return 1; ++ ++ } else if (streq(name, "TasksMax")) { ++ uint64_t limit; ++ ++ r = sd_bus_message_read(message, "t", &limit); ++ if (r < 0) ++ return r; ++ ++ if (mode != UNIT_CHECK) { ++ c->tasks_max = limit; ++ u->cgroup_realized_mask &= ~CGROUP_PIDS; ++ ++ if (limit == (uint64_t) -1) ++ unit_write_drop_in_private(u, mode, name, "TasksMax=infinity"); ++ else ++ unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); ++ } ++ ++ return 1; + } + + if (u->transient && u->load_state == UNIT_STUB) { +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 056a17ac1..1d0d6f67c 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -673,11 +673,36 @@ static int property_get_current_memory( + return sd_bus_message_append(reply, "t", sz); + } + ++static int property_get_current_tasks( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ++ uint64_t cn = (uint64_t) -1; ++ Unit *u = userdata; ++ int r; ++ ++ assert(bus); ++ assert(reply); ++ assert(u); ++ ++ r = unit_get_tasks_current(u, &cn); ++ if (r < 0 && r != -ENODATA) ++ log_unit_warning_errno(u->id, r, "Failed to get pids.current attribute: %m"); ++ ++ return sd_bus_message_append(reply, "t", cn); ++} ++ + const sd_bus_vtable bus_unit_cgroup_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0), + SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0), + SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0), ++ SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0), + SD_BUS_VTABLE_END + }; + +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index f996032cf..26e4c618e 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -125,6 +125,8 @@ $1.StartupBlockIOWeight, config_parse_blockio_weight, 0, + $1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context) + $1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) + $1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) ++$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting) ++$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context) + $1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)' + )m4_dnl + Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 7d1ac6c25..7d2e737d0 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3052,7 +3052,7 @@ int config_parse_memory_limit( + off_t bytes; + int r; + +- if (isempty(rvalue)) { ++ if (isempty(rvalue) || streq(rvalue, "infinity")) { + c->memory_limit = (uint64_t) -1; + return 0; + } +@@ -3060,9 +3060,8 @@ int config_parse_memory_limit( + assert_cc(sizeof(uint64_t) == sizeof(off_t)); + + r = parse_size(rvalue, 1024, &bytes); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "Memory limit '%s' invalid. Ignoring.", rvalue); ++ if (r < 0 || bytes < 1) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } + +@@ -3070,6 +3069,36 @@ int config_parse_memory_limit( + return 0; + } + ++int config_parse_tasks_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) { ++ ++ CGroupContext *c = data; ++ uint64_t u; ++ int r; ++ ++ if (isempty(rvalue) || streq(rvalue, "infinity")) { ++ c->tasks_max = (uint64_t) -1; ++ return 0; ++ } ++ ++ r = safe_atou64(rvalue, &u); ++ if (r < 0 || u < 1) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); ++ return 0; ++ } ++ ++ return 0; ++} ++ + int config_parse_device_allow( + const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 2059353d3..8d334f2c8 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -89,6 +89,7 @@ int config_parse_pass_environ(const char *unit, const char *filename, unsigned l + int config_parse_unit_slice(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_cpu_shares(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_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_tasks_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); + int config_parse_device_policy(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_device_allow(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_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/core/main.c b/src/core/main.c +index cba992cea..aca05a535 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -117,6 +117,7 @@ static bool arg_default_cpu_accounting = false; + static bool arg_default_blockio_accounting = false; + static bool arg_default_memory_accounting = false; + static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; ++static bool arg_default_tasks_accounting = false; + + static void nop_handler(int sig) {} + +@@ -676,6 +677,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, + { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, + { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, ++ { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, + {} + }; + +@@ -1685,6 +1687,7 @@ int main(int argc, char *argv[]) { + m->default_cpu_accounting = arg_default_cpu_accounting; + m->default_blockio_accounting = arg_default_blockio_accounting; + m->default_memory_accounting = arg_default_memory_accounting; ++ m->default_tasks_accounting = arg_default_tasks_accounting; + m->runtime_watchdog = arg_runtime_watchdog; + m->shutdown_watchdog = arg_shutdown_watchdog; + +diff --git a/src/core/manager.h b/src/core/manager.h +index 231c076b1..96dcd83dc 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -261,6 +261,7 @@ struct Manager { + bool default_cpu_accounting; + bool default_memory_accounting; + bool default_blockio_accounting; ++ bool default_tasks_accounting; + + usec_t default_timer_accuracy_usec; + +diff --git a/src/core/unit.c b/src/core/unit.c +index 103f92084..2fcb4fbf0 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -126,6 +126,7 @@ static void unit_init(Unit *u) { + cc->cpu_accounting = u->manager->default_cpu_accounting; + cc->blockio_accounting = u->manager->default_blockio_accounting; + cc->memory_accounting = u->manager->default_memory_accounting; ++ cc->tasks_accounting = u->manager->default_tasks_accounting; + } + + ec = unit_get_exec_context(u); +diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h +index 96a3d3baf..31bd8d311 100644 +--- a/src/shared/cgroup-util.h ++++ b/src/shared/cgroup-util.h +@@ -35,6 +35,7 @@ typedef enum CGroupControllerMask { + CGROUP_BLKIO = 4, + CGROUP_MEMORY = 8, + CGROUP_DEVICE = 16, ++ CGROUP_PIDS = 32, + _CGROUP_CONTROLLER_MASK_ALL = 31 + } CGroupControllerMask; + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 0333599c8..b1862b567 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -3280,6 +3280,8 @@ typedef struct UnitStatusInfo { + /* CGroup */ + uint64_t memory_current; + uint64_t memory_limit; ++ uint64_t tasks_current; ++ uint64_t tasks_max; + + LIST_HEAD(ExecStatusInfo, exec); + } UnitStatusInfo; +@@ -3539,6 +3541,15 @@ static void print_status_info( + if (i->status_errno > 0) + printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno)); + ++ if (i->tasks_current != (uint64_t) -1) { ++ printf(" Tasks: %" PRIu64, i->tasks_current); ++ ++ if (i->tasks_max != (uint64_t) -1) ++ printf(" (limit: %" PRIi64 ")\n", i->tasks_max); ++ else ++ printf("\n"); ++ } ++ + if (i->memory_current != (uint64_t) -1) { + char buf[FORMAT_BYTES_MAX]; + +@@ -3768,6 +3779,10 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * + i->memory_current = u; + else if (streq(name, "MemoryLimit")) + i->memory_limit = u; ++ else if (streq(name, "TasksCurrent")) ++ i->tasks_current = u; ++ else if (streq(name, "TasksMax")) ++ i->tasks_max = u; + + break; + } +@@ -4248,6 +4263,8 @@ static int show_one( + UnitStatusInfo info = { + .memory_current = (uint64_t) -1, + .memory_limit = (uint64_t) -1, ++ .tasks_current = (uint64_t) -1, ++ .tasks_max = (uint64_t) -1, + }; + ExecStatusInfo *p; + int r; diff --git a/SOURCES/0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch b/SOURCES/0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch new file mode 100644 index 00000000..2c6a5dc2 --- /dev/null +++ b/SOURCES/0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch @@ -0,0 +1,201 @@ +From fc7fdb72096d2baeec3238a0ef324569a05da4ae Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 13 Nov 2015 17:13:55 +0100 +Subject: [PATCH] core: add new DefaultTasksMax= setting for system.conf + +This allows initializing the TasksMax= setting of all units by default +to some fixed value, instead of leaving it at infinity as before. + +Cherry-picked from: 0af20ea2ee2af2bcf2258e7a8e1a13181a6a75d6 +Related: #1337244 +--- + man/systemd-system.conf.xml | 13 ++++++++++++- + man/systemd.resource-control.xml | 5 ++++- + src/core/dbus-manager.c | 1 + + src/core/load-fragment-gperf.gperf.m4 | 2 +- + src/core/load-fragment.c | 7 ++++--- + src/core/main.c | 3 +++ + src/core/manager.h | 1 + + src/core/system.conf | 2 ++ + src/core/unit.c | 3 +++ + src/shared/cgroup-util.c | 3 ++- + 10 files changed, 33 insertions(+), 7 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index d367ccd13..53e8ff665 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -1,4 +1,4 @@ +- ++ + + +@@ -319,6 +319,17 @@ + for details on the per-unit settings. + + ++ ++ DefaultTasksMax= ++ ++ Configure the default value for the per-unit ++ TasksMax= setting. See ++ systemd.resource-control5 ++ for details. This setting applies to all unit types that ++ support resource control settings, with the exception of slice ++ units. ++ ++ + + DefaultLimitCPU= + DefaultLimitFSIZE= +diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml +index 6b9329bbe..217105ee5 100644 +--- a/man/systemd.resource-control.xml ++++ b/man/systemd.resource-control.xml +@@ -231,7 +231,10 @@ + see pids.txt. + +- Implies TasksAccounting=true. ++ Implies TasksAccounting=true. The ++ system default for this setting may be controlled with ++ DefaultTasksMax= in ++ systemd-system.conf5. + + + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 7ba1b519e..c92f8c6bf 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2039,6 +2039,7 @@ const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0), + SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0), + SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0), ++ SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST), + + SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 26e4c618e..b2fe627af 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -126,7 +126,7 @@ $1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, + $1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) + $1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) + $1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting) +-$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context) ++$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max) + $1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)' + )m4_dnl + Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 7d2e737d0..c1ffee2c7 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3081,12 +3081,11 @@ int config_parse_tasks_max( + void *data, + void *userdata) { + +- CGroupContext *c = data; +- uint64_t u; ++ uint64_t *tasks_max = data, u; + int r; + + if (isempty(rvalue) || streq(rvalue, "infinity")) { +- c->tasks_max = (uint64_t) -1; ++ *tasks_max = (uint64_t) -1; + return 0; + } + +@@ -3096,6 +3095,8 @@ int config_parse_tasks_max( + return 0; + } + ++ *tasks_max = u; ++ + return 0; + } + +diff --git a/src/core/main.c b/src/core/main.c +index aca05a535..50c9714f7 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -118,6 +118,7 @@ static bool arg_default_blockio_accounting = false; + static bool arg_default_memory_accounting = false; + static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; + static bool arg_default_tasks_accounting = false; ++static uint64_t arg_default_tasks_max = (uint64_t) -1; + + static void nop_handler(int sig) {} + +@@ -678,6 +679,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, + { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, + { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, ++ { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max }, + {} + }; + +@@ -1688,6 +1690,7 @@ int main(int argc, char *argv[]) { + m->default_blockio_accounting = arg_default_blockio_accounting; + m->default_memory_accounting = arg_default_memory_accounting; + m->default_tasks_accounting = arg_default_tasks_accounting; ++ m->default_tasks_max = arg_default_tasks_max; + m->runtime_watchdog = arg_runtime_watchdog; + m->shutdown_watchdog = arg_shutdown_watchdog; + +diff --git a/src/core/manager.h b/src/core/manager.h +index 96dcd83dc..e91e7bd8b 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -263,6 +263,7 @@ struct Manager { + bool default_blockio_accounting; + bool default_tasks_accounting; + ++ uint64_t default_tasks_max; + usec_t default_timer_accuracy_usec; + + struct rlimit *rlimit[_RLIMIT_MAX]; +diff --git a/src/core/system.conf b/src/core/system.conf +index a11f59903..91ef01cd0 100644 +--- a/src/core/system.conf ++++ b/src/core/system.conf +@@ -40,6 +40,8 @@ + #DefaultCPUAccounting=no + #DefaultBlockIOAccounting=no + #DefaultMemoryAccounting=no ++#DefaultTasksAccounting=no ++#DefaultTasksMax= + #DefaultLimitCPU= + #DefaultLimitFSIZE= + #DefaultLimitDATA= +diff --git a/src/core/unit.c b/src/core/unit.c +index 2fcb4fbf0..6a2ad6ed3 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -127,6 +127,9 @@ static void unit_init(Unit *u) { + cc->blockio_accounting = u->manager->default_blockio_accounting; + cc->memory_accounting = u->manager->default_memory_accounting; + cc->tasks_accounting = u->manager->default_tasks_accounting; ++ ++ if (u->type != UNIT_SLICE) ++ cc->tasks_max = u->manager->default_tasks_max; + } + + ec = unit_get_exec_context(u); +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index cf757d2b2..c5d9e4bb5 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -1606,7 +1606,8 @@ static const char mask_names[] = + "cpuacct\0" + "blkio\0" + "memory\0" +- "devices\0"; ++ "devices\0" ++ "pids\0"; + + int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) { + CGroupControllerMask bit = 1; diff --git a/SOURCES/0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch b/SOURCES/0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch new file mode 100644 index 00000000..78951ef4 --- /dev/null +++ b/SOURCES/0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch @@ -0,0 +1,373 @@ +From ff5349960f1cf7af5404b0f765c57eb386c91216 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 13 Nov 2015 18:25:02 +0100 +Subject: [PATCH] logind: add a new UserTasksMax= setting to logind.conf + +This new setting configures the TasksMax= field for the slice objects we +create for each user. + +This alters logind to create the slice unit as transient unit explicitly +instead of relying on implicit generation of slice units by simply +starting them. This also enables us to set a friendly description for +slice units that way. + +Cherry-picked from: 90558f315844ec35e3fd4f1a19ac38c8721c9354 +Conflicts: + src/login/logind-dbus.c + src/login/logind-user.c + src/login/logind.conf + src/login/logind.h + +Resolves: #1337244 +--- + man/logind.conf.xml | 15 ++++++- + src/login/logind-dbus.c | 94 +++++++++++++++++++++++++++++++++++++++++++- + src/login/logind-gperf.gperf | 1 + + src/login/logind-session.c | 25 +++++++----- + src/login/logind-session.h | 3 +- + src/login/logind-user.c | 41 +++++++++++++------ + src/login/logind.c | 1 + + src/login/logind.conf | 1 + + src/login/logind.h | 4 +- + 9 files changed, 160 insertions(+), 25 deletions(-) + +diff --git a/man/logind.conf.xml b/man/logind.conf.xml +index 54651f07d..bcc8ee975 100644 +--- a/man/logind.conf.xml ++++ b/man/logind.conf.xml +@@ -1,4 +1,4 @@ +- ++ + + +@@ -262,7 +262,18 @@ + limit relative to the amount of physical RAM. Defaults to 10%. + Note that this size is a safety limit only. As each runtime + directory is a tmpfs file system, it will only consume as much +- memory as is needed. ++ memory as is needed. ++ ++ ++ ++ UserTasksMax= ++ ++ Sets the maximum number of OS tasks each user ++ may run concurrently. This controls the ++ TasksMax= setting of the per-user slice ++ unit, see ++ systemd.resource-control5 ++ for details. + + + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index fb84e92e5..63b9a0df3 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -2325,13 +2325,101 @@ int manager_dispatch_delayed(Manager *manager) { + return 1; + } + ++int manager_start_slice( ++ Manager *manager, ++ const char *slice, ++ const char *description, ++ const char *after, ++ const char *after2, ++ uint64_t tasks_max, ++ sd_bus_error *error, ++ char **job) { ++ ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; ++ int r; ++ ++ assert(manager); ++ assert(slice); ++ ++ r = sd_bus_message_new_method_call( ++ manager->bus, ++ &m, ++ "org.freedesktop.systemd1", ++ "/org/freedesktop/systemd1", ++ "org.freedesktop.systemd1.Manager", ++ "StartTransientUnit"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append(m, "ss", strempty(slice), "fail"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_open_container(m, 'a', "(sv)"); ++ if (r < 0) ++ return r; ++ ++ if (!isempty(description)) { ++ r = sd_bus_message_append(m, "(sv)", "Description", "s", description); ++ if (r < 0) ++ return r; ++ } ++ ++ if (!isempty(after)) { ++ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after); ++ if (r < 0) ++ return r; ++ } ++ ++ if (!isempty(after2)) { ++ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_close_container(m); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append(m, "a(sa(sv))", 0); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_call(manager->bus, m, 0, error, &reply); ++ if (r < 0) ++ return r; ++ ++ if (job) { ++ const char *j; ++ char *copy; ++ ++ r = sd_bus_message_read(reply, "o", &j); ++ if (r < 0) ++ return r; ++ ++ copy = strdup(j); ++ if (!copy) ++ return -ENOMEM; ++ ++ *job = copy; ++ } ++ ++ return 1; ++} ++ + int manager_start_scope( + Manager *manager, + const char *scope, + pid_t pid, + const char *slice, + const char *description, +- const char *after, const char *after2, ++ const char *after, ++ const char *after2, ++ uint64_t tasks_max, + sd_bus_error *error, + char **job) { + +@@ -2399,6 +2487,10 @@ int manager_start_scope( + if (r < 0) + return r; + ++ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max); ++ if (r < 0) ++ return r; ++ + r = sd_bus_message_close_container(m); + if (r < 0) + return r; +diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf +index 62460673b..8a064e2a9 100644 +--- a/src/login/logind-gperf.gperf ++++ b/src/login/logind-gperf.gperf +@@ -33,3 +33,4 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag + Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec) + Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size) + Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc) ++Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max) +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 746e50aa5..4575a029f 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -510,21 +510,28 @@ static int session_start_scope(Session *s) { + + if (!s->scope) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- _cleanup_free_ char *description = NULL; + char *scope, *job = NULL; +- +- description = strjoin("Session ", s->id, " of user ", s->user->name, NULL); +- if (!description) +- return log_oom(); ++ const char *description; + + scope = strjoin("session-", s->id, ".scope", NULL); + if (!scope) + return log_oom(); + +- r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job); ++ description = strjoina("Session ", s->id, " of user ", s->user->name, NULL); ++ ++ r = manager_start_scope( ++ s->manager, ++ scope, ++ s->leader, ++ s->user->slice, ++ description, ++ "systemd-logind.service", ++ "systemd-user-sessions.service", ++ (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */ ++ &error, ++ &job); + if (r < 0) { +- log_error("Failed to start session scope %s: %s %s", +- scope, bus_error_message(&error, r), error.name); ++ log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r)); + free(scope); + return r; + } else { +@@ -536,7 +543,7 @@ static int session_start_scope(Session *s) { + } + + if (s->scope) +- hashmap_put(s->manager->session_units, s->scope, s); ++ (void) hashmap_put(s->manager->session_units, s->scope, s); + + return 0; + } +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 5002b6868..d662082d8 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -115,7 +115,8 @@ struct Session { + + bool in_gc_queue:1; + bool started:1; +- bool stopping:1; ++ ++ bool stopping; + + sd_bus_message *create_message; + +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 97eb4feca..4298704ce 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -33,6 +33,7 @@ + #include "special.h" + #include "unit-name.h" + #include "bus-util.h" ++#include "bus-common-errors.h" + #include "bus-error.h" + #include "conf-parser.h" + #include "clean-ipc.h" +@@ -367,34 +368,52 @@ fail: + } + + static int user_start_slice(User *u) { +- char *job; + int r; + + assert(u); + + if (!u->slice) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice; +- sprintf(lu, UID_FMT, u->uid); ++ char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice, *job; ++ const char *description; ++ ++ free(u->slice_job); ++ u->slice_job = NULL; + ++ xsprintf(lu, UID_FMT, u->uid); + r = build_subslice(SPECIAL_USER_SLICE, lu, &slice); + if (r < 0) +- return r; +- +- r = manager_start_unit(u->manager, slice, &error, &job); ++ return log_error_errno(r, "Failed to build slice name: %m"); ++ ++ description = strjoina("User Slice of ", u->name); ++ ++ r = manager_start_slice( ++ u->manager, ++ slice, ++ description, ++ "systemd-logind.service", ++ "systemd-user-sessions.service", ++ u->manager->user_tasks_max, ++ &error, ++ &job); + if (r < 0) { +- log_error("Failed to start user slice: %s", bus_error_message(&error, r)); +- free(slice); ++ ++ if (sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS)) ++ /* The slice already exists? If so, that's fine, let's just reuse it */ ++ u->slice = slice; ++ else { ++ log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", slice, bus_error_message(&error, r), error.name); ++ free(slice); ++ /* we don't fail due to this, let's try to continue */ ++ } + } else { + u->slice = slice; +- +- free(u->slice_job); + u->slice_job = job; + } + } + + if (u->slice) +- hashmap_put(u->manager->user_units, u->slice, u); ++ (void) hashmap_put(u->manager->user_units, u->slice, u); + + return 0; + } +diff --git a/src/login/logind.c b/src/login/logind.c +index e8d0669bb..16c931c3e 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -63,6 +63,7 @@ Manager *manager_new(void) { + m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); + + m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ ++ m->user_tasks_max = (uint64_t) -1; + + m->devices = hashmap_new(&string_hash_ops); + m->seats = hashmap_new(&string_hash_ops); +diff --git a/src/login/logind.conf b/src/login/logind.conf +index be8d7dff2..d33e0b34d 100644 +--- a/src/login/logind.conf ++++ b/src/login/logind.conf +@@ -31,3 +31,4 @@ + #IdleActionSec=30min + #RuntimeDirectorySize=10% + #RemoveIPC=no ++#UserTasksMax= +diff --git a/src/login/logind.h b/src/login/logind.h +index e0cb7d023..8503eb24d 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -128,6 +128,7 @@ struct Manager { + sd_event_source *lid_switch_ignore_event_source; + + size_t runtime_dir_size; ++ uint64_t user_tasks_max; + }; + + Manager *manager_new(void); +@@ -176,7 +177,8 @@ int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_ + + int manager_dispatch_delayed(Manager *manager); + +-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job); ++int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job); ++int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job); + int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); + int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); + int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error); diff --git a/SOURCES/0478-core-support-percentage-specifications-on-TasksMax.patch b/SOURCES/0478-core-support-percentage-specifications-on-TasksMax.patch new file mode 100644 index 00000000..67dac1d7 --- /dev/null +++ b/SOURCES/0478-core-support-percentage-specifications-on-TasksMax.patch @@ -0,0 +1,313 @@ +From 7ec6e537898e139cc33017e03465ef40a86dd433 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 Jul 2016 15:58:49 +0200 +Subject: [PATCH] core: support percentage specifications on TasksMax= + +This adds support for a TasksMax=40% syntax for specifying values relative to +the system's configured maximum number of processes. This is useful in order to +neatly subdivide the available room for tasks within containers. + +Cherry-picked from: 83f8e80857090f63cf6a02c54d381dad3c0fad55 +Related: #1337244 +--- + man/systemd.resource-control.xml | 15 +++---- + src/core/dbus-cgroup.c | 22 +++++++++++ + src/core/load-fragment.c | 15 +++++-- + src/libsystemd/sd-bus/bus-util.c | 19 +++++++++ + src/shared/util.c | 84 ++++++++++++++++++++++++++++++++++++++++ + src/shared/util.h | 5 +++ + src/test/test-util.c | 39 +++++++++++++++++++ + 7 files changed, 187 insertions(+), 12 deletions(-) + +diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml +index 217105ee5..f507c6748 100644 +--- a/man/systemd.resource-control.xml ++++ b/man/systemd.resource-control.xml +@@ -221,15 +221,12 @@ + TasksMax=N + + +- Specify the maximum number of tasks that may be +- created in the unit. This ensures that the number of tasks +- accounted for the unit (see above) stays below a specific +- limit. If assigned the special value +- infinity no tasks limit is applied. This +- controls the pids.max control group +- attribute. For details about this control group attribute, +- see pids.txt. ++ Specify the maximum number of tasks that may be created in the unit. This ensures that the number of ++ tasks accounted for the unit (see above) stays below a specific limit. This either takes an absolute number ++ of tasks or a percentage value that is taken relative to the configured maximum number of tasks on the ++ system. If assigned the special value infinity, no tasks limit is applied. This controls ++ the pids.max control group attribute. For details about this control group attribute, see ++ pids.txt. + + Implies TasksAccounting=true. The + system default for this setting may be controlled with +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index a4465dc7a..fa76c60c1 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -694,6 +694,8 @@ int bus_cgroup_set_property( + r = sd_bus_message_read(message, "t", &limit); + if (r < 0) + return r; ++ if (limit <= 0) ++ return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name); + + if (mode != UNIT_CHECK) { + c->tasks_max = limit; +@@ -705,6 +707,26 @@ int bus_cgroup_set_property( + unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); + } + ++ return 1; ++ } else if (streq(name, "TasksMaxScale")) { ++ uint64_t limit; ++ uint32_t raw; ++ ++ r = sd_bus_message_read(message, "u", &raw); ++ if (r < 0) ++ return r; ++ ++ limit = system_tasks_max_scale(raw, UINT32_MAX); ++ if (limit <= 0 || limit >= UINT64_MAX) ++ return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name); ++ ++ if (mode != UNIT_CHECK) { ++ c->tasks_max = limit; ++ u->cgroup_realized_mask &= ~CGROUP_PIDS; ++ unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%", ++ (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); ++ } ++ + return 1; + } + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index c1ffee2c7..411475024 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3089,9 +3089,18 @@ int config_parse_tasks_max( + return 0; + } + +- r = safe_atou64(rvalue, &u); +- if (r < 0 || u < 1) { +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); ++ r = parse_percent(rvalue); ++ if (r < 0) { ++ r = safe_atou64(rvalue, &u); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); ++ return 0; ++ } ++ } else ++ u = system_tasks_max_scale(r, 100U); ++ ++ if (u <= 0 || u >= UINT64_MAX) { ++ log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue); + return 0; + } + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index ed0849b63..f46fa2bbf 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1409,7 +1409,26 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + } + + r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes); ++ } else if (streq(field, "TasksMax")) { ++ uint64_t t; ++ ++ 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 = sd_bus_message_append(m, "sv", "TasksMax", "t", t); + } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) { + uint64_t u; + +diff --git a/src/shared/util.c b/src/shared/util.c +index cadaddee3..bbb457759 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -94,6 +94,7 @@ + #include "def.h" + #include "sparse-endian.h" + #include "conf-parser.h" ++#include "cgroup-util.h" + + int saved_argc = 0; + char **saved_argv = NULL; +@@ -8707,3 +8708,86 @@ int extract_many_words(const char **p, const char *separators, ExtractFlags flag + + return c; + } ++ ++int parse_percent_unbounded(const char *p) { ++ const char *pc, *n; ++ unsigned v; ++ int r; ++ ++ pc = endswith(p, "%"); ++ if (!pc) ++ return -EINVAL; ++ ++ n = strndupa(p, pc - p); ++ r = safe_atou(n, &v); ++ if (r < 0) ++ return r; ++ ++ return (int) v; ++} ++ ++int parse_percent(const char *p) { ++ int v; ++ ++ v = parse_percent_unbounded(p); ++ if (v > 100) ++ return -ERANGE; ++ ++ return v; ++} ++ ++uint64_t system_tasks_max(void) { ++ ++#if SIZEOF_PID_T == 4 ++#define TASKS_MAX ((uint64_t) (INT32_MAX-1)) ++#elif SIZEOF_PID_T == 2 ++#define TASKS_MAX ((uint64_t) (INT16_MAX-1)) ++#else ++#error "Unknown pid_t size" ++#endif ++ ++ _cleanup_free_ char *value = NULL, *root = NULL; ++ uint64_t a = TASKS_MAX, b = TASKS_MAX; ++ ++ /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this ++ * limit: ++ * ++ * a) the maximum value for the pid_t type ++ * b) the cgroups pids_max attribute for the system ++ * c) the kernel's configure maximum PID value ++ * ++ * And then pick the smallest of the three */ ++ ++ if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0) ++ (void) safe_atou64(value, &a); ++ ++ if (cg_get_root_path(&root) >= 0) { ++ free(value); ++ value = NULL; ++ ++ if (cg_get_attribute("pids", root, "pids.max", &value) >= 0) ++ (void) safe_atou64(value, &b); ++ } ++ ++ return MIN3(TASKS_MAX, ++ a <= 0 ? TASKS_MAX : a, ++ b <= 0 ? TASKS_MAX : b); ++} ++ ++uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { ++ uint64_t t, m; ++ ++ assert(max > 0); ++ ++ /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages ++ * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */ ++ ++ t = system_tasks_max(); ++ assert(t > 0); ++ ++ m = t * v; ++ if (m / t != v) /* overflow? */ ++ return UINT64_MAX; ++ ++ return m / max; ++} +diff --git a/src/shared/util.h b/src/shared/util.h +index 12afcc342..f1b6c348f 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -1098,3 +1098,8 @@ typedef enum ExtractFlags { + int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); + int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); + int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; ++int parse_percent_unbounded(const char *p); ++int parse_percent(const char *p); ++ ++uint64_t system_tasks_max(void); ++uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 9ae347b43..971f97d7c 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -1530,6 +1530,43 @@ static void test_shell_maybe_quote(void) { + test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); + } + ++static void test_system_tasks_max(void) { ++ uint64_t t; ++ ++ t = system_tasks_max(); ++ assert_se(t > 0); ++ assert_se(t < UINT64_MAX); ++ ++ log_info("Max tasks: %" PRIu64, t); ++} ++ ++static void test_system_tasks_max_scale(void) { ++ uint64_t t; ++ ++ t = system_tasks_max(); ++ ++ assert_se(system_tasks_max_scale(0, 100) == 0); ++ assert_se(system_tasks_max_scale(100, 100) == t); ++ ++ assert_se(system_tasks_max_scale(0, 1) == 0); ++ assert_se(system_tasks_max_scale(1, 1) == t); ++ assert_se(system_tasks_max_scale(2, 1) == 2*t); ++ ++ assert_se(system_tasks_max_scale(0, 2) == 0); ++ assert_se(system_tasks_max_scale(1, 2) == t/2); ++ assert_se(system_tasks_max_scale(2, 2) == t); ++ assert_se(system_tasks_max_scale(3, 2) == (3*t)/2); ++ assert_se(system_tasks_max_scale(4, 2) == t*2); ++ ++ assert_se(system_tasks_max_scale(0, UINT32_MAX) == 0); ++ assert_se(system_tasks_max_scale((UINT32_MAX-1)/2, UINT32_MAX-1) == t/2); ++ assert_se(system_tasks_max_scale(UINT32_MAX, UINT32_MAX) == t); ++ ++ /* overflow */ ++ ++ assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); ++} ++ + int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); +@@ -1608,6 +1645,8 @@ int main(int argc, char *argv[]) { + test_uid_ptr(); + test_sparse_write(); + test_shell_maybe_quote(); ++ test_system_tasks_max(); ++ test_system_tasks_max_scale(); + + return 0; + } diff --git a/SOURCES/0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch b/SOURCES/0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch new file mode 100644 index 00000000..540a1bfb --- /dev/null +++ b/SOURCES/0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch @@ -0,0 +1,84 @@ +From 7f72b471bbfd449f4261d12cc7b062f6e7034283 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 17:40:50 +0200 +Subject: [PATCH] core: reinstate propagation of stop/restart jobs via + RequsiteOf dependencies + +This reverts the primary effect of be7d9ff730cb88d7c6a869dd5c47754c78ceaef2. + +After all Requisite= should be close to Requires=, without the one +exception that it doesn't pull in dependencies on start. However, +reverse deps on stop/restart should be treated the same way as for +Restart=, and this is already documented in the man page, hence stick to +it. + +http://lists.freedesktop.org/archives/systemd-devel/2015-May/032049.html +(cherry picked from commit ce74e76920dca603a12ef4bf605567965e9e7e45) + +[msekleta: we didn't backport be7d9ff730cb88d7c6a869dd5c47754c78ceaef2 +and hence we don't have UNIT_REQUISITE_OF. Note that this patch was +backported because it makes backports of followup patches easier] + +Related: #1436021 +--- + src/core/transaction.c | 41 +++++++++++++---------------------------- + 1 file changed, 13 insertions(+), 28 deletions(-) + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index 57e9cb3f8..428b7671b 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -1008,40 +1008,25 @@ int transaction_add_job_and_dependencies( + } + + if (type == JOB_STOP || type == JOB_RESTART) { ++ static const UnitDependency propagate_deps[] = { ++ UNIT_REQUIRED_BY, ++ UNIT_BOUND_BY, ++ UNIT_CONSISTS_OF, ++ }; + +- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) { +- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); +- if (r < 0) { +- if (r != -EBADR) +- goto fail; +- +- if (e) +- sd_bus_error_free(e); +- } +- } +- +- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) { +- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); +- if (r < 0) { +- if (r != -EBADR) +- goto fail; ++ unsigned j; + +- if (e) +- sd_bus_error_free(e); +- } +- } ++ for (j = 0; j < ELEMENTSOF(propagate_deps); j++) ++ SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) { + +- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) { +- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); +- if (r < 0) { +- if (r != -EBADR) +- goto fail; ++ r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); ++ if (r < 0) { ++ if (r != -EBADR) ++ goto fail; + +- if (e) + sd_bus_error_free(e); ++ } + } +- } +- + } + + if (type == JOB_RELOAD) { diff --git a/SOURCES/0480-core-when-propagating-restart-requests-due-to-deps-d.patch b/SOURCES/0480-core-when-propagating-restart-requests-due-to-deps-d.patch new file mode 100644 index 00000000..4053e4e9 --- /dev/null +++ b/SOURCES/0480-core-when-propagating-restart-requests-due-to-deps-d.patch @@ -0,0 +1,142 @@ +From 77f4e582d0f381391594e6f8a7b6767d572d96f7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 18:13:22 +0200 +Subject: [PATCH] core: when propagating restart requests due to deps, + downgrade restart to try-restart + +Previously, if a service A depended on a service B via Requires=, and A +was not running and B restarted this would trigger a start of A as well, +since the restart was propagated as restart independently of the state +of A. + +This patch ensures that a restart of B would be propagated as a +try-restart to A, thus not changing its state if it isn't up. + +http://lists.freedesktop.org/archives/systemd-devel/2015-May/032061.html +(cherry picked from commit c6497ccb7153af9a1252c48918e380b5134314de) + +Resolves: #1436021 +--- + src/core/job.c | 28 ++++++++++++++-------------- + src/core/job.h | 2 +- + src/core/manager.c | 2 +- + src/core/transaction.c | 11 ++++++++--- + 4 files changed, 24 insertions(+), 19 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 703286496..1617e24c0 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -392,38 +392,38 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) { + } + } + +-void job_type_collapse(JobType *t, Unit *u) { ++JobType job_type_collapse(JobType t, Unit *u) { + UnitActiveState s; + +- switch (*t) { ++ switch (t) { + + case JOB_TRY_RESTART: + s = unit_active_state(u); + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) +- *t = JOB_NOP; +- else +- *t = JOB_RESTART; +- break; ++ return JOB_NOP; ++ ++ return JOB_RESTART; + + case JOB_RELOAD_OR_START: + s = unit_active_state(u); + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) +- *t = JOB_START; +- else +- *t = JOB_RELOAD; +- break; ++ return JOB_START; ++ ++ return JOB_RELOAD; + + default: +- ; ++ return t; + } + } + + int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) { +- JobType t = job_type_lookup_merge(*a, b); ++ JobType t; ++ ++ t = job_type_lookup_merge(*a, b); + if (t < 0) + return -EEXIST; +- *a = t; +- job_type_collapse(a, u); ++ ++ *a = job_type_collapse(t, u); + return 0; + } + +diff --git a/src/core/job.h b/src/core/job.h +index e4191ee77..ce81607de 100644 +--- a/src/core/job.h ++++ b/src/core/job.h +@@ -210,7 +210,7 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_; + + /* Collapses a state-dependent job type into a simpler type by observing + * the state of the unit which it is going to be applied to. */ +-void job_type_collapse(JobType *t, Unit *u); ++JobType job_type_collapse(JobType t, Unit *u); + + int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u); + +diff --git a/src/core/manager.c b/src/core/manager.c +index 8bd80e687..287cf6a74 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1303,7 +1303,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove + "Trying to enqueue job %s/%s/%s", unit->id, + job_type_to_string(type), job_mode_to_string(mode)); + +- job_type_collapse(&type, unit); ++ type = job_type_collapse(type, unit); + + tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY); + if (!tr) +diff --git a/src/core/transaction.c b/src/core/transaction.c +index 428b7671b..34df15718 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -855,8 +855,7 @@ int transaction_add_job_and_dependencies( + /* by ? job_type_to_string(by->type) : "NA"); */ + + if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED)) +- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, +- "Unit %s is not loaded properly.", unit->id); ++ return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); + + if (type != JOB_STOP) { + r = bus_unit_check_load_state(unit, e); +@@ -1014,12 +1013,18 @@ int transaction_add_job_and_dependencies( + UNIT_CONSISTS_OF, + }; + ++ JobType ptype; + unsigned j; + ++ /* We propagate STOP as STOP, but RESTART only ++ * as TRY_RESTART, in order not to start ++ * dependencies that are not around. */ ++ ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type; ++ + for (j = 0; j < ELEMENTSOF(propagate_deps); j++) + SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) { + +- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); ++ r = transaction_add_job_and_dependencies(tr, job_type_collapse(ptype, dep), dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; diff --git a/SOURCES/0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch b/SOURCES/0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch new file mode 100644 index 00000000..4c49410d --- /dev/null +++ b/SOURCES/0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch @@ -0,0 +1,31 @@ +From b5ed9900d9a02abd78bfb151932748725b7c0bdb Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 May 2015 20:39:23 +0200 +Subject: [PATCH] core: properly handle jobs that are suppressed to JOB_NOPs + when propagating restarts + +Cherry-picked from: 48894cd0 +Resolves: #1436021 +--- + src/core/transaction.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index 34df15718..66bbb6066 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -1023,8 +1023,13 @@ int transaction_add_job_and_dependencies( + + for (j = 0; j < ELEMENTSOF(propagate_deps); j++) + SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) { ++ JobType nt; + +- r = transaction_add_job_and_dependencies(tr, job_type_collapse(ptype, dep), dep, ret, true, override, false, false, ignore_order, e); ++ nt = job_type_collapse(ptype, dep); ++ if (nt == JOB_NOP) ++ continue; ++ ++ r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; diff --git a/SOURCES/0482-tests-set-tasks_max-to-infinity.patch b/SOURCES/0482-tests-set-tasks_max-to-infinity.patch new file mode 100644 index 00000000..3d356472 --- /dev/null +++ b/SOURCES/0482-tests-set-tasks_max-to-infinity.patch @@ -0,0 +1,52 @@ +From a1c4eecf9a334e5841744cabdc18bdfdc108a636 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 21 Apr 2017 15:44:25 +0200 +Subject: [PATCH] tests: set tasks_max to infinity + +rhel-only +(upstream does the same but the code there is quite different) + +Related: #1337244 +--- + src/test/test-cgroup-mask.c | 11 +++++++++++ + src/test/test-execute.c | 5 +++++ + 2 files changed, 16 insertions(+) + +diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c +index 9e9de23e0..471adb25b 100644 +--- a/src/test/test-cgroup-mask.c ++++ b/src/test/test-cgroup-mask.c +@@ -45,6 +45,17 @@ static int test_cgroup_mask(void) { + puts("manager_new: Permission denied. Skipping test."); + return EXIT_TEST_SKIP; + } ++ assert_se(r >= 0); ++ ++ /* Turn off all kinds of default accouning, so that we can ++ * verify the masks resulting of our configuration and nothing ++ * else. */ ++ m->default_cpu_accounting = ++ m->default_memory_accounting = ++ m->default_blockio_accounting = ++ m->default_tasks_accounting = false; ++ m->default_tasks_max = (uint64_t) -1; ++ + assert_se(r >= 0); + assert_se(manager_startup(m, serial, fdset) >= 0); + +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 8e70702cb..627097fcf 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -270,6 +270,11 @@ int main(int argc, char *argv[]) { + } + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); ++ m->default_cpu_accounting = ++ m->default_memory_accounting = ++ m->default_blockio_accounting = ++ m->default_tasks_accounting = false; ++ m->default_tasks_max = (uint64_t) -1; + + for (test = tests; test && *test; test++) + (*test)(m); diff --git a/SOURCES/0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch b/SOURCES/0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch new file mode 100644 index 00000000..85acc3da --- /dev/null +++ b/SOURCES/0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch @@ -0,0 +1,49 @@ +From 9576fa3ecf91fd4703e2180ac080fd975292730f Mon Sep 17 00:00:00 2001 +From: hese10 +Date: Wed, 12 Oct 2016 19:40:28 +0300 +Subject: [PATCH] Avoid forever loop for journalctl --list-boots command + (#4278) + +When date is changed in system to future and normal user logs to new +journal file, and then date is changed back to present time, the +"journalctl --list-boot" command goes to forever loop. This commit tries +to fix this problem by checking first the boot id list if the found boot +id was already in that list. If it is found, then stopping the boot id +find loop. + +(cherry picked from commit ec02a6c90a5d8b234db534ce3f8f1901f8532057) + +Conflicts: + src/journal/journalctl.c +Related: #1294516 +--- + src/journal/journalctl.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 723854a2e..c771cff8b 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1039,7 +1039,7 @@ static int get_boots( + + bool skip_once; + int r, count = 0; +- BootId *head = NULL, *tail = NULL; ++ BootId *head = NULL, *tail = NULL, *id; + const bool advance_older = query_ref_boot && ref_boot_offset <= 0; + sd_id128_t previous_boot_id; + +@@ -1121,6 +1121,13 @@ static int get_boots( + break; + } + } else { ++ LIST_FOREACH(boot_list, id, head) { ++ if (sd_id128_equal(id->id, current->id)) { ++ /* boot id already stored, something wrong with the journal files */ ++ /* exiting as otherwise this problem would cause forever loop */ ++ goto finish; ++ } ++ } + LIST_INSERT_AFTER(boot_list, head, tail, current); + tail = current; + current = NULL; diff --git a/SOURCES/0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch b/SOURCES/0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch new file mode 100644 index 00000000..a53f4b36 --- /dev/null +++ b/SOURCES/0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch @@ -0,0 +1,40 @@ +From ca55fb67bc81313edf0aa6523b6f9ffce50ecdda Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 24 Apr 2017 18:33:12 +0200 +Subject: [PATCH] sd-journal: return SD_JOURNAL_INVALIDATE only if journal + files were actually deleted/moved (#5580) + +When caller invokes sd_journal_open() we usually open at least one +directory with journal files. add_root_directory() function increments +current_invalidate_counter. After sd_journal_open() returns +current_invalidate_counter != last_invalidate_counter. + +After caller waits for journal events (e.g. waits for new messages in +journal) then it usually calls sd_journal_process(). However, on first +call to sd_journal_process(), function determine_change() returns +SD_JOURNAL_INVALIDATE even though no journal files were +deleted/moved. This is because current_invalidate_counter != +last_invalidate_counter. + +After the fix we make sure counters has the same value before we begin +processing inotify events. + +(cherry picked from commit f934644424daa6c86fd2284fe8f33ea233ece874) + +Resolves: #1446140 +--- + src/journal/sd-journal.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 20456c3a1..72f312b67 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -2190,6 +2190,7 @@ _public_ int sd_journal_process(sd_journal *j) { + assert_return(!journal_pid_changed(j), -ECHILD); + + j->last_process_usec = now(CLOCK_MONOTONIC); ++ j->last_invalidate_counter = j->current_invalidate_counter; + + for (;;) { + union inotify_event_buffer buffer; diff --git a/SOURCES/0485-load-fragment-don-t-print-error-about-incorrect-synt.patch b/SOURCES/0485-load-fragment-don-t-print-error-about-incorrect-synt.patch new file mode 100644 index 00000000..a4b0a158 --- /dev/null +++ b/SOURCES/0485-load-fragment-don-t-print-error-about-incorrect-synt.patch @@ -0,0 +1,29 @@ +From c6774e13acf7b3d8783bc5ab31b2ea72b2fc9aaf Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 25 Apr 2017 14:53:47 +0200 +Subject: [PATCH] load-fragment: don't print error about incorrect syntax when + IPv6 is disabled + +(cherry-picked from commit f847b8b7df1de5686f8cbe5a4944a85dfb303595) + +Resolves: #1377055 +--- + src/core/load-fragment.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 411475024..58e44b89b 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -367,8 +367,9 @@ int config_parse_socket_listen(const char *unit, + + r = socket_address_parse(&p->address, k ? k : rvalue); + if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, -r, +- "Failed to parse address value, ignoring: %s", rvalue); ++ if (r != -EAFNOSUPPORT) ++ log_syntax(unit, LOG_ERR, filename, line, -r, ++ "Failed to parse address value, ignoring: %s", rvalue); + return 0; + } + diff --git a/SOURCES/0486-core-manager-add-some-missing-dbus-properties.patch b/SOURCES/0486-core-manager-add-some-missing-dbus-properties.patch new file mode 100644 index 00000000..2f323367 --- /dev/null +++ b/SOURCES/0486-core-manager-add-some-missing-dbus-properties.patch @@ -0,0 +1,36 @@ +From 285085cc7df8dd01fd372ce484ac9b3fb2d23de3 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Thu, 8 Oct 2015 07:35:36 +0300 +Subject: [PATCH] core: manager: add some missing dbus properties + +(cherry picked from commit 670a3efe31e729f9396fbf615aede47f10b4462e) + +Conflicts: + src/core/dbus-manager.c + +Resolves: #1427927 +--- + src/core/dbus-manager.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index c92f8c6bf..9d4f63377 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2039,6 +2039,16 @@ const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0), + SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0), + SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0), ++ SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST), + + SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/SOURCES/0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch b/SOURCES/0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch new file mode 100644 index 00000000..135a0d75 --- /dev/null +++ b/SOURCES/0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch @@ -0,0 +1,100 @@ +From 86669b5615683a5292ca048c362a000d471329d9 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Mon, 12 Oct 2015 06:39:00 +0000 +Subject: [PATCH] core: manager: expose DefaultLimit* as properties on dbus + +(cherry picked from commit 97eb42315785821dae3349978a1adf7d49aa5fc1) + +Conflicts: + src/core/dbus-manager.c + +Resolves: #1427927 +--- + src/core/dbus-manager.c | 16 ++++++++++++++++ + src/libsystemd/sd-bus/bus-util.c | 39 +++++++++++++++++++++++++++++++++++++++ + src/libsystemd/sd-bus/bus-util.h | 1 + + 3 files changed, 56 insertions(+) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 9d4f63377..d34ed042f 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2049,6 +2049,22 @@ const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST), + + SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index f46fa2bbf..263457427 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1937,3 +1937,42 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un + + return 0; + } ++ ++int bus_property_get_rlimit( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ++ struct rlimit *rl; ++ uint64_t u; ++ rlim_t x; ++ ++ assert(bus); ++ assert(reply); ++ assert(userdata); ++ ++ rl = *(struct rlimit**) userdata; ++ if (rl) ++ x = rl->rlim_max; ++ else { ++ struct rlimit buf = {}; ++ int z; ++ ++ z = rlimit_from_string(startswith(property, "Default") ? property + 7 : property); ++ assert(z >= 0); ++ ++ getrlimit(z, &buf); ++ x = buf.rlim_max; ++ } ++ ++ /* rlim_t might have different sizes, let's map ++ * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on ++ * all archs */ ++ u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x; ++ ++ return sd_bus_message_append(reply, "t", u); ++} +diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h +index 8c8846c6e..d5f4e9750 100644 +--- a/src/libsystemd/sd-bus/bus-util.h ++++ b/src/libsystemd/sd-bus/bus-util.h +@@ -214,3 +214,4 @@ int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet); + DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free); + + int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes); ++int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); diff --git a/SOURCES/0488-fstab-generator-remove-bogus-condition.patch b/SOURCES/0488-fstab-generator-remove-bogus-condition.patch new file mode 100644 index 00000000..a62491f6 --- /dev/null +++ b/SOURCES/0488-fstab-generator-remove-bogus-condition.patch @@ -0,0 +1,30 @@ +From 38815fb30199a76684d4153a0a2dcd6abd3a2dda Mon Sep 17 00:00:00 2001 +From: nmartensen +Date: Fri, 15 Jan 2016 07:55:25 +0100 +Subject: [PATCH] fstab-generator: remove bogus condition + +The sysroot mount is already taken care of by the add_sysroot_mount function. With this condition left in, we can get something like this: + +initrd-root-fs.target.requires +`-- usr.mount -> /run/systemd/generator/usr.mount + +in the main system (i.e., not in the initramfs). In the initramfs, the previous condition already kicks in. +Cherry-picked from: ce3f6d82b003f365f718f24e48f55b8a0372b924 +Resolves: #1446171 +--- + src/fstab-generator/fstab-generator.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 32aca2244..23b5457e4 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -476,8 +476,6 @@ static int parse_fstab(bool initrd) { + "x-systemd.automount\0"); + if (initrd) + post = SPECIAL_INITRD_FS_TARGET; +- else if (mount_in_initrd(me)) +- post = SPECIAL_INITRD_ROOT_FS_TARGET; + else if (mount_is_network(me)) + post = SPECIAL_REMOTE_FS_TARGET; + else diff --git a/SOURCES/0489-readahead-collect-don-t-print-warning-message-when-h.patch b/SOURCES/0489-readahead-collect-don-t-print-warning-message-when-h.patch new file mode 100644 index 00000000..92d72b9d --- /dev/null +++ b/SOURCES/0489-readahead-collect-don-t-print-warning-message-when-h.patch @@ -0,0 +1,29 @@ +From 530c665c059d3117c21b0dd6c1046accbf07208c Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 4 May 2017 16:53:30 +0200 +Subject: [PATCH] readahead-collect: don't print warning message when handling + symlink + +Since we call open() with O_NOFOLLOW we can't really open symlinks (we +would need to add O_PATH and we don't want that). Let's shortcut things +and return immediately, but don't treat this as an error. + +Resolves: #1387095 +--- + src/readahead/readahead-collect.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c +index 822a803a4..90f7f70bc 100644 +--- a/src/readahead/readahead-collect.c ++++ b/src/readahead/readahead-collect.c +@@ -106,6 +106,9 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { + if (errno == EPERM || errno == EACCES) + return 0; + ++ if (errno == ELOOP) ++ return 0; ++ + log_warning("open(%s) failed: %m", fn); + r = -errno; + goto finish; diff --git a/SOURCES/0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch b/SOURCES/0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch new file mode 100644 index 00000000..101ea0b0 --- /dev/null +++ b/SOURCES/0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch @@ -0,0 +1,38 @@ +From 2a1f91ffc371f2bc3767a806ff387517ff9b9fc8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 9 Jul 2015 18:43:55 -0300 +Subject: [PATCH] tmpfiles: don't recursively descend into journal directories + in /var + +Do so only in /run. We shouldn't alter ACLs for existing files in /var, +but only for new files. If the admin made changes to the ACLs they +shouls stay in place. + +We should still do recursive ACL changes for files in /run, since those +are not persistent, and will hence lack ACLs on every boot. + +Also, /var/log/journal might be quit large, /run/log/journal is usually +not, hence we should avoid the recursive descending on /var, but not on +/run. + +Fixes #534 + +(cherry picked from commit 8b258a645ae63dff3ab8dde6520d2e770e2a40f1) +Related: #1411199 +--- + tmpfiles.d/systemd.conf.m4 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4 +index b447b01f5..d9d51af92 100644 +--- a/tmpfiles.d/systemd.conf.m4 ++++ b/tmpfiles.d/systemd.conf.m4 +@@ -35,7 +35,7 @@ z /var/log/journal 2755 root systemd-journal - - + z /var/log/journal/%m 2755 root systemd-journal - - + m4_ifdef(`HAVE_ACL',`` + a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x +-A+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x ++a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x + '')m4_dnl + + d /var/lib/systemd 0755 root root - diff --git a/SOURCES/0491-tmpfiles-also-set-acls-on-var-log-journal.patch b/SOURCES/0491-tmpfiles-also-set-acls-on-var-log-journal.patch new file mode 100644 index 00000000..88487996 --- /dev/null +++ b/SOURCES/0491-tmpfiles-also-set-acls-on-var-log-journal.patch @@ -0,0 +1,29 @@ +From 2b089fee5954986c932845887ed2cfd889bd4410 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 29 Nov 2015 18:37:01 -0500 +Subject: [PATCH] tmpfiles: also set acls on /var/log/journal + +This way, directories created later for containers or for +journald-remote, will be readable by adm & wheel groups by default, +similarly to /var/log/journal/%m itself. + +https://github.com/systemd/systemd/issues/1971 +(cherry picked from commit 57d5b3130cd34b9a844f4258f55c1134b27bc5ad) +Related: #1411199 +--- + tmpfiles.d/systemd.conf.m4 | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4 +index d9d51af92..fcd6ec026 100644 +--- a/tmpfiles.d/systemd.conf.m4 ++++ b/tmpfiles.d/systemd.conf.m4 +@@ -34,6 +34,8 @@ A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x + z /var/log/journal 2755 root systemd-journal - - + z /var/log/journal/%m 2755 root systemd-journal - - + m4_ifdef(`HAVE_ACL',`` ++a+ /var/log/journal - - - - d:group:adm:r-x,d:group:wheel:r-x ++a+ /var/log/journal - - - - group:adm:r-x,group:wheel:r-x + a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x + a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x + '')m4_dnl diff --git a/SOURCES/0492-tmpfiles-set-acls-on-system.journal-explicitly.patch b/SOURCES/0492-tmpfiles-set-acls-on-system.journal-explicitly.patch new file mode 100644 index 00000000..24d608e0 --- /dev/null +++ b/SOURCES/0492-tmpfiles-set-acls-on-system.journal-explicitly.patch @@ -0,0 +1,30 @@ +From d38e703a133487218c91f1e76072fc6b35c0978c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 29 Nov 2015 18:48:40 -0500 +Subject: [PATCH] tmpfiles: set acls on system.journal explicitly + +https://github.com/systemd/systemd/issues/1397 +(cherry picked from commit afae249efa4774c6676738ac5de6aeb4daf4889f) +Resolves: #1411199 +--- + tmpfiles.d/systemd.conf.m4 | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4 +index fcd6ec026..0575408db 100644 +--- a/tmpfiles.d/systemd.conf.m4 ++++ b/tmpfiles.d/systemd.conf.m4 +@@ -33,11 +33,13 @@ A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x + + z /var/log/journal 2755 root systemd-journal - - + z /var/log/journal/%m 2755 root systemd-journal - - ++z /var/log/journal/%m/system.journal 0640 root systemd-journal - - + m4_ifdef(`HAVE_ACL',`` + a+ /var/log/journal - - - - d:group:adm:r-x,d:group:wheel:r-x + a+ /var/log/journal - - - - group:adm:r-x,group:wheel:r-x + a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x + a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x ++a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r-- + '')m4_dnl + + d /var/lib/systemd 0755 root root - diff --git a/SOURCES/0493-sysctl-configure-kernel-parameters-in-the-order-they.patch b/SOURCES/0493-sysctl-configure-kernel-parameters-in-the-order-they.patch new file mode 100644 index 00000000..990ea6f3 --- /dev/null +++ b/SOURCES/0493-sysctl-configure-kernel-parameters-in-the-order-they.patch @@ -0,0 +1,126 @@ +From 0e39139e505a8310ae8530fb2463a9e8f2170d2f Mon Sep 17 00:00:00 2001 +From: HATAYAMA Daisuke +Date: Sat, 24 Sep 2016 21:56:07 +0900 +Subject: [PATCH] sysctl: configure kernel parameters in the order they occur + in each sysctl configuration files (#4205) + +Currently, systemd-sysctl command configures kernel parameters in each sysctl +configuration files in random order due to characteristics of iterator of +Hashmap. + +However, kernel parameters need to be configured in the order they occur in +each sysctl configuration files. + +- For example, consider fs.suid_coredump and kernel.core_pattern. If + fs.suid_coredump=2 is configured before kernel.core_pattern= whose default + value is "core", then kernel outputs the following message: + + Unsafe core_pattern used with suid_dumpable=2. Pipe handler or fully qualified core dump path required. + + Note that the security issue mentioned in this message has already been fixed + on recent kernels, so this is just a warning message on such kernels. But + it's still confusing to users that this message is output on some boot and + not output on another boot. + +- I don't know but there could be other kernel parameters that are significant + in the order they are configured. + +- The legacy sysctl command configures kernel parameters in the order they + occur in each sysctl configuration files. Although I didn't find any official + specification explaining this behavior of sysctl command, I don't think there + is any meaningful reason to change this behavior, in particular, to the + random one. + +This commit does the change by simply using OrderedHashmap instead of +Hashmap. + +(cherry picked from commit 886cf982d3018f7451f0548dadbc05bd2d583bb6) + +Resolves: #1382244 +--- + src/sysctl/sysctl.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c +index 4fb293b9b..bb2bea7cd 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -90,14 +90,14 @@ static int apply_sysctl(const char *property, const char *value) { + return r; + } + +-static int apply_all(Hashmap *sysctl_options) { +- int r = 0; ++static int apply_all(OrderedHashmap *sysctl_options) { ++ int r; + char *property, *value; + Iterator i; + + assert(sysctl_options); + +- HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) { ++ ORDERED_HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) { + int k; + + k = apply_sysctl(property, value); +@@ -107,7 +107,7 @@ static int apply_all(Hashmap *sysctl_options) { + return r; + } + +-static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) { ++static int parse_file(OrderedHashmap *sysctl_options, const char *path, bool ignore_enoent) { + _cleanup_fclose_ FILE *f = NULL; + int r; + +@@ -171,13 +171,13 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno + } + + found: +- existing = hashmap_get2(sysctl_options, p, &v); ++ existing = ordered_hashmap_get2(sysctl_options, p, &v); + if (existing) { + if (streq(value, existing)) + continue; + + log_debug("Overwriting earlier assignment of %s in file '%s'.", p, path); +- free(hashmap_remove(sysctl_options, p)); ++ free(ordered_hashmap_remove(sysctl_options, p)); + free(v); + } + +@@ -191,7 +191,7 @@ found: + return log_oom(); + } + +- k = hashmap_put(sysctl_options, property, new_value); ++ k = ordered_hashmap_put(sysctl_options, property, new_value); + if (k < 0) { + log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", property); + free(property); +@@ -277,7 +277,7 @@ static int parse_argv(int argc, char *argv[]) { + + int main(int argc, char *argv[]) { + int r = 0, k; +- Hashmap *sysctl_options; ++ OrderedHashmap *sysctl_options; + + r = parse_argv(argc, argv); + if (r <= 0) +@@ -289,7 +289,7 @@ int main(int argc, char *argv[]) { + + umask(0022); + +- sysctl_options = hashmap_new(&string_hash_ops); ++ sysctl_options = ordered_hashmap_new(&string_hash_ops); + if (!sysctl_options) { + r = log_oom(); + goto finish; +@@ -331,7 +331,7 @@ int main(int argc, char *argv[]) { + r = k; + + finish: +- hashmap_free_free_free(sysctl_options); ++ ordered_hashmap_free_free_free(sysctl_options); + strv_free(arg_prefixes); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/SOURCES/0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch b/SOURCES/0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch new file mode 100644 index 00000000..fabc78ff --- /dev/null +++ b/SOURCES/0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch @@ -0,0 +1,31 @@ +From 3126e1ac82a14399e4a759b68ab85e10ba8ba3b3 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 19 Apr 2017 08:52:40 +0200 +Subject: [PATCH] units: drop explicit NotifyAccess setting from journald's + unit file (#5749) + +systemd-journald service consists of only single process and that is the +MainPID. Make unit file shorter and drop NotifyAccess=all since it is +not useful in such case. + +https://lists.freedesktop.org/archives/systemd-devel/2017-April/038667.html + +(cherry picked from commit 6f0e6bd253f449bedec78ec8a468929d3c5d8faf) + +Resolves: #1444356 +--- + units/systemd-journald.service.in | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index 8575912bb..c85c34932 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -19,7 +19,6 @@ Sockets=systemd-journald.socket + ExecStart=@rootlibexecdir@/systemd-journald + Restart=always + RestartSec=0 +-NotifyAccess=all + StandardOutput=null + CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE + WatchdogSec=3min diff --git a/SOURCES/0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch b/SOURCES/0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch new file mode 100644 index 00000000..1873610a --- /dev/null +++ b/SOURCES/0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch @@ -0,0 +1,32 @@ +From 6f755a0934a1806a187076f9757064d3e973d1d2 Mon Sep 17 00:00:00 2001 +From: Benjamin Robin +Date: Sat, 19 Sep 2015 21:57:51 +0200 +Subject: [PATCH] systemd-notify: Always pass a valid pid to sd_pid_notify + +If the option --pid was used, take the pid from this option, unless take +the parend pid. Using 0 as pid (ucred of systemd-notify) will result 99% of the +time in a failure with this error: "Cannot find unit for notify message of PID" + +Shouldn't we use always the ppid, since the MAINPID is something else ? + +Signed-off-by: Benjamin Robin + +Cherry-picked from: 9de009a9 +Resolves: #1381743 +--- + src/notify/notify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/notify/notify.c b/src/notify/notify.c +index c89a6cc06..0d382992a 100644 +--- a/src/notify/notify.c ++++ b/src/notify/notify.c +@@ -209,7 +209,7 @@ int main(int argc, char* argv[]) { + goto finish; + } + +- r = sd_pid_notify(arg_pid, false, n); ++ r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n); + if (r < 0) { + log_error_errno(r, "Failed to notify init system: %m"); + goto finish; diff --git a/SOURCES/0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch b/SOURCES/0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch new file mode 100644 index 00000000..e9c1a13c --- /dev/null +++ b/SOURCES/0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch @@ -0,0 +1,30 @@ +From 5a282fc000a52fe98a31ac69832678b1d1d5778d Mon Sep 17 00:00:00 2001 +From: Maciej Wereski +Date: Tue, 8 Sep 2015 15:36:30 +0200 +Subject: [PATCH] sd_pid_notify_with_fds: fix computing msg_controllen + +CMSG_SPACE(0) may return value other than 0. This caused sendmsg to fail +with EINVAL, when have_pid or n_fds was 0. + +Cherry-picked from: a5bd3c32abb00ad945282568fd1a97c180b68047 +Resolves: #1381743 +--- + src/libsystemd/sd-daemon/sd-daemon.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c +index 1474321c9..2c4dd9d22 100644 +--- a/src/libsystemd/sd-daemon/sd-daemon.c ++++ b/src/libsystemd/sd-daemon/sd-daemon.c +@@ -397,8 +397,9 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char + have_pid = pid != 0 && pid != getpid(); + + if (n_fds > 0 || have_pid) { +- msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) + +- CMSG_SPACE(sizeof(struct ucred) * have_pid); ++ /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */ ++ msghdr.msg_controllen = (n_fds ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + ++ CMSG_SPACE(sizeof(struct ucred)) * have_pid; + msghdr.msg_control = alloca(msghdr.msg_controllen); + + cmsg = CMSG_FIRSTHDR(&msghdr); diff --git a/SOURCES/0497-rules-move-cpu-hotplug-rule-to-separate-file.patch b/SOURCES/0497-rules-move-cpu-hotplug-rule-to-separate-file.patch new file mode 100644 index 00000000..f192f24e --- /dev/null +++ b/SOURCES/0497-rules-move-cpu-hotplug-rule-to-separate-file.patch @@ -0,0 +1,58 @@ +From 360d7eb0f8233d16557ef34a9e58055a67ea9b70 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 12 Jun 2017 13:43:48 +0200 +Subject: [PATCH] rules: move cpu hotplug rule to separate file + +In kdump initrd we don't want to automatically bring online all +available CPUs. Hence, kdump maintainers can easily mask the rule by +placing symlink to /dev/null with the same name in /etc/udev/rules.d + +RHEL-only + +Related: #1266322 + +[msekleta: note that this is just part of the fix for #1266322, in +order to fix the bug it is necessary to actually mask the newly added +rule when generating kdump initrd] +--- + Makefile.am | 1 + + rules/40-redhat-cpu-hotplug.rules | 4 ++++ + rules/40-redhat.rules | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + create mode 100644 rules/40-redhat-cpu-hotplug.rules + +diff --git a/Makefile.am b/Makefile.am +index e9ceac98a..94fee02c5 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3511,6 +3511,7 @@ dist_udevrules_DATA += \ + rules/80-net-setup-link.rules \ + rules/95-udev-late.rules \ + rules/40-redhat.rules \ ++ rules/40-redhat-cpu-hotplug.rules \ + rules/73-idrac.rules \ + rules/80-net-name-slot.rules + +diff --git a/rules/40-redhat-cpu-hotplug.rules b/rules/40-redhat-cpu-hotplug.rules +new file mode 100644 +index 000000000..bc5ddc841 +--- /dev/null ++++ b/rules/40-redhat-cpu-hotplug.rules +@@ -0,0 +1,4 @@ ++# do not edit this file, it will be overwritten on update ++ ++# CPU hotadd request ++SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 34a1df9c4..d04c7fc9a 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -1,8 +1,5 @@ + # do not edit this file, it will be overwritten on update + +-# CPU hotadd request +-SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" +- + # Memory hotadd request + SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online" + diff --git a/SOURCES/0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch b/SOURCES/0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch new file mode 100644 index 00000000..dd6ae569 --- /dev/null +++ b/SOURCES/0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch @@ -0,0 +1,49 @@ +From f8747430762d9daad14f71cdd7ee98daf833e161 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 27 Jun 2017 09:21:19 +0200 +Subject: [PATCH] Revert "rules: move cpu hotplug rule to separate file" + +This reverts commit 360d7eb0f8233d16557ef34a9e58055a67ea9b70. +Resolves: #1465108 +--- + Makefile.am | 1 - + rules/40-redhat-cpu-hotplug.rules | 4 ---- + rules/40-redhat.rules | 3 +++ + 3 files changed, 3 insertions(+), 5 deletions(-) + delete mode 100644 rules/40-redhat-cpu-hotplug.rules + +diff --git a/Makefile.am b/Makefile.am +index 94fee02c5..e9ceac98a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3511,7 +3511,6 @@ dist_udevrules_DATA += \ + rules/80-net-setup-link.rules \ + rules/95-udev-late.rules \ + rules/40-redhat.rules \ +- rules/40-redhat-cpu-hotplug.rules \ + rules/73-idrac.rules \ + rules/80-net-name-slot.rules + +diff --git a/rules/40-redhat-cpu-hotplug.rules b/rules/40-redhat-cpu-hotplug.rules +deleted file mode 100644 +index bc5ddc841..000000000 +--- a/rules/40-redhat-cpu-hotplug.rules ++++ /dev/null +@@ -1,4 +0,0 @@ +-# do not edit this file, it will be overwritten on update +- +-# CPU hotadd request +-SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index d04c7fc9a..34a1df9c4 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -1,5 +1,8 @@ + # do not edit this file, it will be overwritten on update + ++# CPU hotadd request ++SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" ++ + # Memory hotadd request + SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online" + 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 00000000..7dff683b --- /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: 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/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 00000000..9991b10b --- /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/0503-sysctl-fix-uninitialized-variable.patch b/SOURCES/0503-sysctl-fix-uninitialized-variable.patch new file mode 100644 index 00000000..821541cb --- /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/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 00000000..9c734458 --- /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 00000000..2ba63a37 --- /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/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 00000000..683a3cc0 --- /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-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 00000000..2574d5d9 --- /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 00000000..1f546b29 --- /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/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 00000000..23e502cc --- /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/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 00000000..360bd21a --- /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-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 00000000..be7b3bbe --- /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-units-introduce-getty-pre.target-6667.patch b/SOURCES/0512-units-introduce-getty-pre.target-6667.patch new file mode 100644 index 00000000..3d298ba7 --- /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-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 00000000..2f1eba66 --- /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 00000000..917239d5 --- /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/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 00000000..6164a39a --- /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/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 00000000..6094a08b --- /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/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 00000000..85b7a593 --- /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/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 00000000..d355027c --- /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 00000000..82925c70 --- /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 00000000..3b12cdba --- /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 00000000..e3e98989 --- /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 00000000..1c9c72d9 --- /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 00000000..50dee6c0 --- /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 00000000..bbd9364e --- /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 00000000..a4ba7877 --- /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 00000000..1b4ed932 --- /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 00000000..ce36900a --- /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 00000000..0aeb0b15 --- /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 00000000..c4e2bc0b --- /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 00000000..fddfd6b1 --- /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 00000000..bd82b938 --- /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 00000000..7fcdd5c1 --- /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 00000000..ba9d7a65 --- /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 00000000..0709d776 --- /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 00000000..3c3e8b8c --- /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 00000000..2b8fccc9 --- /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 00000000..ebae836c --- /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 00000000..de5b8071 --- /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 00000000..3edfc86b --- /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 00000000..95d622a8 --- /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 00000000..fa938bd6 --- /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 00000000..2f1e33b8 --- /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 00000000..addea4f5 --- /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 00000000..bc4ca5ea --- /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 00000000..0b18ab27 --- /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 00000000..7e4c5320 --- /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 00000000..971fe389 --- /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 00000000..3eebde93 --- /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 00000000..eb867e1a --- /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 00000000..e4e49645 --- /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 00000000..61153278 --- /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 00000000..6203c9ed --- /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 00000000..cf020a97 --- /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 00000000..129e378b --- /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 00000000..6750c024 --- /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 00000000..f8095245 --- /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 00000000..9736e981 --- /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 00000000..5bb71086 --- /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 00000000..8f6023fe --- /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 00000000..3fce2ef7 --- /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 00000000..afaf1684 --- /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 00000000..a8693a1f --- /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 00000000..6ef7b475 --- /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 00000000..c72084ce --- /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 00000000..5fb3090d --- /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 00000000..9cdfb0c6 --- /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 00000000..d6ee4d4a --- /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 00000000..59537ff8 --- /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 00000000..a238169c --- /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 00000000..08e3ac19 --- /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 00000000..252fc6b5 --- /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 00000000..cfd15f3b --- /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 00000000..c922fe2d --- /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 00000000..762bbc8d --- /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 00000000..8f6516ae --- /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 00000000..8c40d40d --- /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 00000000..0fa5760d --- /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 00000000..38d71ebc --- /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 00000000..a12c7aba --- /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 00000000..2798123a --- /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 00000000..5be44af4 --- /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 00000000..fa3a2072 --- /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 00000000..14853bf8 --- /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 00000000..1ee34f38 --- /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 00000000..726ccafc --- /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 00000000..b89c611b --- /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 00000000..35fdb0b5 --- /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 00000000..c6309e01 --- /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 00000000..8210792b --- /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 00000000..e2c0f6fb --- /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 00000000..1e8f0572 --- /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 00000000..fb8c7005 --- /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 00000000..9d9c0f2e --- /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 00000000..e80a7e67 --- /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 00000000..498bad38 --- /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 00000000..180ee6dc --- /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 00000000..3d5962d5 --- /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 00000000..77832cc4 --- /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 00000000..e53a3849 --- /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 00000000..288ad7b1 --- /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 00000000..d0b9e21b --- /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 00000000..cbcc4d58 --- /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 00000000..1e36686b --- /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 00000000..45078720 --- /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 00000000..bc131c84 --- /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 00000000..2630ceb9 --- /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 00000000..1283fd04 --- /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 00000000..67a3ed9e --- /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 00000000..3a6a0a88 --- /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 00000000..c3f7d246 --- /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 00000000..26c212af --- /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 00000000..026f18bb --- /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 00000000..94dca301 --- /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/60-alias-kmsg.rules b/SOURCES/60-alias-kmsg.rules new file mode 100644 index 00000000..9c7236a7 --- /dev/null +++ b/SOURCES/60-alias-kmsg.rules @@ -0,0 +1,10 @@ +SUBSYSTEM!="block", GOTO="log_end" +KERNEL=="loop*|ram*", GOTO="log_end" +ACTION=="remove", GOTO="log_end" +ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="log_end" +ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="log_end" + +IMPORT{cmdline}="udev.alias" +ENV{udev.alias}=="1", RUN+="/bin/sh -c 'echo udev-alias: $name \($links\) > /dev/kmsg'" + +LABEL="log_end" diff --git a/SOURCES/76-phys-port-name.conf b/SOURCES/76-phys-port-name.conf new file mode 100644 index 00000000..fe456d0a --- /dev/null +++ b/SOURCES/76-phys-port-name.conf @@ -0,0 +1,2 @@ +install_items+=" /usr/lib/udev/phys-port-name-gen " +install_items+=" /usr/lib/udev/rules.d/76-phys-port-name.rules " diff --git a/SOURCES/76-phys-port-name.rules b/SOURCES/76-phys-port-name.rules new file mode 100644 index 00000000..067f73af --- /dev/null +++ b/SOURCES/76-phys-port-name.rules @@ -0,0 +1,9 @@ +# do not edit this file, it will be overwritten on update +ACTION!="add", GOTO="phys_port_name_end" +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/SOURCES/99-default-disable.preset b/SOURCES/99-default-disable.preset new file mode 100644 index 00000000..1f29b505 --- /dev/null +++ b/SOURCES/99-default-disable.preset @@ -0,0 +1 @@ +disable * diff --git a/SOURCES/listen.conf b/SOURCES/listen.conf new file mode 100644 index 00000000..3d68da07 --- /dev/null +++ b/SOURCES/listen.conf @@ -0,0 +1 @@ +$SystemLogSocketName /run/systemd/journal/syslog diff --git a/SOURCES/org.freedesktop.hostname1.policy b/SOURCES/org.freedesktop.hostname1.policy new file mode 100644 index 00000000..00141562 --- /dev/null +++ b/SOURCES/org.freedesktop.hostname1.policy @@ -0,0 +1,100 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Set host name + Rechnername festlegen + Ορισμός ονόματος οικοδεσπότη + Définir le nom d'hôte + Gépnév beállítása + Configura il nome host + Ustawienie nazwy komputera + Definir nome de máquina + Настроить имя компьютера + Ange värdnamn + Встановити назву вузла + Authentication is required to set the local host name. + Legitimierung ist zum Festlegen des lokalen Rechnernamens notwendig + Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη. + Authentification requise pour définir le nom d'hôte local. + Hitelesítés szükséges a helyi gépnév beállításához. + Autenticazione richiesta per configurare il nome host locale. + Wymagane jest uwierzytelnienie, aby ustawić nazwę lokalnego komputera. + É necessária autenticação para definir nome de máquina local. + Чтобы настроить имя компьютера, необходимо пройти аутентификацию. + Autentisering krävs för att ange lokalt värdnamn. + Засвідчення потрібне, щоб встановити назву локального вузла. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Set static host name + Statischen Rechnernamen festlegen + Ορισμός στατικού ονόματος οικοδεσπότη + Définir le nom d'hôte statique + Statikus gépnév beállítása + Configura il nome host statico + Ustawienie statycznej nazwy komputera + Definir nome estático de máquina + Настроить статическое имя компьютера + Ange statiskt värdnamn + Встановити статичну назву вузла + Authentication is required to set the statically configured local host name, as well as the pretty host name. + Authentifizierung ist erforderlich, um den statisch geänderten, lokalen Rechnernamen, sowie den beschönigten Rechnernamen festzulegen. + Απαιτείται πιστοποίηση για να ορίσετε το στατικά ρυθμισμένο όνομα τοπικού οικοδεσπότη, καθώς και το pretty όνομα οικοδεσπότη. + Authentification requise pour définir le nom d'hôte local de manière statique, tout comme le nom d'hôte familier. + Hitelesítés szükséges a statikusan megadott helyi gépnév, valamint a szép gépnév beállításához. + Autenticazione richiesta per configurare staticamente il nome host locale e il nome host descrittivo. + Wymagane jest uwierzytelnienie, aby ustawić statycznie skonfigurowaną nazwę lokalnego komputera, a także jego ładną nazwę. + É necessária autenticação para definir o nome de máquina local configurado estaticamente, assim como o nome apresentável de máquina. + Чтобы настроить статическое имя компьютера, а также его «красивое» имя, необходимо пройти аутентификацию. + Autentisering krävs för att ange det statiskt konfigurerade lokala värdnamnet såväl som det stiliga värdnamnet. + Засвідчення потрібне, щоб вказати статично налаштовану назву локального вузла, так само й форматовану. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.hostname1.set-hostname org.freedesktop.hostname1.set-machine-info + + + + Set machine information + Maschinen-Information festlegen + Ορισμός πληροφοριών μηχανής + Définir les informations sur la machine + Gépinformációk beállítása + Configura le informazioni sulla macchina + Ustawienie informacji o komputerze + Definir informações da máquina + Настроить информацию о компьютере + Ange datorinformation + Встановити інформацію про машину + Authentication is required to set local machine information. + Legitimierung ist zum Festlegen der lokalen Maschinen-Information erforderlich. + Απαιτείται πιστοποίηση για να ορίσετε πληροφορίες τοπικής μηχανής. + Authentification requise pour définir les informations sur la machine locale. + Hitelesítés szükséges a helyi gép információinak beállításához. + Autenticazione richiesta per configurare le informazioni sulla macchina locale. + Wymagane jest uwierzytelnienie, aby ustawić informacje o lokalnym komputerze. + É necessária autenticação para definir informações de máquina local. + Чтобы настроить информацию о компьютере, необходимо пройти аутентификацию. + Autentisering krävs för att ange lokal datorinformation. + Засвідчення потрібно, щоб вказати локальну інформацію про машини. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.import1.policy b/SOURCES/org.freedesktop.import1.policy new file mode 100644 index 00000000..e05e4bb9 --- /dev/null +++ b/SOURCES/org.freedesktop.import1.policy @@ -0,0 +1,27 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Download a VM or container image + Abbild einer VM oder eines Containers herunterladen + Télécharger une image de machine virtuelle (VM) ou de conteneur + Pobranie obrazu maszyny wirtualnej lub kontenera + Загрузить образ виртуальной машины или контейнера + Authentication is required to download a VM or container image + Legitimierung ist zum Herunterladen eines VM- oder Containerabbilds erforderlich + Authentification requise pour télécharger une image de machine virtuelle (VM) ou de conteneur. + Wymagane jest uwierzytelnienie, aby pobrać obraz maszyny wirtualnej lub kontenera + Чтобы загрузить образ виртуальной машины или контейнера, необходимо пройти аутентификацию. + + auth_admin + auth_admin + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.locale1.policy b/SOURCES/org.freedesktop.locale1.policy new file mode 100644 index 00000000..5f9b5717 --- /dev/null +++ b/SOURCES/org.freedesktop.locale1.policy @@ -0,0 +1,70 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Set system locale + Die lokale Sprachumgebung festlegen + Ορισμός τοπικών ρυθμίσεων συστήματος + Définir la langue du système + Területi beállítás megadása + Configura le impostazioni regionali di sistema + Ustawienie lokalizacji systemu + Definir configurações regionais do sistema + Настроить системную локаль + Ange systemlokal + Вказати системну локаль + Authentication is required to set the system locale. + Legitimierung ist zum Festlegen der systemweiten Spracheinstellungen erforderlich. + Απαιτείται πιστοποίηση για να ορίσετε τις τοπικές ρυθμίσεις του συστήματος. + Authentification requise pour définir la langue du système. + Hitelesítés szükséges a rendszer területi beállításainak megadásához. + Autenticazione richiesta per configurare le impostazioni regionali di sistema. + Wymagane jest uwierzytelnienie, aby ustawić lokalizację systemu. + É necessária autenticação para definir as configurações regionais do sistema. + Чтобы настроить системную локаль, необходимо пройти аутентификацию. + Autentisering krävs för att ange systemlokal. + Засвідчення потрібно, щоб встановити системну локаль. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.locale1.set-keyboard + + + + Set system keyboard settings + Tastatureinstellungen des Systems festlegen + Ορισμός ρυθμίσεων πληκτρολογίου συστήματος + Définir les paramètres de clavier du système + Rendszer billentyűzetbeállítások megadása + Configura la tastiera di sistema + Ustawienie klawiatury systemu + Definir configurações de teclado do sistema + Настроить параметры клавиатуры + Ange systeminställningar för tangentbord + Вказати налаштування системної клавіатури + Authentication is required to set the system keyboard settings. + Legitimierung ist zum Festlegen der Tastatureinstellungen des Systems erforderlich. + Απαιτείται πιστοποίηση για να ορίσετε τις ρυθμίσεις πληκτρολογίου του συστήματος. + Authentification requise pour définir les paramètres de clavier du système. + Hitelesítés szükséges a rendszer billentyűzetbeállításainak megadásához. + Autenticazione richiesta per configurare la tastiera di sistema. + Wymagane jest uwierzytelnienie, aby ustawić klawiaturę systemu. + É necessária autenticação para definir as configurações de teclado do sistema. + Чтобы настроить параметры клавиатуры, необходимо пройти аутентификацию. + Autentisering krävs för att ange systeminställningar för tangentbord. + Засвідчення потрібно, щоб вказати налаштування системної клавіатури. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.login1.policy b/SOURCES/org.freedesktop.login1.policy new file mode 100644 index 00000000..0a192737 --- /dev/null +++ b/SOURCES/org.freedesktop.login1.policy @@ -0,0 +1,743 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Allow applications to inhibit system shutdown + Anwendungen dürfen das Herunterfahren des Systems unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τον τερματισμό του συστήματος + Permet aux applications d'empêcher l'arrêt du système + Alkalmazások meggátolhatják a rendszer leállítását + Consenti alle applicazioni di inibire lo spegnimento del sistema + Zezwolenie programom na wstrzymywanie wyłączenia systemu + Permitir que aplicativos inibam o desligamento do sistema + Разрешить приложениям устанавливать блокировку на выключение системы + Tillåt program att hindra systemavstängning + Дозволити програмам перешкоджати вимкненню системи + Authentication is required for an application to inhibit system shutdown. + Legitimierung ist notwendig, um Anwendungen das Herunterfahren des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει τον τερματισμό του συστήματος. + Authentification requise pour permettre à une application d'empêcher l'arrêt du système. + Hitelesítés szükséges egy alkalmazás számára a rendszerleállítás meggátlásához. + Autenticazione richiesta per un'applicazione per inibire lo spegnimento del sistema. + Program wymaga uwierzytelnienia, aby wstrzymać wyłączenie systemu. + É necessária autenticação para que um aplicativo iniba o desligamento do sistema. + Чтобы разрешить приложениям устанавливать блокировку на выключение системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemavstängning. + Засвідчення потрібно, щоб дозволити програмам перешкоджати вимкненню системи. + + no + yes + yes + + org.freedesktop.login1.inhibit-delay-shutdown org.freedesktop.login1.inhibit-block-sleep org.freedesktop.login1.inhibit-delay-sleep org.freedesktop.login1.inhibit-block-idle + + + + Allow applications to delay system shutdown + Anwendungen dürfen das Herunterfahren des Systems verzögern + Να επιτρέπεται στις εφαρμογές να καθυστερούν τον τερματισμό του συστήματος + Permet aux applications de retarder l'arrêt du système + Alkalmazások késleltethetik a rendszer leállítását + Consenti alle applicazioni di ritardare lo spegnimento del sistema + Zezwolenie programom na opóźnienie wyłączenia systemu + Permitir que aplicativos atrasem o desligamento do sistema + Разрешить приложениям устанавливать задержку на выключение системы + Tillåt program att fördröja systemavstängning + Дозволити програмам затримувати вимкнення системи + Authentication is required for an application to delay system shutdown. + Legitimierung ist notwendig, um Anwendungen das Verzögern des Herunterfahren des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να καθυστερήσει τον τερματισμό του συστήματος. + Authentification requise pour permettre à une application de retarder l'arrêt du système. + Hitelesítés szükséges egy alkalmazás számára a rendszerleállítás késleltetéséhez. + Autenticazione richiesta per un'applicazione per ritardare lo spegnimento del sistema. + Program wymaga uwierzytelnienia, aby opóźnić wyłączenie systemu. + É necessária autenticação para que um aplicativo atrase o desligamento do sistema. + Чтобы разрешить приложениям устанавливать задержку на выключение системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att fördröja systemavstängning. + Засвідчення потрібно, щоб дозволити програмам затримувати вимкнення системи. + + yes + yes + yes + + org.freedesktop.login1.inhibit-delay-sleep + + + + Allow applications to inhibit system sleep + Anwendungen dürfen den Bereitschaftsmodus unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν την ύπνωση του συστήματος + Permet aux applications d'empêcher la mise en veille du système + Alkalmazások meggátolhatják a rendszer altatását + Consenti alle applicazioni di inibire il sistema in pausa + Zezwolenie programom na wstrzymanie uśpienia systemu + Permitir que aplicativos inibam a suspensão do sistema + Разрешить приложениям устанавливать блокировку на засыпание системы + Tillåt program att hindra system att försättas i viloläge + Дозволити програмам перешкоджати засинанню системи + Authentication is required for an application to inhibit system sleep. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden des Bereitschaftsmodus zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την ύπνωση του συστήματος. + Authentification requise pour permettre à une application d'empêcher la mise en veille du système. + Hitelesítés szükséges egy alkalmazás számára a rendszeraltatás meggátlásához. + Autenticazione richiesta per un'applicazione per inibire il sistema in pausa. + Program wymaga uwierzytelnienia, aby wstrzymać uśpienie systemu. + É necessária autenticação para que um aplicativo iniba a suspensão do sistema. + Чтобы разрешить приложениям устанавливать блокировку на засыпание системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra ett system att försättas i viloläge. + Засвідчення потрібно, щоб дозволити програмам перешкоджати засинанню системи. + + no + yes + yes + + org.freedesktop.login1.inhibit-delay-sleep org.freedesktop.login1.inhibit-block-idle + + + + Allow applications to delay system sleep + Anwendungen dürfen den Bereitschaftsmodus verzögern + Να επιτρέπεται στις εφαρμογές να καθυστερούν την ύπνωση του συστήματος + Permet aux applications de retarder la mise en veille du système + Alkalmazások késleltethetik a rendszer altatását + Consenti alle applicazioni di ritardare il sistema in pausa + Zezwolenie programom na opóźnienie uśpienia systemu + Permite que aplicativos atrasem a suspensão do sistema + Разрешить приложениям устанавливать задержку на засыпание системы + Tillåt program att fördröja att system försätts i viloläge + Дозволити програмами затримувати засинання системи + Authentication is required for an application to delay system sleep. + Legitimierung ist erforderlich, um Anwendungen das Verzögern des Bereitschaftsmodus zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να καθυστερήσει την ύπνωση του συστήματος. + Authentification requise pour permettre à une application de retarder la mise en veille du système. + Hitelesítés szükséges egy alkalmazás számára a rendszeraltatás késleltetéséhez. + Autenticazione richiesta per un'applicazione per ritardare il sistema in pausa. + Program wymaga uwierzytelnienia, aby opóźnić uśpienie systemu. + É necessária autenticação para que um aplicativo atrase a suspensão do sistema. + Чтобы разрешить приложениям устанавливать задержку на засыпание системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att fördröja ett system att försättas i viloläge. + Засвідчення потрібно, щоб дозволити програмам затримувати засинання системи. + + yes + yes + yes + + + + + Allow applications to inhibit automatic system suspend + Anwendungen dürfen den automatischen Bereitschaftsmodus unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν την αυτόματη αναστολή του συστήματος + Permet aux applications d'empêcher l'hibernation automatique du système + Alkalmazások meggátolhatják a rendszer automatikus felfüggesztését + Consenti alle applicazioni di inibire la sospesione automatica del sistema + Zezwolenie programom na wstrzymanie automatycznego uśpienia systemu + Permitir que aplicativos inibam a suspensão automática do sistema + Разрешить приложениям устанавливать блокировку на автоматический переход системы в ждущий режим + Tillåt program att hindra automatiskt systemvänteläge + Дозволити програмам перешкоджати автоматичному призупиненню системи + Authentication is required for an application to inhibit automatic system suspend. + Legitimierung ist notwendig, um Anwendungen das Unterbinden des automatischen Bereitschaftsmodus zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την αυτόματη αναστολή του συστήματος. + Authentification requise pour permettre à une application d'empêcher l'hibernation automatique du système. + Hitelesítés szükséges egy alkalmazás számára az automatikus rendszerfelfüggesztés meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la sospensione automatica del sistema. + Program wymaga uwierzytelnienia, aby wstrzymać automatyczne uśpienie systemu. + É necessária autenticação para que um aplicativo iniba a suspensão automática do sistema. + Чтобы разрешить приложениям устанавливать блокировку на автоматический переход системы в ждущий режим, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra automatiskt systemvänteläge. + Засвідчення потрібно, щоб дозволити програмам перешкоджати автоматичному призупиненню системи. + + yes + yes + yes + + + + + Allow applications to inhibit system handling of the power key + Anwendungen dürfen das Auswerten des Ein-/Ausschaltknopfs des Systems unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του πλήκτρου ενεργοποίησης του συστήματος + Permet aux applications d'empêcher la gestion du bouton d'alimentation du système + Alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema del tasto di accensione + Zezwolenie programom na wstrzymanie obsługi klawisza zasilania przez system + Permitir que aplicativos inibam o sistema de gerenciar o botão de energia + Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку выключения + Tillåt program att hindra systemhantering av strömknappen + Дозволити програмам перешкоджати обробленню системою клавіші живлення + Authentication is required for an application to inhibit system handling of the power key. + Legitmierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung der Ein-/Ausschaltknopfs des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του πλήκτρου ενεργοποίησης του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion du bouton d'alimentation du système. + Hitelesítés szükséges egy alkalmazás számára a bekapcsoló gomb rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la gestione di sistema del tasto di accensione. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę klawisza zasilania przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre a chave de ligar/desligar. + Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку выключения, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av strömknappen. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші живлення. + + no + yes + yes + + org.freedesktop.login1.inhibit-handle-suspend-key org.freedesktop.login1.inhibit-handle-hibernate-key org.freedesktop.login1.inhibit-handle-lid-switch + + + + Allow applications to inhibit system handling of the suspend key + Anwendungen dürfen das Auswerten des Bereitschaftsknopfs des Systems unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του πλήκτρου αναστολής του συστήματος. + Permet aux applications d'empêcher la gestion du bouton de mise en veille du système + Alkalmazások meggátolhatják a felfüggesztés gomb rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema del tasto di sospensione + Zezwolenie programom na wstrzymanie obsługi klawisza uśpienia przez system + Permitir que aplicativos inibam o sistema de gerenciar o botão de suspensão + Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в ждущий режим + Tillåt program att hindra systemhantering av väntelägesknappen + Дозволити програмам перешкоджати обробленню системою клавіші призупинення + Authentication is required for an application to inhibit system handling of the suspend key. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung des Bereitschaftsknopfes des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του πλήκτρου αναστολής του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion du bouton de mise en veille du système. + Hitelesítés szükséges egy alkalmazás számára a felfüggesztés gomb rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la gestione di sistema del tasto di sospensione. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę klawisza uśpienia przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre a chave de suspensão. + Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в ждущий режим, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av väntelägesknappen. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші призупинення. + + no + yes + yes + + org.freedesktop.login1.inhibit-handle-hibernate-key org.freedesktop.login1.inhibit-handle-lid-switch + + + + Allow applications to inhibit system handling of the hibernate key + Anwendungen dürfen das Auswerten des Knopfs für den Ruhezustand unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του πλήκτρου αδρανοποίησης του συστήματος + Permet aux applications d'empêcher la gestion du bouton d'hibernation du système + Alkalmazások meggátolhatják a hibernálás gomb rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema del tasto di ibernazione + Zezwolenie programom na wstrzymanie obsługi klawisza hibernacji przez system + Permitir que aplicativos inibam o sistema de gerenciar o botão de hibernação + Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в спящий режим + Tillåt program att hindra systemhantering av vilolägesknappen + Дозволити програмам перешкоджати обробленню системою клавіші присипання + Authentication is required for an application to inhibit system handling of the hibernate key. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung des Knopfs für den Ruhezustand zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του πλήκτρου αδρανοποίησης του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion du bouton d'hibernation du système. + Hitelesítés szükséges egy alkalmazás számára a hibernálás gomb rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la gestione di sistema del tasto di ibernazione. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę klawisza hibernacji przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre a chave de hibernar. + Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в спящий режим, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av vilolägesknappen. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші присипання. + + no + yes + yes + + + + + Allow applications to inhibit system handling of the lid switch + Anwendungen dürfen das Auswerten des Notebookdeckelschalters unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του διακόπτη καλύμματος του συστήματος + Permet aux applications d'empêcher la gestion par le système du rabat de l'écran + Alkalmazások meggátolhatják a fedélkapcsoló rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema alla apertura/chiusura del portatile + Zezwolenie programom na wstrzymanie obsługi przełącznika pokrywy przez system + Permitir que aplicativos inibam o sistema de gerenciar a abertura/fechamento da tampa do dispositivo portátil + Разрешить приложениям устанавливать блокировку на обработку закрытия крышки ноутбука + Tillåt program att hindra systemhantering av växel för datorhölje + Дозволити програмам перешкоджати обробленню системою клавіші перемикання кришки + Authentication is required for an application to inhibit system handling of the lid switch. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung des Notebookdeckelschalters des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του διακόπτη καλύμματος του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion par le système du rabat de l'écran. + Hitelesítés szükséges egy alkalmazás számára a fedélkapcsoló rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per consentire ad un'applicazione di inibire la gestione di sistema alla apertura/chiusura del portatile. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę przełącznika pokrywy przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre o interruptor da tela. + Чтобы разрешить приложениям устанавливать блокировку на обработку закрытия крышки ноутбука, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av brytaren för datorhöljet. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші перемикання кришки. + + no + yes + yes + + + + + Allow non-logged-in users to run programs + Nicht angemeldete Benutzer dürfen Programme ausführen + Να επιτρέπεται σε μη συνδεμένους χρήστες να εκτελούν προγράμματα + Permet aux utilisateurs non connectés d'exécuter des programmes + Programfuttatás engedélyezése be nem jelentkezett felhasználók számára + Consenti agli utenti non connessi di eseguire programmi + Zezwolenie niezalogowanym użytkownikom na uruchamianie programów + Permitir que programas sejam executados por usuários que não possuem sessão + Разрешить пользователям оставлять программы в фоновом режиме после завершения сеанса + Tillåt ej inloggade användare att köra program + Дозволити незареєстрованим користувачам запускати програми + Authentication is required to run programs as a non-logged-in user. + Legitimierung ist erforderlich, damit nicht angemeldete Benutzer Programme ausführen dürfen. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μη συνδεμένους χρήστες να εκτελούν προγράμματα. + Authentification requise pour permettre aux utilisateurs non connectés d'exécuter des programmes. + Hitelesítés szükséges a programfuttatáshoz be nem jelentkezett felhasználóként. + Autenticazione richiesta per consentire agli utenti non connessi di eseguire programmi. + Wymagane jest uwierzytelnienie, aby uruchamiać programy jako niezalogowany użytkownik. + É necessária autenticação para executar programas como usuário sem sessão aberta. + Чтобы разрешить пользователям оставлять программы в фоновом режиме после завершения сеанса, необходимо пройти аутентификацию. + Autentisering krävs för att köra program som en icke inloggad användare. + Засвідчення потрібно, щоб дозволити незареєстрованим користувачам запускати програми. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Allow attaching devices to seats + Das Anschließen von Geräten an Arbeitsstationen erlauben + Να επιτρέπεται η προσάρτηση συσκευών στους σταθμούς εργασίας + Permet d'associer des périphériques à des postes (seats) + Eszközök csatolásának engedélyezése munkaállomásokhoz + Consenti di collegare dispositivi alle postazioni + Zezwolenie na podłączanie urządzeń do stanowisk + Permitir conectar dispositivos em estações + Разрешить подключение устройств к рабочим местам + Tillåt att binda enheter till platser + Дозволити під'єднання пристроїв до місць + Authentication is required for attaching a device to a seat. + Legitimierung ist zum Anschließen eines Geräts an eine Arbeitsstation notwendig. + Απαιτείται πιστοποίηση για προσάρτηση μιας συσκευής σε έναν σταθμό εργασίας. + Authentification requise pour associer un périphérique à un poste (seat). + Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy munkaállomáshoz + Autenticazione richiesta per collegare un dispositivo ad una postazione. + Wymagane jest uwierzytelnienie, aby podłączyć urządzenie do stanowiska. + É necessária autenticação para conectar um dispositivo em uma estação. + Чтобы разрешить подключение устройств к рабочим местам, необходимо пройти аутентификацию. + Autentisering krävs för att binda en enhet till en plats. + Засвідчення потрібно, щоб під'єднувати пристрої до місць. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.flush-devices + + + + Flush device to seat attachments + Zurücksetzen der an eine Arbeitsstation angeschlossenen Geräte + Αφαίρεση συσκευής από προσαρτήσεις σταθμού εργασίας + Révoquer les associations de périphériques aux postes (seats) + Eszközök és munkaállomások csatolásainak törlése + Scollega i dispositivi dalla postazione + Usunięcie podłączenia urządzeń do stanowisk + Liberar dispositivo para conexões da estação + Сбросить привязки устройств к рабочим местам + Töm bindningar för enhet-till-plats + Очисний пристрій для під'єднань до місця + Authentication is required for resetting how devices are attached to seats. + Legitimierung ist zum Zurücksetzen notwendig, wie Geräte an eine Arbeitsstation angeschlossen werden. + Απαιτείται πιστοποίηση για επαναφορά του τρόπου που οι συσκευές προσαρτώνται στους σταθμούς εργασίας. + Authentification requise pour révoquer les associations de périphériques aux postes (seats). + Hitelesítés szükséges az eszközök munkaállomásokhoz csatolásainak alaphelyzetbe állításához. + Autenticazione richiesta per ripristinare come i dispositivi sono collegati alle postazioni. + Wymagane jest uwierzytelnienie, aby ponownie ustawić sposób podłączenia urządzeń do stanowisk. + É necessária autenticação para redefinir a quantidade de dispositivos conectados na estação. + Чтобы сбросить привязки устройств к рабочим местам, необходимо пройти аутентификацию. + Autentisering krävs för att återställa hur enheter är bundna till platser. + Засвідчення потрібно, щоб перезапустити спосіб під'єднання до місць. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Power off the system + Das System ausschalten + Σβήσιμο του συστήματος + Éteindre le système + A rendszer kikapcsolása + Spegnere il sistema + Wyłączenie systemu + Desligar o sistema + Выключить систему + Stäng av systemet + Вимкнути систему + Authentication is required for powering off the system. + Legitimierung ist zum Ausschalten des Systems notwendig. + Απαιτείται πιστοποίηση για την σβήσιμο του συστήματος. + Authentification requise pour éteindre le système. + Hitelesítés szükséges a rendszer kikapcsolásához. + Autenticazione richiesta per spegnere il sistema. + Wymagane jest uwierzytelnienie, aby wyłączyć system. + É necessária autenticação para desligar o sistema. + Чтобы выключить систему, необходимо пройти аутентификацию. + Autentisering krävs för att stänga av systemet. + Засвідчення потрібно, щоб вимкнути систему. + + auth_admin_keep + auth_admin_keep + yes + + + + + Power off the system while other users are logged in + Das System herunter fahren, während andere Benutzer angemeldet sind + Σβήσιμο του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Éteindre le système alors que d'autres utilisateurs sont connectés + A rendszer kikapcsolása miközben be vannak jelentkezve más felhasználók + Spegnere il sistema mentre altri utenti sono connessi + Wyłączenie systemu, kiedy są zalogowani inni użytkownicy + Desligar o sistema enquanto outros usuários estão conectados + Выключить систему, несмотря на то, что в ней работают другие пользователи + Stäng av systemet medan andra användare är inloggade + Вимикнути систему, коли інші користувачі ще в ній + Authentication is required for powering off the system while other users are logged in. + Legitimierung ist zum Herunterfahren des Systems notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για σβήσιμο του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour éteindre le système alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer kikapcsolásához miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per spegnere il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para desligar o sistema enquanto outros usuários estão conectados. + Чтобы выключить систему, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att stänga av systemet medan andra användare är inloggade. + Засвідчення потрібно, щоб вимкнути систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.power-off + + + + Power off the system while an application asked to inhibit it + Das System ausschalten, während eine Anwendung anfordert es zu unterbinden + Απενεργοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Éteindre le système alors qu'une application a demandé de l'empêcher + A rendszer kikapcsolása miközben egy alkalmazás ennek meggátlását kérte + Spegnere il sistema mentre un'applicazione chiede di inibirne l'azione + Wyłączenie systemu, kiedy program zażądał jego wstrzymania + Desligar o sistema enquanto um aplicativo solicitou inibição + Выключить систему, несмотря на то, что приложение запросило блокировку выключения + Stäng av systemet även då ett program hindrar det + Вимкнути систему, коли програми намагаються першкодити цьому + Authentication is required for powering off the system while an application asked to inhibit it. + Legitimierung ist zum Ausschalten des Systems notwendig, während eine Anwendung anfordert es zu unterbinden. + Απαιτείται πιστοποίηση για απενεργοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour éteindre le système alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer kikapcsolásához miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per spegnere il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy program zażądał jego wstrzymania. + É necessária autenticação para desligar o sistema enquanto um aplicativo solicitou inibição. + Чтобы выключить систему, несмотря на то, что приложение запросило блокировку выключения, необходимо пройти аутентификацию. + Autentisering krävs för att stänga av systemet även då ett program hindrar det. + Засвідчення потрібно, щоб вимкнути систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.power-off + + + + Reboot the system + Das System neu starten + Επανεκκίνηση του συστήματος + Redémarrer le système + A rendszer újraindítása + Riavviare il sistema + Ponowne uruchomienie systemu + Reiniciar o sistema + Перезагрузить систему + Starta om systemet + Перезавантажити систему + Authentication is required for rebooting the system. + Legitimierung ist zum Neustart des Systems notwendig. + Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος. + Authentification requise pour redémarrer le système. + Hitelesítés szükséges a rendszer újraindításához. + Autenticazione richiesta per riavviare il sistema. + Wymagane jest uwierzytelnienie, aby ponownie uruchomić system. + É necessária autenticação para reiniciar o sistema. + Чтобы перезагрузить систему, необходимо пройти аутентификацию. + Autentisering krävs för att starta om systemet. + Для перезавантаження системи необхідна ідентифікація. + + auth_admin_keep + auth_admin_keep + yes + + + + + Reboot the system while other users are logged in + Das Systems neu starten, während andere Benutzer angemeldet sind + Επανεκκίνηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Redémarrer le système alors que d'autres utilisateurs sont connectés + A rendszer újraindítása mialatt be vannak jelentkezve más felhasználók + Riavviare il sistema mentre altri utenti sono connessi + Ponowne uruchomienie systemu, kiedy są zalogowani inni użytkownicy + Reiniciar o sistema enquanto outros usuários estiverem conectados + Перезагрузить систему, несмотря на то, что в ней работают другие пользователи + Starta om systemet medan andra användare är inloggade + Перезавантажити, якщо інщі користувачі в системі + Authentication is required for rebooting the system while other users are logged in. + Legitimierung ist zum Neustart des Systems notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour redémarrer le système alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer újraindításához miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per riavviare il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para reiniciar o sistema enquanto outros usuários estiverem conectados. + Чтобы перезагрузить систему, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att starta om systemet medan andra användare är inloggade. + Засвідчення потрібно, щоб перезапустити систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.reboot + + + + Reboot the system while an application asked to inhibit it + Das System neu starten, während eine Anwendung anfordert es zu unterbinden + Επανεκκίνηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί + Redémarrer le système alors qu'une application a demandé de l'empêcher + A rendszer újraindítása miközben egy alkalmazás ennek meggátlását kérte + Riavviare il sistema mentre un'applicazione chiede di inibirne l'azione + Ponowne uruchomienie systemu, kiedy program zażądał jego wstrzymania + Reiniciar o sistema enquanto um aplicativo solicitou inibição + Перезагрузить систему, несмотря на то, что приложение запросило блокировку выключения + Starta om systemet även då ett program hindrar det. + Перезапустити систему, коли програми намагаються першкодити цьому + Authentication is required for rebooting the system while an application asked to inhibit it. + Legitimierung ist zum Neustart des Systems notwendig, während eine Anwendung anforderte es zu unterbinden. + Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour redémarrer le système alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer újraindításához miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per riavviare il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy program zażądał jego wstrzymania. + É necessária autenticação para reiniciar o sistema enquanto um aplicativo solicitou inibição. + Чтобы перезагрузить систему, несмотря на то, что приложение запросило блокировку выключения, необходимо пройти аутентификацию. + Autentisering krävs för att starta om systemet även då ett program hindrar det. + Засвідчення потрібно, щоб перезапустити систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.reboot + + + + Suspend the system + Das System in Bereitschaft versetzen + Αναστολή του συστήματος + Mettre le système en veille + A rendszer felfüggesztése + Sospendere il sistema + Uśpienie systemu + Suspender o sistema + Перевести систему в ждущий режим + Försätt system i vänteläge + Призупинити систему + Authentication is required for suspending the system. + Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig. + Απαιτείται πιστοποίηση για την αναστολή του συστήματος. + Authentification requise pour mettre le système en veille. + Hitelesítés szükséges a rendszer felfüggesztéséhez. + Autenticazione richiesta per sospendere il sistema. + Wymagane jest uwierzytelnienie, aby uśpić system. + É necessária autenticação para suspender o sistema. + Чтобы перевести систему в ждущий режим, необходимо пройти аутентификацию. + Autentisering krävs för att försätta system i vänteläge. + Засвідчення потрібно, щоб призупинити систему. + + auth_admin_keep + auth_admin_keep + yes + + + + + Suspend the system while other users are logged in + Das System in Bereitschaft versetzen, während andere Benutzer angemeldet sind. + Αναστολή του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Mettre le système en veille alors que d'autres utilisateurs sont connectés + A rendszer felfüggesztése mialatt be vannak jelentkezve más felhasználók + Sospendere il sistema mentre altri utenti sono connessi + Uśpienie systemu, kiedy są zalogowani inni użytkownicy + Suspender o sistema enquanto outros usuários estiverem conectados + Перевести систему в ждущий режим, несмотря на то, что в ней работают другие пользователи + Försätt systemet i vänteläge medan andra användare är inloggade + Призупинити систему, коли інші користувачі в ній + Authentication is required for suspending the system while other users are logged in. + Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για αναστολή του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour mettre le système en veille alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer felfüggesztéséhez miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per sospendere il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby uśpić system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para suspender o sistema enquanto outros usuários estiverem conectados. + Чтобы перевести систему в ждущий режим, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att försätta systemet i vänteläge medan andra användare är inloggade. + Засвідчення потрібно, щоб призупинити систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.suspend + + + + Suspend the system while an application asked to inhibit it + Das System in Bereitschaft versetzen, während eine Anwendung anfordert dies zu unterbinden + Αναστολή του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί + Mettre le système en veille alors qu'une application a demandé de l'empêcher + A rendszer felfüggesztése miközben egy alkalmazás ennek meggátlását kérte + Sospendere il sistema mentre un'applicazione chiede di inibirne l'azione + Uśpienie systemu, kiedy program zażądał jego wstrzymania + Suspender o sistema enquanto um aplicativo solicitou inibição + Перевести систему в ждущий режим, несмотря на то, что приложение запросило блокировку + Försätt systemet i vänteläge även då ett program hindrar det + Призупинити систему, коли програми намагаються першкодити цьому + Authentication is required for suspending the system while an application asked to inhibit it. + Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig, während eine Anwendung anfordert dies zu unterbinden. + Απαιτείται πιστοποίηση για αναστολή του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour mettre le système en veille alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer felfüggesztéséhez miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per sospendere il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby uśpić system, kiedy program zażądał jego wstrzymania. + É necessária autenticação para suspender o sistema enquanto um aplicativo solicitou inibição. + Чтобы перевести систему в ждущий режим, несмотря на то, что приложение запросило блокировку, необходимо пройти аутентификацию. + Autentisering krävs för att försätta ett program i vänteläge även då ett program hindrar det. + Засвідчення потрібно, щоб призупнити систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.suspend + + + + Hibernate the system + Den Ruhezustand des Systems aktivieren + Αδρανοποίηση του συτήματος + Mettre le système en hibernation + A rendszer hibernálása + Ibernare il sistema + Hibernacja systemu + Hibernar o sistema + Перевести систему в спящий режим + Försätt systemet i viloläge + Приспати систему + Authentication is required for hibernating the system. + Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig. + Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος. + Authentification requise pour mettre le système en hibernation. + Hitelesítés szükséges a rendszer hibernálásához. + Autenticazione richiesta per ibernare il sistema. + Wymagane jest uwierzytelnienie, aby zahibernować system. + É necessária autenticação para hibernar o sistema. + Чтобы перевести систему в спящий режим, необходимо пройти аутентификацию. + Autentisering krävs för att försätta systemet i viloläge. + Засвідчення потрібно, щоб приспати систему. + + auth_admin_keep + auth_admin_keep + yes + + + + + Hibernate the system while other users are logged in + Den Ruhezustand des Systems aktivieren, während andere Benutzer angemeldet sind + Αδρανοποίηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Mettre le système en hibernation alors que d'autres utilisateurs sont connectés + A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók + Ibernare il sistema mentre altri utenti sono connessi + Hibernacja systemu, kiedy są zalogowani inni użytkownicy + Hibernar o sistema enquanto outros usuários estiverem conectados + Перевести систему в спящий режим, несмотря на то, что в ней работают другие пользователи + Försätt systemet i viloläge medan andra användare är inloggade + Приспати систему, коли інші користувачі в ній + Authentication is required for hibernating the system while other users are logged in. + Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour mettre le système en hibernation alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer hibernálásához miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per ibernare il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para hibernar o sistema enquanto outros usuários estiverem conectados. + Чтобы перевести систему в спящий режим, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att försätta systemet i viloläge medan andra användare är inloggade. + Засвідчення потрібно, щоб присипання систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.hibernate + + + + Hibernate the system while an application asked to inhibit it + Das System in den Ruhezustand versetzen, während eine Anwendung wünscht dies zu verhindern + Αδρανοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί + Mettre le système en hibernation alors qu'une application a demandé de l'empêcher + A rendszer hibernálása miközben egy alkalmazás ennek meggátlását kérte + Ibernare il sistema mentre un'applicazione chiede di inibirne l'azione + Hibernacja systemu, kiedy program zażądał jej wstrzymania + Hibernar o sistema enquanto um aplicativo solicitou inibição + Перевести систему в спящий режим, несмотря на то, что приложение запросило блокировку + Försätt systemet i viloläge även då ett program hindrar det + Приспати систему, коли програми намагаються першкодити цьому + Authentication is required for hibernating the system while an application asked to inhibit it. + Legitimierung ist zum Versetzen des System in den Ruhezustand notwendig, während eine Anwendung wünscht dies zu verhindern. + Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour mettre le système en hibernation alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer hibernálásához miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per ibernare il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy program zażądał jej wstrzymania. + É necessária autenticação para hibernar o sistema enquanto um aplicativo solicitou inibição. + Чтобы перевести систему в спящий режим, несмотря на то, что приложение запросило блокировку, необходимо пройти аутентификацию. + Autentisering krävs för att försätta ett program i viloläge även då ett program hindrar det. + Засвідчення потрібно, щоб приспати систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.hibernate + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.machine1.policy b/SOURCES/org.freedesktop.machine1.policy new file mode 100644 index 00000000..d7998b83 --- /dev/null +++ b/SOURCES/org.freedesktop.machine1.policy @@ -0,0 +1,34 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Log into a local container + In einem lokalen Container anmelden + Connexion dans un conteneur local + Bejelentkezés helyi konténerbe + Accedi in un container locale + Logowanie do lokalnego kontenera + Conectar a um contêiner local + Зайти в локальный контейнер + Logga till en lokal behållare + Authentication is required to log into a local container + Legitimierung ist zum Anmelden in einem lokalen Container notwendig + Authentification requise pour permettre la connexion dans un conteneur local. + Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe. + Autenticazione richiesta per accedere in un container locale + Wymagane jest uwierzytelnienie, aby zalogować się do lokalnego kontenera + É necessária autenticação para se conectar a um contêiner local. + Autentisering krävs för att tillåta loggning till en lokal behållare. + + auth_admin + auth_admin + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.systemd1.policy b/SOURCES/org.freedesktop.systemd1.policy new file mode 100644 index 00000000..f7e013ca --- /dev/null +++ b/SOURCES/org.freedesktop.systemd1.policy @@ -0,0 +1,118 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Send passphrase back to system + Passphrase zurück an das System senden + Αποστολή του συνθηματικού πίσω στο σύστημα + Renvoyer la phrase secrète au système + Jelmondat visszaküldése a rendszernek + Inviare la frase segreta (passphrase) al sistema + Wysłanie hasła z powrotem do systemu + Enviar frase secreta de volta ao sistema + Отправить пароль системе + Skicka tillbaka lösenfras till system + Надіслати пароль назад у систему + Authentication is required to send the entered passphrase back to the system. + Legitimierung ist zum Senden des eingegebenen Kennworts zurück an das System notwendig. + Απαιτείται πιστοποίηση για αποστολή του εισερχόμενου συνθηματικού πίσω στο σύστημα. + Authentification requise pour renvoyer la phrase secrète au système. + Hitelesítés szükséges a bevitt jelmondat visszaküldéséhez a rendszernek. + Autenticazione richiesta per inviare la frase segreta (passphrase) al sistema. + Wymagane jest uwierzytelnienie, aby wysłać podane hasło z powrotem do systemu. + É necessária autenticação para enviar a frase secreta informada de volta ao sistema. + Чтобы отправить пароль системе, необходимо пройти аутентификацию. + Autentisering krävs för att skicka tillbaka den angivna lösenfrasen till systemet. + Засвідчення потрібно, щоб надіслати введений пароль назад у систему. + + no + no + auth_admin_keep + + /usr/lib/systemd/systemd-reply-password + + + + Manage system services or units + Systemdienste und Einheiten verwalten + Gérer les services système ou les unités + Rendszerszolgáltatások vagy -egységek kezelése + Gestisci i servizi o le unità di sistema + Zarządzanie usługami lub jednostkami systemu + Gerenciar unidades e serviços do sistema + Управление системными службами и юнитами + Hantera systemtjänster eller enheter + Authentication is required to manage system services or units. + Legitimierung ist notwendig für die Verwaltung von Systemdiensten und Einheiten + Authentification requise pour gérer les services système ou les unités. + Hitelesítés szükséges a rendszerszolgáltatások vagy -egységek kezeléséhez. + Autenticazione richiesta per gestire servizi e unità di sistema. + Wymagane jest uwierzytelnienie, aby zarządzać usługami lub jednostkami systemu. + É necessária autenticação para gerenciar unidades e serviços do sistema. + Для управления системными службами и юнитами, необходимо пройти аутентификацию. + Autentisering krävs för att hantera systemtjänster eller enheter. + + auth_admin + auth_admin + auth_admin_keep + + + + + Manage system service or unit files + Systemdienste und Einheitendateien verwalten + Gérer le service système ou ses fichiers unités + Rendszerszolgáltatás- vagy egységfájlok kezelése + Gestisci i file dei servizi o delle unità di sistema + Zarządzanie plikami usług lub jednostek systemu + Gerenciar arquivos de unidades e serviços do sistema + Управление файлами конфигурации системных служб и юнитов + Hantera systemtjänster eller enhetsfiler + Authentication is required to manage system service or unit files. + Legitimierung ist notwendig für die Verwaltung von Systemdiensten und Einheitendateien. + Authentification requise pour gérer le service système ou ses fichiers unités. + Hitelesítés szükséges a rendszerszolgáltatás- vagy egységfájlok kezeléséhez. + Autenticazione richiesta per gestire i file dei servizi o delle unità di sistema. + Wymagane jest uwierzytelnienie, aby zarządzać plikami usług lub jednostek systemu. + É necessária autenticação para gerenciar arquivos "unit" e "service" do sistema. + Для управления файлами конфигурации системных служб и юнитов, необходимо пройти аутентификацию. + Autentisering krävs för att hantera systemtjänster eller enhetsfiler. + + auth_admin + auth_admin + auth_admin_keep + + + + + Reload the systemd state + Den systemd-Zustand neu laden + Recharger l'état de systemd + A systemd állapotának újratöltése + Riavviare lo stato di systemd + Ponowne wczytanie stanu systemd + Recarregar o estado do sistema + Перечитать конфигурацию systemd + Läs om tillståndet för systemd + Authentication is required to reload the systemd state. + Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig. + Authentification requise pour recharger l'état de systemd + Hitelesítés szükséges a systemd állapotának újratöltéséhez. + Autenticazione richiesta per riavviare lo stato di sistemd. + Wymagane jest uwierzytelnienie, aby ponownie wczytać stan systemd. + É necessária autenticação para recarregar o estado do sistema. + Чтобы заставить systemd перечитать конфигурацию, необходимо пройти аутентификацию. + Autentisering krävs för att läsa om tillståndet för systemd. + + auth_admin + auth_admin + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.timedate1.policy b/SOURCES/org.freedesktop.timedate1.policy new file mode 100644 index 00000000..e9f4c96c --- /dev/null +++ b/SOURCES/org.freedesktop.timedate1.policy @@ -0,0 +1,130 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Set system time + Die Systemzeit festlegen + Ορισμός ώρας συστήματος + Définir l'heure du système + Rendszeridő beállítása + Configura l'orario di sistema + Ustawienie czasu systemu + Definir horário do sistema + Настроить системное время + Ange systemtid + Вказати системний час + Authentication is required to set the system time. + Legitimierung ist zum Festlegen der Systemzeit notwendig. + Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος. + Authentification requise pour définir l'heure du système. + Hitelesítés szükséges a rendszeridő beállításához. + Autenticazione richiesta per configurare l'orario di sistema. + Wymagane jest uwierzytelnienie, aby ustawić czas systemu. + É necessária autenticação para definir o horário do sistema. + Чтобы настроить системное время, необходимо пройти аутентификацию. + Autentisering krävs för ange systemtiden. + Засвідчення потрібно, щоб вказати системний час. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.timedate1.set-timezone org.freedesktop.timedate1.set-ntp + + + + Set system timezone + Die Systemzeitzone festlegen + Ορισμός ζώνης ώρας συστήματος + Définir le fuseau horaire du système + Rendszer időzónájának beállítása + Configura il fuso orario di sistema + Ustawienie strefy czasowej systemu + Definir fuso horário do sistema + Настроить часовой пояс + Ange systemets tidszon + Вказати системний часовий пояс + Authentication is required to set the system timezone. + Legitimierung ist zum Festlegen der Systemzeitzone notwendig. + Απαιτείται πιστοποίηση για να ορίσετε την ώρα ζώνης του συστήματος. + Authentification requise pour définir le fuseau horaire du système. + Hitelesítés szükséges a rendszer időzónájának beállításához. + Autenticazione richiesta per configurare il fuso orario di sistema. + Wymagane jest uwierzytelnienie, aby ustawić strefę czasową systemu. + É necessária autenticação para definir o fuso horário do sistema. + Чтобы настроить часовой пояс, необходимо пройти аутентификацию. + Autentisering krävs för att ange systemets tidszon. + Засвідчення потрібно, щоб вказати системний часовий пояс. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Set RTC to local timezone or UTC + Echtzeituhr auf lokale Zeitzone oder UTC setzen + Ορισμός RTC στην τοπική ζώνη ώρας ή UTC + Positionner l'horloge matérielle à l'heure locale ou sur le temps universel coordonné (UTC) + Az RTC beállítása helyi időzónára vagy UTC-re + Configura l'orologio di sistema (RTC) al fuso orario locale o al tempo civile (UTC) + Ustawienie RTC na lokalną strefę czasową lub strefę UTC + Definir o relógio do sistema (RTC) para fuso horário local ou UTC + Установить аппаратные часы по местному времени или по Гринвичу + Sätt realtidsklocka (RTC) till lokal tidszon eller koordinerad universell tid (UTC) + Вкажіть RTC для локального часового поясу або UTC + Authentication is required to control whether the RTC stores the local or UTC time. + Legitimierung ist notwendig zum Festlegen, ob die Echtzeituhr auf lokale Zeitzone oder UTC eingestellt ist. + Απαιτείται πιστοποίηση για να ελέγξετε αν το RTC αποθηκεύει την τοπική ή την ώρα UTC. + Authentification requise pour positionner l'horloge matérielle à l'heure locale ou sur le temps universel coordonné (UTC). + Hitelesítés szükséges az RTC beállításához a helyi időzóna vagy UTC tárolására. + Autenticazione richiesta per verificare se l'orologio di sistema (RTC) è configurato all'orario locale o al tempo civile (UTC). + Wymagane jest uwierzytelnienie, aby kontrolować, czy RTC przechowuje czas lokalny lub czas UTC. + É necessária autenticação para controlar se o RTC deve, ou não, armazenar o horário local ou de UTC. + Чтобы контролировать, установлены аппаратные часы по местному времени или по Гринвичу, необходимо пройти аутентификацию. + Autentisering krävs för att kunna kontrollera huruvida realtidsklockan (RTC) lagrar den lokala eller koordinerade universella tiden (UTC). + Засвідчення потрібно, щоб контролювати, чи RTC зберігає час, чи UTC. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Turn network time synchronization on or off + Netzwerkzeitabgeich ein- oder ausschalten + Ενεργοποίηση/Απενεργοποίηση συγχρονισμού ώρας δικτύου + Activer ou désactiver la synchronisation de l'heure avec le réseau + Hálózati időszinkronizáció be- vagy kikapcsolása + Abilita o meno la sincronizzazione dell'orario in rete + Włączenie lub wyłączenie synchronizacji czasu przez sieć + Ligar/desligar a sincronização do horário em rede + Включить или выключить синхронизацию времени по сети + Växla synkronisering av nätverkstid på och av + Увімкнути або вимкнути синхронізування через мережу + Authentication is required to control whether network time synchronization shall be enabled. + Legitimierung ist zum Festlegen, ob Netzwerkzeitabgeich eingeschaltet sein soll, erforderlich. + Απαιτείται πιστοποίηση για να ελέγξετε αν ο συγχρονισμός ώρας δικτύου θα ενεργοποιηθεί. + Authentification requise pour activer ou désactiver la synchronisation de l'heure avec le réseau. + Hitelesítés szükséges a hálózati időszinkronizáció engedélyezéséhez. + Autenticazione richiesta per verificare se la sincronizzazione dell'orario in rete possa essere attivata. + Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację czasu przez sieć. + É necessária autenticação para controlar se deve ser habilitada, ou não, a sincronização de horário através de rede. + Чтобы включить или выключить синхронизацию времени по сети, необходимо пройти аутентификацию. + Autentisering krävs för att kontrollera huruvida synkronisering av nätverkstid ska vara aktiverat. + Засвідчення потрібно, щоб контролювати, чи синхронізування часу через мережу запущено. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/phys-port-name-gen b/SOURCES/phys-port-name-gen new file mode 100755 index 00000000..abf47cf7 --- /dev/null +++ b/SOURCES/phys-port-name-gen @@ -0,0 +1,37 @@ +#!/bin/bash + +SYSPATH="/sys/class/net/$1" +DEV_ID=$(<"${SYSPATH}/dev_id") +DEV_PORT=$(<"${SYSPATH}/dev_port") +PHYS_PORT_NAME=$(<"${SYSPATH}/phys_port_name") + +#if PHYS_PORT_NAME is empty we are safe +[ -z "${PHYS_PORT_NAME}" ] && exit 0 + +# On-board index based names +if [ -n "${ID_NET_NAME_ONBOARD}" ]; then + ID_NET_NAME_ONBOARD="${ID_NET_NAME_ONBOARD%d${DEV_PORT}}n${PHYS_PORT_NAME}" +fi + +if [ -n "${DEV_ID}" ]; then + DEV_ID=$(printf "%u" "${DEV_ID}") + if [ "${DEV_ID}" -eq "0" ] && [ -n "${DEV_PORT}" ]; then + # dev_port is decimal string, but we have a bug in net_id and we convert it to integer using base 16 + DEV_ID=$(printf "%u" "0x${DEV_PORT}") + fi +fi + +# PCI hot plug slot number based names +if [ -n "${ID_NET_NAME_SLOT}" ]; then + ID_NET_NAME_SLOT="${ID_NET_NAME_SLOT%d${DEV_ID}}n${PHYS_PORT_NAME}" +fi + +# PCI path based names +if [ -n "${ID_NET_NAME_PATH}" ]; then + ID_NET_NAME_PATH="${ID_NET_NAME_PATH%d${DEV_ID}}n${PHYS_PORT_NAME}" +fi + +[ -n "${ID_NET_NAME_ONBOARD}" ] && echo "ID_NET_NAME_ONBOARD=${ID_NET_NAME_ONBOARD}" +[ -n "${ID_NET_NAME_SLOT}" ] && echo "ID_NET_NAME_SLOT=${ID_NET_NAME_SLOT}" +[ -n "${ID_NET_NAME_PATH}" ] && echo "ID_NET_NAME_PATH=${ID_NET_NAME_PATH}" + diff --git a/SOURCES/rc.local b/SOURCES/rc.local new file mode 100644 index 00000000..a7e0ad25 --- /dev/null +++ b/SOURCES/rc.local @@ -0,0 +1,13 @@ +#!/bin/bash +# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES +# +# It is highly advisable to create own systemd services or udev rules +# to run scripts during boot instead of using this file. +# +# In contrast to previous versions due to parallel execution during boot +# this script will NOT be run after all other services. +# +# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure +# that this script will be executed during boot. + +touch /var/lock/subsys/local diff --git a/SOURCES/systemd-sysv-convert b/SOURCES/systemd-sysv-convert new file mode 100755 index 00000000..1c3f1a98 --- /dev/null +++ b/SOURCES/systemd-sysv-convert @@ -0,0 +1,148 @@ +#!/usr/bin/python +# -*- Mode: Python; python-indent: 8; indent-tabs-mode: t -*- + +import sys, os, argparse, errno + +def find_service(service, runlevel): + priority = -1 + + for l in os.listdir("/etc/rc%i.d" % runlevel): + if len(l) < 4: + continue + + if l[0] != 'S' or l[3:] != service: + continue + + p = int(l[1:3]) + + if p >= 0 and p <= 99 and p >= priority: + priority = p; + + return priority + +def lookup_database(services): + try: + database = open("/var/lib/systemd/sysv-convert/database", "r") + except IOError, e: + if e.errno != errno.ENOENT: + raise e + + return {} + + found = {} + k = 0 + + for line in database: + service, r, p = line.strip().split("\t", 3) + k += 1 + + try: + runlevel = int(r) + priority = int(p) + except ValueError, e: + sys.stderr.write("Failed to parse database line %i. Ignoring." % k) + continue + + if runlevel not in (2, 3, 4, 5): + sys.stderr.write("Runlevel out of bounds in database line %i. Ignoring." % k) + continue + + if priority < 0 or priority > 99: + sys.stderr.write("Priority out of bounds in database line %i. Ignoring." % k) + continue + + if service not in services: + continue + + if service not in found: + found[service] = {} + + if runlevel not in found[service] or found[service][runlevel] < priority: + found[service][runlevel] = priority + + return found + +def mkdir_p(path): + try: + os.makedirs(path, 0755) + except OSError, e: + if e.errno != errno.EEXIST: + raise e + +if os.geteuid() != 0: + sys.stderr.write("Need to be root.\n") + sys.exit(1) + +parser = argparse.ArgumentParser(description='Save and Restore SysV Service Runlevel Information') + +parser.add_argument('services', metavar='SERVICE', type=str, nargs='+', + help='Service names') + +parser.add_argument('--save', dest='save', action='store_const', + const=True, default=False, + help='Save SysV runlevel information for one or more services') + +parser.add_argument('--show', dest='show', action='store_const', + const=True, default=False, + help='Show saved SysV runlevel information for one or more services') + +parser.add_argument('--apply', dest='apply', action='store_const', + const=True, default=False, + help='Apply saved SysV runlevel information for one or more services to systemd counterparts') + +a = parser.parse_args() + +if a.save: + for service in a.services: + if not os.access("/etc/rc.d/init.d/%s" % service, os.F_OK): + sys.stderr.write("SysV service %s does not exist.\n" % service) + sys.exit(1) + + mkdir_p("/var/lib/systemd/sysv-convert") + database = open("/var/lib/systemd/sysv-convert/database", "a") + + for runlevel in (2, 3, 4, 5): + priority = find_service(service, runlevel) + + if priority >= 0: + database.write("%s\t%s\t%s\n" % (service, runlevel, priority)) + +elif a.show: + found = lookup_database(a.services) + + if len(found) <= 0: + sys.stderr.write("No information about passed services found.\n") + sys.exit(1) + + for service, data in found.iteritems(): + for runlevel, priority in data.iteritems(): + sys.stdout.write("SysV service %s enabled in runlevel %s at priority %s\n" % (service, runlevel, priority)) + +elif a.apply: + for service in a.services: + if not os.access("/lib/systemd/system/%s.service" % service, os.F_OK): + sys.stderr.write("systemd service %s.service does not exist.\n" % service) + sys.exit(1) + + found = lookup_database(a.services) + + if len(found) <= 0: + sys.stderr.write("No information about passed services found.\n") + sys.exit(1) + + for service, data in found.iteritems(): + for runlevel in data.iterkeys(): + + sys.stderr.write("ln -sf /lib/systemd/system/%s.service /etc/systemd/system/runlevel%i.target.wants/%s.service\n" % (service, runlevel, service)) + + mkdir_p("/etc/systemd/system/runlevel%i.target.wants" % runlevel) + + try: + os.symlink("/lib/systemd/system/%s.service" % service, + "/etc/systemd/system/runlevel%i.target.wants/%s.service" % (runlevel, service)) + except OSError, e: + if e.errno != errno.EEXIST: + raise e + +else: + parser.print_help() diff --git a/SOURCES/yum-protect-systemd.conf b/SOURCES/yum-protect-systemd.conf new file mode 100644 index 00000000..24ad079b --- /dev/null +++ b/SOURCES/yum-protect-systemd.conf @@ -0,0 +1 @@ +systemd diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec new file mode 100644 index 00000000..070d7d2a --- /dev/null +++ b/SPECS/systemd.spec @@ -0,0 +1,3279 @@ +# We ship a .pc file but don't want to have a dep on pkg-config. We +# strip the automatically generated dep here and instead co-own the +# directory. +%global __requires_exclude pkg-config +%global _hardened_build 1 +%global optflags %(echo %{optflags} | sed 's/-fPIE//' | sed 's/-fPIC//' | sed 's/-D_FORTIFY_SOURCE=2//') + + + +Name: systemd +Url: http://www.freedesktop.org/wiki/Software/systemd +Version: 219 +Release: 57%{?dist} +# For a breakdown of the licensing, see README +License: LGPLv2+ and MIT and GPLv2+ +Summary: A System and Service Manager + +Source0: https://github.com/systemd/systemd/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz +# Preset policy is in rhel-release package +# we are just disabling everything +Source1: 99-default-disable.preset +# Prevent accidental removal of the systemd package +Source2: yum-protect-systemd.conf +# SysV convert script. +Source3: systemd-sysv-convert +# ship /etc/rc.d/rc.local https://bugzilla.redhat.com/show_bug.cgi?id=968401 +Source4: rc.local +#https://bugzilla.redhat.com/show_bug.cgi?id=1032711 +Source5: 60-alias-kmsg.rules +# Stop-gap, just to ensure things work fine with rsyslog without having to change the package right-away +Source6: listen.conf +# Generating translations is sometimes broken, let's ship the translated policy files directly in sources +Source7: org.freedesktop.hostname1.policy +Source8: org.freedesktop.import1.policy +Source9: org.freedesktop.locale1.policy +Source10: org.freedesktop.login1.policy +Source11: org.freedesktop.machine1.policy +Source12: org.freedesktop.systemd1.policy +Source13: org.freedesktop.timedate1.policy +Source14: phys-port-name-gen +Source15: 76-phys-port-name.rules +Source16: 76-phys-port-name.conf + +# RHEL-specific +Patch0001: 0001-kernel-install-add-fedora-specific-callouts-to-new-k.patch +Patch0002: 0002-Revert-fsck-re-enable-fsck-l.patch +Patch0003: 0003-sysctl-bring-back-etc-sysctl.conf.patch +Patch0004: 0004-remove-user-.service.patch +Patch0005: 0005-logind-session-save-stopping-flag.patch +Patch0006: 0006-man-mention-System-Administrator-s-Guide-in-systemct.patch +Patch0007: 0007-rules-automatically-online-hot-added-CPUs.patch +Patch0008: 0008-Revert-remove-references-of-readahead.patch +Patch0009: 0009-Revert-missing-remove-fanotify.patch +Patch0010: 0010-Revert-readahead-wipe-out-readahead.patch +Patch0011: 0011-rules-add-rule-for-naming-Dell-iDRAC-USB-Virtual-NIC.patch +Patch0012: 0012-udev-net_id-correctly-name-netdevs-based-on-dev_port.patch +Patch0013: 0013-Revert-blkid-Warn-when-rejecting-a-superblock-with-a.patch +Patch0014: 0014-journald-audit-exit-gracefully-in-the-case-we-can-t-.patch +Patch0015: 0015-fedora-disable-resolv.conf-symlink.patch +Patch0016: 0016-Revert-timedated-manage-systemd-timesyncd-directly-i.patch +Patch0017: 0017-journal-remote-fix-certificate-status-memory-leak.patch +Patch0018: 0018-journal-remote-fix-client_cert-memory-leak.patch +Patch0019: 0019-tmpfiles-Fix-parse_acl-error-message.patch +Patch0020: 0020-test-utf8-fix-utf16-tests-on-BE-machines.patch +Patch0021: 0021-tmpfiles-avoid-creating-duplicate-acl-entries.patch +Patch0022: 0022-shared-time-util-fix-gcc5-warning.patch +Patch0023: 0023-test-time-test-infinity-parsing-in-nanoseconds.patch +Patch0024: 0024-bootchart-fix-default-init-path.patch +Patch0025: 0025-systemctl-bump-NOFILE-only-for-systemctl_main.patch +Patch0026: 0026-acl-util-avoid-freeing-uninitialized-pointer.patch +Patch0027: 0027-bootchart-svg-fix-checking-of-list-end.patch +Patch0028: 0028-systemd-add-getrandom-syscall-numbers-for-MIPS.patch +Patch0029: 0029-unit-use-weaker-dependencies-between-mount-and-devic.patch +Patch0030: 0030-unit-When-stopping-due-to-BindsTo-log-which-unit-cau.patch +Patch0031: 0031-sysctl-downgrade-message-about-sysctl-overrides-to-d.patch +Patch0032: 0032-sysctl-add-some-hints-how-to-override-settings.patch +Patch0033: 0033-core-rework-device-state-logic.patch +Patch0034: 0034-core-fix-return-value-on-OOM.patch +Patch0035: 0035-machined-use-x-machine-unix-prefix-for-the-container.patch +Patch0036: 0036-shared-AFS-is-also-a-network-filesystem.patch +Patch0037: 0037-core-downgrade-unit-type-not-supported-message.patch +Patch0038: 0038-journal-remote-fix-saving-of-binary-fields.patch +Patch0039: 0039-journal-fix-Inappropriate-ioctl-for-device-on-ext4.patch +Patch0040: 0040-sd-daemon-replace-VLA-with-alloca-to-make-llvm-happy.patch +Patch0041: 0041-tmpfiles-quietly-ignore-ACLs-on-unsupported-filesyst.patch +Patch0042: 0042-shared-util-assume-ac-when-sys-class-power_supply-is.patch +Patch0043: 0043-import-remove-unused-variable.patch +Patch0044: 0044-hwdb-fix-ThinkPad-X-Tablet-special-keys.patch +Patch0045: 0045-man-add-newlines-to-the-pull-raw-example-in-machinec.patch +Patch0046: 0046-core-shared-in-deserializing-match-same-files-reache.patch +Patch0047: 0047-shared-use-SocketAddress-in-socket_address_matches_f.patch +Patch0048: 0048-shared-avoid-semi-duplicating-socket_address_equal.patch +Patch0049: 0049-shared-handle-unnamed-sockets-in-socket_address_equa.patch +Patch0050: 0050-man-make-bootup-graph-consistent.patch +Patch0051: 0051-nspawn-fix-whitespace-and-typo-in-partition-table-bl.patch +Patch0052: 0052-man-explain-time-units-in-tmpfiles.patch +Patch0053: 0053-systemctl-check-validity-of-PID-we-received.patch +Patch0054: 0054-systemctl-support-auditd.service-better.patch +Patch0055: 0055-shared-unit-name-fix-gcc5-warning.patch +Patch0056: 0056-test-hashmap-fix-gcc5-warning.patch +Patch0057: 0057-shared-fix-wrong-assertion-in-barrier_set_role.patch +Patch0058: 0058-hwdb-Update-database-of-Bluetooth-company-identifier.patch +Patch0059: 0059-journal-make-skipping-of-exhausted-journal-files-eff.patch +Patch0060: 0060-shared-condition-fix-gcc5-warning.patch +Patch0061: 0061-man-correct-description-of-systemd-user-sessions.patch +Patch0062: 0062-build-sys-allow-lto-and-FORTIFY_SOURCE-with-O-sz.patch +Patch0063: 0063-man-fix-typo.patch +Patch0064: 0064-bus-proxyd-avoid-logging-oom-twice.patch +Patch0065: 0065-Do-not-run-sysv-generator-test-when-sysv-compat-is-d.patch +Patch0066: 0066-README-mention-ACLs-more.patch +Patch0067: 0067-Do-not-advertise-.d-snippets-over-main-config-file.patch +Patch0068: 0068-hwdb-add-pnpid-for-the-T450s-touchpad.patch +Patch0069: 0069-networkd-netdev-inform-when-we-take-over-an-existing.patch +Patch0070: 0070-man-replace-obsolete-wiki-link-with-man-page.patch +Patch0071: 0071-Use-correct-uname-identifiers-in-arch_map-for-SuperH.patch +Patch0072: 0072-hwdb-fix-Dell-XPS12-9Q33-key-name.patch +Patch0073: 0073-Remove-the-cap-on-epoll-events.patch +Patch0074: 0074-Allow-up-to-4096-simultaneous-connections.patch +Patch0075: 0075-hwdb-add-Logitech-G5-Laser-Mouse.patch +Patch0076: 0076-tmpfiles-Fix-handling-of-duplicate-lines.patch +Patch0077: 0077-hwdb-add-Lenovo-W451-to-TOUCHPAD_HAS_TRACKPOINT_BUTT.patch +Patch0078: 0078-vconsole-match-on-vtcon-events-not-fbcon-ones.patch +Patch0079: 0079-core-do-not-spawn-jobs-or-touch-other-units-during-c.patch +Patch0080: 0080-firstboot-set-all-spwd-fields-to-1-for-consistency-w.patch +Patch0081: 0081-sysusers-do-not-reject-users-with-already-present-et.patch +Patch0082: 0082-nspawn-fix-use-after-free-and-leak-in-error-paths.patch +Patch0083: 0083-login-fix-copy-pasto-in-error-path.patch +Patch0084: 0084-journalctl-update-hint-now-that-we-set-ACL-everywher.patch +Patch0085: 0085-sd-journal-return-error-when-we-cannot-open-a-file.patch +Patch0086: 0086-missing.h-add-NDA_.patch +Patch0087: 0087-udevd-close-race-in-udev-settle.patch +Patch0088: 0088-man-document-that-ExecStartPre-is-not-the-place-to-s.patch +Patch0089: 0089-journal-fix-return-code.patch +Patch0090: 0090-console-fix-error-code-inversion.patch +Patch0091: 0091-bus-proxy-complain-only-once-about-queue-overflows.patch +Patch0092: 0092-cgtop-fix-assert-when-not-on-tty.patch +Patch0093: 0093-man-split-paragraph.patch +Patch0094: 0094-hwdb-update.patch +Patch0095: 0095-networkd-Begin-with-serial-number-1-for-netlink-requ.patch +Patch0096: 0096-journal-remote-downgrade-routine-messages-to-debug.patch +Patch0097: 0097-journal-remote-process-events-without-delay.patch +Patch0098: 0098-man-update-example-2-in-systemd.network-5.patch +Patch0099: 0099-gpt-auto-generator-fix-detection-of-srv.patch +Patch0100: 0100-sd-rtnl-never-set-serial-to-0.patch +Patch0101: 0101-gpt-auto-generator-allow-type-check-to-fail.patch +Patch0102: 0102-man-fix-a-bunch-of-links.patch +Patch0103: 0103-man-link-to-fd.o-for-dbus-stuff.patch +Patch0104: 0104-man-fix-name-of-systemd.resource-control-5.patch +Patch0105: 0105-selinux-fix-SEGV-during-switch-root-if-SELinux-polic.patch +Patch0106: 0106-service-don-t-add-After-dependencies-on-.busname-uni.patch +Patch0107: 0107-libudev-monitor-fix-error-path-in-send_device.patch +Patch0108: 0108-core-remove-left-over-debug-message.patch +Patch0109: 0109-units-there-is-no-systemd-udev-hwdb-update.service.patch +Patch0110: 0110-util-remove-redundant-debug-message.patch +Patch0111: 0111-tmpfiles-remove-redundant-debug-message.patch +Patch0112: 0112-sysv-generator-initialize-LookupPaths-just-once.patch +Patch0113: 0113-core-do-not-use-quotes-around-virt-and-arch.patch +Patch0114: 0114-udev-downgrade-has-devpath-and-filled-with-db-file-m.patch +Patch0115: 0115-cryptsetup-generator-remove-warning-about-crypttab-a.patch +Patch0116: 0116-sysctl-tweak-debug-message.patch +Patch0117: 0117-journald-add-syslog-fields-for-audit-messages.patch +Patch0118: 0118-core-remove-useless-debug-message.patch +Patch0119: 0119-man-standard-conf-change-directory-reference-to-wild.patch +Patch0120: 0120-core-don-t-change-removed-devices-to-state-tentative.patch +Patch0121: 0121-fstab-generator-ignore-invalid-swap-priority.patch +Patch0122: 0122-missing.h-add-more-btrfs-types-and-defines.patch +Patch0123: 0123-build-sys-add-configure-option-to-disableLTO-gold.patch +Patch0124: 0124-rules-bring-back-80-net-name-slot.rules.patch +Patch0125: 0125-Revert-journald-allow-restarting-journald-without-lo.patch +Patch0126: 0126-Revert-man-switch-yum-to-dnf-for-Fedora.patch +Patch0127: 0127-journal-remove-audit-socket-unit-files.patch +Patch0128: 0128-factory-we-don-t-want-that.patch +Patch0129: 0129-timedated-flip-internal-status-after-executing-opera.patch +Patch0130: 0130-timedated-fix-enable-disable-reversal.patch +Patch0131: 0131-core-make-SELinux-enable-disable-check-symmetric.patch +Patch0132: 0132-shared-add-path_compare-an-ordering-path-comparison.patch +Patch0133: 0133-core-namespace-fix-path-sorting.patch +Patch0134: 0134-machine-do-not-rely-on-asprintf-setting-arg-on-error.patch +Patch0135: 0135-some-compilators-don-t-support-__INCLUDE_LEVEL__.patch +Patch0136: 0136-udev-net_id-support-multi-port-enpo-device-names.patch +Patch0137: 0137-udev-net_id-improve-comments.patch +Patch0138: 0138-udev-restore-udevadm-settle-timeout.patch +Patch0139: 0139-udev-settle-should-return-immediately-when-timeout-i.patch +Patch0140: 0140-udev-Fix-ping-timeout-when-settle-timeout-is-0.patch +Patch0141: 0141-detect-virt-use-proc-device-tree.patch +Patch0142: 0142-ARM-detect-virt-detect-Xen.patch +Patch0143: 0143-ARM-detect-virt-detect-QEMU-KVM.patch +Patch0144: 0144-Persistent-by_path-links-for-ata-devices.patch +Patch0145: 0145-man-document-forwarding-to-syslog-better.patch +Patch0146: 0146-man-fix-typos-in-previous-comimt.patch +Patch0147: 0147-LSB-always-add-network-online.target-to-services-wit.patch +Patch0148: 0148-rules-enable-memory-hotplug.patch +Patch0149: 0149-rules-reload-sysctl-settings-when-the-bridge-module-.patch +Patch0150: 0150-console-getty.service-don-t-start-when-dev-console-i.patch +Patch0151: 0151-resolved-Do-not-add-.busname-dependencies-when-compi.patch +Patch0152: 0152-man-add-journal-remote.conf-5.patch +Patch0153: 0153-mount-don-t-run-quotaon-only-for-network-filesystems.patch +Patch0154: 0154-mount-fix-up-wording-in-the-comment.patch +Patch0155: 0155-udev-net_id-fix-copy-paste-error.patch +Patch0156: 0156-man-don-t-mention-journalctl-dev-sda.patch +Patch0157: 0157-units-move-After-systemd-hwdb-update.service-depende.patch +Patch0158: 0158-units-explicitly-order-systemd-user-sessions.service.patch +Patch0159: 0159-zsh-completion-update-loginctl.patch +Patch0160: 0160-zsh-completion-add-missing-M-completion-for-journalc.patch +Patch0161: 0161-zsh-completion-update-hostnamectl.patch +Patch0162: 0162-shell-completion-systemctl-switch-root-verb.patch +Patch0163: 0163-core-automount-beef-up-error-message.patch +Patch0164: 0164-man-remove-fs-from-rootfsflags.patch +Patch0165: 0165-shared-fix-memleak.patch +Patch0166: 0166-udevd-fix-synchronization-with-settle-when-handling-.patch +Patch0167: 0167-python-systemd-fix-is_socket_inet-to-cope-with-ports.patch +Patch0168: 0168-man-fix-examples-indentation-in-tmpfiles.d-5.patch +Patch0169: 0169-systemctl-avoid-bumping-NOFILE-rlimit-unless-needed.patch +Patch0170: 0170-exit-status-Fix-NOTINSSTALLED-typo.patch +Patch0171: 0171-tmpfiles-there-s-no-systemd-forbid-user-logins.servi.patch +Patch0172: 0172-kmod-setup-load-ip_tables-kmod-at-boot.patch +Patch0173: 0173-util-Fix-assertion-in-split-on-missing.patch +Patch0174: 0174-units-set-KillMode-mixed-for-our-daemons-that-fork-w.patch +Patch0175: 0175-unit-don-t-add-automatic-dependencies-on-device-unit.patch +Patch0176: 0176-update-done-ignore-nanosecond-file-timestamp-compone.patch +Patch0177: 0177-sd-daemon-simplify-sd_pid_notify_with_fds.patch +Patch0178: 0178-fstab-generator-add-x-systemd.requires-and-x-systemd.patch +Patch0179: 0179-core-Fix-assertion-with-empty-Exec-paths.patch +Patch0180: 0180-rules-load-sg-module.patch +Patch0181: 0181-util-add-shell_maybe_quote-call-for-preparing-a-stri.patch +Patch0182: 0182-bus-util-be-more-verbose-if-dbus-job-fails.patch +Patch0183: 0183-notify-fix-badly-backported-help-message.patch +Patch0184: 0184-cryptsetup-craft-a-unique-ID-with-the-source-device.patch +Patch0185: 0185-systemctl-introduce-now-for-enable-disable-and-mask.patch +Patch0186: 0186-udev-also-create-old-sas-paths.patch +Patch0187: 0187-journald-do-not-strip-leading-whitespace-from-messag.patch +Patch0188: 0188-Revert-core-one-step-back-again-for-nspawn-we-actual.patch +Patch0189: 0189-bus-creds-always-set-SD_BUS_CREDS_PID-when-we-set-pi.patch +Patch0190: 0190-sd-bus-do-not-use-per-datagram-auxiliary-information.patch +Patch0191: 0191-sd-bus-store-selinux-context-at-connection-time.patch +Patch0192: 0192-journald-simplify-context-handling.patch +Patch0193: 0193-bash-completion-add-verb-set-property.patch +Patch0194: 0194-sd-bus-don-t-inherit-connection-creds-into-message-c.patch +Patch0195: 0195-udev-fix-crash-in-path_id-builtin.patch +Patch0196: 0196-sysv-generator-test-Fix-assertion.patch +Patch0197: 0197-man-avoid-line-break-in-url.patch +Patch0198: 0198-Add-VARIANT-as-a-standard-value-for-etc-os-release.patch +Patch0199: 0199-Fix-permissions-on-run-systemd-nspawn-locks.patch +Patch0200: 0200-generators-rename-add_-root-usr-_mount-to-add_-sysro.patch +Patch0201: 0201-Generate-systemd-fsck-root.service-in-the-initramfs.patch +Patch0202: 0202-units-fix-typo-in-systemd-resolved.service.patch +Patch0203: 0203-core-don-t-consider-umask-for-SocketMode.patch +Patch0204: 0204-timedate-fix-memory-leak-in-timedated.patch +Patch0205: 0205-coredump-make-sure-we-vacuum-by-default.patch +Patch0206: 0206-tmpfiles-don-t-fail-if-we-cannot-create-a-subvolume-.patch +Patch0207: 0207-resolved-fix-crash-when-shutting-down.patch +Patch0208: 0208-resolved-allow-DnsAnswer-objects-with-no-space-for-R.patch +Patch0209: 0209-id128-add-new-sd_id128_is_null-call.patch +Patch0210: 0210-journalctl-Improve-boot-ID-lookup.patch +Patch0211: 0211-test-hashmap-fix-an-assert.patch +Patch0212: 0212-units-make-sure-systemd-nspawn-.slice-instances-are-.patch +Patch0213: 0213-Revert-journald-audit-exit-gracefully-in-the-case-we.patch +Patch0214: 0214-journald-handle-more-gracefully-when-bind-fails-on-a.patch +Patch0215: 0215-udev-link-config-fix-corruption.patch +Patch0216: 0216-udev-net_id-Only-read-the-first-64-bytes-of-PCI-conf.patch +Patch0217: 0217-shared-generator-correct-path-to-systemd-fsck.patch +Patch0218: 0218-logind-Save-the-user-s-state-when-a-session-enters-S.patch +Patch0219: 0219-small-fix-ru-translation.patch +Patch0220: 0220-kmod-setup-don-t-warn-when-ipv6-can-t-be-loaded.patch +Patch0221: 0221-Partially-revert-ma-setup-simplify.patch +Patch0222: 0222-ima-setup-write-policy-one-line-at-a-time.patch +Patch0223: 0223-ata_id-unbotch-format-specifier.patch +Patch0224: 0224-install-explicitly-return-0-on-success.patch +Patch0225: 0225-systemd.service.xml-document-that-systemd-removes-th.patch +Patch0226: 0226-core-handle-log-target-null-when-calling-systemd-shu.patch +Patch0227: 0227-man-ProtectHome-protects-root-as-well.patch +Patch0228: 0228-timedatectl-trim-non-local-RTC-warning-to-80-chars-w.patch +Patch0229: 0229-escape-fix-exit-code.patch +Patch0230: 0230-man-information-about-available-properties.patch +Patch0231: 0231-journal-in-persistent-mode-create-var-log-journal-wi.patch +Patch0232: 0232-sysv-generator-fix-wrong-Overwriting-existing-symlin.patch +Patch0233: 0233-mount-don-t-claim-a-device-is-gone-from-proc-self-mo.patch +Patch0234: 0234-mount-properly-check-for-mounts-currently-in-proc-se.patch +Patch0235: 0235-units-add-Install-section-to-tmp.mount.patch +Patch0236: 0236-bus-util-add-articles-to-explanation-messages.patch +Patch0237: 0237-bus-util-print-correct-warnings-for-units-that-fail-.patch +Patch0238: 0238-Revert-journald-move-dev-log-socket-to-run.patch +Patch0239: 0239-journald-server-don-t-read-audit-events.patch +Patch0240: 0240-everything-remove-traces-of-user.patch +Patch0241: 0241-selinux-fix-check-for-transient-units.patch +Patch0242: 0242-socket-fix-setsockopt-call.-SOL_SOCKET-changed-to-SO.patch +Patch0243: 0243-selinux-fix-missing-SELinux-unit-access-check.patch +Patch0244: 0244-selinux-always-use-_raw-API-from-libselinux.patch +Patch0245: 0245-udev-net_id-support-predictable-ifnames-on-virtio-bu.patch +Patch0246: 0246-Revert-sysctl.d-default-to-fq_codel-fight-bufferbloa.patch +Patch0247: 0247-loginctl-print-nontrivial-properties-in-logictl-show.patch +Patch0248: 0248-login-fix-label-on-run-nologin.patch +Patch0249: 0249-udev-rules-prandom-character-device-node-permissions.patch +Patch0250: 0250-login-fix-gcc-warning-include-missing-header-file.patch +Patch0251: 0251-shutdown-make-sure-run-nologin-has-correct-label.patch +Patch0252: 0252-sd-event-fix-prepare-priority-queue-comparison-funct.patch +Patch0253: 0253-units-run-ldconfig-also-when-cache-is-unpopulated.patch +Patch0254: 0254-selinux-fix-regression-of-systemctl-subcommands-when.patch +Patch0255: 0255-tmpfiles.d-don-t-clean-SAP-lockfiles-and-logs.patch +Patch0256: 0256-udev-make-naming-for-virtio-devices-opt-in.patch +Patch0257: 0257-tmpfiles.d-don-t-clean-SAP-sockets-either.patch +Patch0258: 0258-run-synchronously-wait-until-the-scope-unit-we-creat.patch +Patch0259: 0259-device-rework-how-we-enter-tentative-state.patch +Patch0260: 0260-core-Do-not-bind-a-mount-unit-to-a-device-if-it-was-.patch +Patch0261: 0261-logind-set-RemoveIPC-no-by-default.patch +Patch0262: 0262-sysv-generator-follow-symlinks-in-etc-rc.d-init.d.patch +Patch0263: 0263-sysv-generator-test-always-log-to-console.patch +Patch0264: 0264-man-RemoveIPC-is-set-to-no-on-rhel.patch +Patch0265: 0265-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch +Patch0266: 0266-test-sysv-generator-Check-for-network-online.target.patch +Patch0267: 0267-makefile-disable-udev-tests.patch +Patch0268: 0268-arm-aarch64-detect-virt-check-dmi.patch +Patch0269: 0269-detect-virt-dmi-look-for-KVM.patch +Patch0270: 0270-Revert-journald-turn-ForwardToSyslog-off-by-default.patch +Patch0271: 0271-terminal-util-when-resetting-terminals-don-t-wait-fo.patch +Patch0272: 0272-basic-terminal-util-introduce-SYSTEMD_COLORS-environ.patch +Patch0273: 0273-ask-password-don-t-abort-when-message-is-missing.patch +Patch0274: 0274-sysv-generator-do-not-join-dependencies-on-one-line-.patch +Patch0275: 0275-udev-fibre-channel-fix-NPIV-support.patch +Patch0276: 0276-ata_id-unreverse-WWN-identifier.patch +Patch0277: 0277-Fixup-WWN-bytes-for-big-endian-systems.patch +Patch0278: 0278-sd-journal-introduce-has_runtime_files-and-has_persi.patch +Patch0279: 0279-journalctl-improve-error-messages-when-the-specified.patch +Patch0280: 0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch +Patch0281: 0281-journalctl-make-journalctl-dev-sda-work.patch +Patch0282: 0282-journalctl-add-match-for-the-current-boot-when-calle.patch +Patch0283: 0283-man-clarify-what-happens-when-journalctl-is-called-w.patch +Patch0284: 0284-core-downgrade-warning-about-duplicate-device-names.patch +Patch0285: 0285-udev-downgrade-a-few-warnings-to-debug-messages.patch +Patch0286: 0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch +Patch0287: 0287-Revert-udev-fibre-channel-fix-NPIV-support.patch +Patch0288: 0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch +Patch0289: 0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch +Patch0290: 0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch +Patch0291: 0291-s390-add-personality-support.patch +Patch0292: 0292-socket_address_listen-do-not-rely-on-errno.patch +Patch0293: 0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch +Patch0294: 0294-journal-fix-error-handling-when-compressing-journal-.patch +Patch0295: 0295-journal-irrelevant-coding-style-fixes.patch +Patch0296: 0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch +Patch0297: 0297-core-look-for-instance-when-processing-template-name.patch +Patch0298: 0298-core-improve-error-message-when-starting-template-wi.patch +Patch0299: 0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch +Patch0300: 0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch +Patch0301: 0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch +Patch0302: 0302-test-execute-add-tests-for-RuntimeDirectory.patch +Patch0303: 0303-core-fix-group-ownership-when-Group-is-set.patch +Patch0304: 0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch +Patch0305: 0305-core-add-new-RandomSec-setting-for-time-units.patch +Patch0306: 0306-core-rename-Random-to-RandomizedDelay.patch +Patch0307: 0307-journal-remote-change-owner-of-var-log-journal-remot.patch +Patch0308: 0308-Add-Seal-option-in-the-configuration-file-for-journa.patch +Patch0309: 0309-tests-fix-make-check-failure.patch +Patch0310: 0310-device-make-sure-to-not-ignore-re-plugged-device.patch +Patch0311: 0311-device-Ensure-we-have-sysfs-path-before-comparing.patch +Patch0312: 0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch +Patch0313: 0313-nspawn-fix-minor-memory-leak.patch +Patch0314: 0314-basic-fix-error-memleak-in-socket-util.patch +Patch0315: 0315-core-fix-memory-leak-in-manager_run_generators.patch +Patch0316: 0316-modules-load-fix-memory-leak.patch +Patch0317: 0317-core-fix-memory-leak-on-failed-preset-all.patch +Patch0318: 0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch +Patch0319: 0319-core-fix-memory-leak-in-transient-units.patch +Patch0320: 0320-bus-fix-leak-in-error-path.patch +Patch0321: 0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch +Patch0322: 0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch +Patch0323: 0323-import-use-the-old-curl-api.patch +Patch0324: 0324-importd-drop-dkr-support.patch +Patch0325: 0325-import-add-support-for-gpg2-for-verifying-imported-i.patch +Patch0326: 0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch +Patch0327: 0327-mount-remove-obsolete-n.patch +Patch0328: 0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch +Patch0329: 0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch +Patch0330: 0330-logind-process-session-inhibitor-fds-at-higher-prior.patch +Patch0331: 0331-Teach-bus_append_unit_property_assignment-about-Dele.patch +Patch0332: 0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch +Patch0333: 0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch +Patch0334: 0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch +Patch0335: 0335-run-make-slice-work-in-conjunction-with-scope.patch +Patch0336: 0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch +Patch0337: 0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch +Patch0338: 0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch +Patch0339: 0339-hwdb-selinuxify-a-bit-3460.patch +Patch0340: 0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch +Patch0341: 0341-systemctl-return-diffrent-error-code-if-service-exis.patch +Patch0342: 0342-systemctl-Replace-init-script-error-codes-with-enum-.patch +Patch0343: 0343-systemctl-rework-systemctl-status-a-bit.patch +Patch0344: 0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch +Patch0345: 0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch +Patch0346: 0346-journal-when-verifying-journal-files-handle-empty-on.patch +Patch0347: 0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch +Patch0348: 0348-journalctl-properly-detect-empty-journal-files.patch +Patch0349: 0349-journal-uppercase-first-character-in-verify-error-me.patch +Patch0350: 0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch +Patch0351: 0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch +Patch0352: 0352-sd-event-expose-the-event-loop-iteration-counter-via.patch +Patch0353: 0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch +Patch0354: 0354-manager-Fixing-a-debug-printf-formatting-mistake.patch +Patch0355: 0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch +Patch0356: 0356-core-accept-time-units-for-time-based-resource-limit.patch +Patch0357: 0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch +Patch0358: 0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch +Patch0359: 0359-core-fix-rlimit-parsing.patch +Patch0360: 0360-core-dump-rlim_cur-too.patch +Patch0361: 0361-install-fix-disable-via-unit-file-path.patch +Patch0362: 0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch +Patch0363: 0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch +Patch0364: 0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch +Patch0365: 0365-core-fix-priority-ordering-in-notify-handling.patch +Patch0366: 0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch +Patch0367: 0367-systemctl-consider-service-running-only-when-it-is-i.patch +Patch0368: 0368-install-do-not-crash-when-processing-empty-masked-un.patch +Patch0369: 0369-Revert-install-fix-disable-via-unit-file-path.patch +Patch0370: 0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch +Patch0371: 0371-tmpfiles-enforce-ordering-when-executing-lines.patch +Patch0372: 0372-Introduce-bus_unit_check_load_state-helper.patch +Patch0373: 0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch +Patch0374: 0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch +Patch0375: 0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch +Patch0376: 0376-fix-gcc-warnings-about-uninitialized-variables.patch +Patch0377: 0377-journalctl-rework-code-that-checks-whether-we-have-a.patch +Patch0378: 0378-journalctl-Improve-boot-ID-lookup.patch +Patch0379: 0379-journalctl-only-have-a-single-exit-path-from-main.patch +Patch0380: 0380-journalctl-free-all-command-line-argument-objects.patch +Patch0381: 0381-journalctl-rename-boot_id_t-to-BootId.patch +Patch0382: 0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch +Patch0383: 0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch +Patch0384: 0384-journald-fix-count-of-object-meta-fields.patch +Patch0385: 0385-journal-cat-return-a-correct-error-not-1.patch +Patch0386: 0386-journalctl-introduce-short-options-for-since-and-unt.patch +Patch0387: 0387-journal-s-Envalid-Invalid.patch +Patch0388: 0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch +Patch0389: 0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch +Patch0390: 0390-journal-normalize-priority-of-logging-sources.patch +Patch0391: 0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch +Patch0392: 0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch +Patch0393: 0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch +Patch0394: 0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch +Patch0395: 0395-units-remove-udev-control-socket-when-systemd-stops-.patch +Patch0396: 0396-logind-don-t-assert-if-the-slice-is-missing.patch +Patch0397: 0397-core-enable-transient-unit-support-for-slice-units.patch +Patch0398: 0398-sd-bus-bump-message-queue-size.patch +Patch0399: 0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch +Patch0400: 0400-rules-add-NVMe-rules-3136.patch +Patch0401: 0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch +Patch0402: 0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch +Patch0403: 0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch +Patch0404: 0404-systemctl-core-ignore-masked-units-in-preset-all.patch +Patch0405: 0405-shared-install-handle-dangling-aliases-as-an-explici.patch +Patch0406: 0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch +Patch0407: 0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch +Patch0408: 0408-If-the-notification-message-length-is-0-ignore-the-m.patch +Patch0409: 0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch +Patch0410: 0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch +Patch0411: 0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch +Patch0412: 0412-pid1-process-zero-length-notification-messages-again.patch +Patch0413: 0413-pid1-more-informative-error-message-for-ignored-noti.patch +Patch0414: 0414-manager-219-needs-u-id-in-log_unit_debug.patch +Patch0415: 0415-virt-add-possibility-to-skip-the-check-for-chroot.patch +Patch0416: 0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch +Patch0417: 0417-core-fix-assertion-check.patch +Patch0418: 0418-tmp.mount.hm4-After-swap.target-3087.patch +Patch0419: 0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch +Patch0420: 0420-Recognise-Lustre-as-a-remote-file-system-4530.patch +Patch0421: 0421-unit-don-t-add-Requires-for-tmp.mount.patch +Patch0422: 0422-core-return-0-from-device_serialize.patch +Patch0423: 0423-mtd_probe-include-stdint.patch +Patch0424: 0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch +Patch0425: 0425-sd-journal-properly-export-has_-persistent-runtime-_.patch +Patch0426: 0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch +Patch0427: 0427-failure-action-generalize-failure-action-to-emergenc.patch +Patch0428: 0428-core-use-emergency_action-for-ctr-alt-del-burst.patch +Patch0429: 0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch +Patch0430: 0430-core-fix-CapabilityBoundingSet-merging.patch +Patch0431: 0431-core-fix-capability-bounding-set-parsing.patch +Patch0432: 0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch +Patch0433: 0433-shared-fix-double-free-in-unmask-5005.patch +Patch0434: 0434-shared-fix-double-free-in-link.patch +Patch0435: 0435-shared-check-strdup-NULL.patch +Patch0436: 0436-core-improve-error-message-when-RefuseManualStart-St.patch +Patch0437: 0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch +Patch0438: 0438-man-document-that-the-automatic-journal-limits-are-c.patch +Patch0439: 0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch +Patch0440: 0440-bash-completion-add-support-for-now-5155.patch +Patch0441: 0441-basic-fix-touch-creating-files-with-07777-mode.patch +Patch0442: 0442-udev-net_id-add-support-for-phys_port_name-attribute.patch +Patch0443: 0443-install-introduce-UnitFileFlags.patch +Patch0444: 0444-shared-systemctl-teach-is-enabled-to-show-installati.patch +Patch0445: 0445-udev-fix-crash-with-invalid-udev.log-priority.patch +Patch0446: 0446-core-make-exec-code-a-bit-more-readable.patch +Patch0447: 0447-core-Private-Protect-options-with-RootDirectory.patch +Patch0448: 0448-core-if-the-start-command-vanishes-during-runtime-do.patch +Patch0449: 0449-systemctl-make-sure-that-now-is-carried-out-5209.patch +Patch0450: 0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch +Patch0451: 0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch +Patch0452: 0452-automount-add-expire-support.patch +Patch0453: 0453-fstab-generator-fix-memleak.patch +Patch0454: 0454-remove-bus-proxyd.patch +Patch0455: 0455-execute-Add-new-PassEnvironment-directive.patch +Patch0456: 0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch +Patch0457: 0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch +Patch0458: 0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch +Patch0459: 0459-Add-microphone-mute-keymap-for-Dell-Precision.patch +Patch0460: 0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch +Patch0461: 0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch +Patch0462: 0462-core-port-config_parse_bounding_set-to-extract_first.patch +Patch0463: 0463-core-simplify-parsing-of-capability-bounding-set-set.patch +Patch0464: 0464-test-add-test-for-capability-bounding-set-parsing.patch +Patch0465: 0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch +Patch0466: 0466-capabilities-added-support-for-ambient-capabilities.patch +Patch0467: 0467-man-add-AmbientCapabilities-entry.patch +Patch0468: 0468-test-capability-rebase-to-upstream-version.patch +Patch0469: 0469-namespace-don-t-fail-on-masked-mounts.patch +Patch0470: 0470-sysv-generator-Provides-network-should-also-pull-net.patch +Patch0471: 0471-Install-correctly-report-symlink-creations.patch +Patch0472: 0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch +Patch0473: 0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch +Patch0474: 0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch +Patch0475: 0475-core-add-support-for-the-pids-cgroup-controller.patch +Patch0476: 0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch +Patch0477: 0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch +Patch0478: 0478-core-support-percentage-specifications-on-TasksMax.patch +Patch0479: 0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch +Patch0480: 0480-core-when-propagating-restart-requests-due-to-deps-d.patch +Patch0481: 0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch +Patch0482: 0482-tests-set-tasks_max-to-infinity.patch +Patch0483: 0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch +Patch0484: 0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch +Patch0485: 0485-load-fragment-don-t-print-error-about-incorrect-synt.patch +Patch0486: 0486-core-manager-add-some-missing-dbus-properties.patch +Patch0487: 0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch +Patch0488: 0488-fstab-generator-remove-bogus-condition.patch +Patch0489: 0489-readahead-collect-don-t-print-warning-message-when-h.patch +Patch0490: 0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch +Patch0491: 0491-tmpfiles-also-set-acls-on-var-log-journal.patch +Patch0492: 0492-tmpfiles-set-acls-on-system.journal-explicitly.patch +Patch0493: 0493-sysctl-configure-kernel-parameters-in-the-order-they.patch +Patch0494: 0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch +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-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);} + +BuildRequires: libcap-devel +BuildRequires: tcp_wrappers-devel +BuildRequires: pam-devel +BuildRequires: libselinux-devel +BuildRequires: audit-libs-devel +BuildRequires: cryptsetup-devel +BuildRequires: dbus-devel +BuildRequires: libacl-devel +BuildRequires: pciutils-devel +BuildRequires: glib2-devel +BuildRequires: gobject-introspection-devel +BuildRequires: libblkid-devel +BuildRequires: xz-devel +BuildRequires: zlib-devel +BuildRequires: bzip2-devel +BuildRequires: lz4-devel +BuildRequires: libidn-devel +BuildRequires: libcurl-devel +BuildRequires: kmod-devel +BuildRequires: elfutils-devel +BuildRequires: libgcrypt-devel +BuildRequires: gnutls-devel +BuildRequires: qrencode-devel +BuildRequires: libmicrohttpd-devel +BuildRequires: libxslt +BuildRequires: docbook-style-xsl +BuildRequires: pkgconfig +BuildRequires: intltool +BuildRequires: gperf +BuildRequires: gawk +BuildRequires: gtk-doc +BuildRequires: python2-devel +BuildRequires: python-lxml +BuildRequires: automake +BuildRequires: autoconf +BuildRequires: libtool +BuildRequires: git +BuildRequires: libmount-devel + +Requires(post): coreutils +Requires(post): gawk +Requires(post): sed +Requires(post): acl +Requires(pre): coreutils +Requires(pre): /usr/bin/getent +Requires(pre): /usr/sbin/groupadd +Requires: dbus +Requires: %{name}-libs = %{version}-%{release} +Requires: kmod >= 18-4 +Requires: redhat-release >= 7.0 +Requires: diffutils + +Provides: /bin/systemctl +Provides: /sbin/shutdown +Provides: syslog +Provides: systemd-units = %{version}-%{release} + +Conflicts: dracut < 033-243 +Conflicts: initscripts < 9.49.28-1 + +#Obsolete packages when we are migrating from rhel6 +Provides: udev = %{version} +Obsoletes: udev < 183 +Obsoletes: system-setup-keyboard < 0.9 +Provides: system-setup-keyboard = 0.9 +Obsoletes: nss-myhostname < 0.4 +Provides: nss-myhostname = 0.4 +Obsoletes: upstart < 1.2-3 +Obsoletes: upstart-sysvinit < 1.2-3 +Conflicts: upstart-sysvinit +Obsoletes: hal +Obsoletes: ConsoleKit + +%description +systemd is a system and service manager for Linux, compatible with +SysV and LSB init scripts. systemd provides aggressive parallelization +capabilities, uses socket and D-Bus activation for starting services, +offers on-demand starting of daemons, keeps track of processes using +Linux cgroups, supports snapshotting and restoring of the system +state, maintains mount and automount points and implements an +elaborate transactional dependency-based service control logic. It can +work as a drop-in replacement for sysvinit. + +%package libs +Summary: systemd libraries +License: LGPLv2+ and MIT +Obsoletes: libudev < 183 + +%description libs +Libraries for systemd and udev, as well as the systemd PAM module. + +%package devel +Summary: Development headers for systemd +License: LGPLv2+ and MIT +Requires: %{name} = %{version}-%{release} +Provides: libudev-devel = %{version} +Obsoletes: libudev-devel < 183 +Requires: %{name}-libs = %{version}-%{release} + +%description devel +Development headers and auxiliary files for developing applications for systemd. + +%package sysv +Summary: SysV tools for systemd +License: LGPLv2+ +Requires: %{name} = %{version}-%{release} + +%description sysv +SysV compatibility tools for systemd + +%package python +Summary: Python 2 bindings for systemd +License: LGPLv2+ +Requires: %{name} = %{version}-%{release} +Requires: %{name}-libs = %{version}-%{release} + +%description python +This package contains bindings which allow Python 2 programs to use +systemd APIs + +%package -n libgudev1 +Summary: Libraries for adding libudev support to applications that use glib +Conflicts: filesystem < 3 +License: LGPLv2+ +Requires: %{name}-libs = %{version}-%{release} +Requires: glib2 >= 2.42 + +%description -n libgudev1 +This package contains the libraries that make it easier to use libudev +functionality from applications that use glib. + +%package -n libgudev1-devel +Summary: Header files for adding libudev support to applications that use glib +Requires: libgudev1 = %{version}-%{release} +License: LGPLv2+ + +%description -n libgudev1-devel +This package contains the header and pkg-config files for developing +glib-based applications using libudev functionality. + +%package journal-gateway +Summary: Gateway for serving journal events over the network using HTTP +Requires: %{name} = %{version}-%{release} +License: LGPLv2+ +Requires(pre): /usr/bin/getent +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%description journal-gateway +systemd-journal-gatewayd serves journal events over the network using HTTP. + +%package networkd +Summary: System service that manages networks. +Requires: %{name} = %{version}-%{release} +License: LGPLv2+ +Requires(pre): /usr/bin/getent +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%description networkd +systemd-networkd is a system service that manages networks. +It detects and configures network devices as they appear, as well as creating virtual network devices. + +%package resolved +Summary: Network Name Resolution manager. +Requires: %{name} = %{version}-%{release} +License: LGPLv2+ +Requires(pre): /usr/bin/getent +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%description resolved +systemd-resolved is a system service that manages network name resolution. +It implements a caching DNS stub resolver and an LLMNR resolver and responder. + +%prep +%setup -q + +%if %{num_patches} +git init +git config user.email "systemd-maint@redhat.com" +git config user.name "systemd team" +git add . +git commit -a -q -m "%{version} baseline." + +# Apply all the patches. +git am %{patches} +%endif + +%build +./autogen.sh + +CONFIGURE_OPTS=( + --libexecdir=%{_prefix}/lib + --with-sysvinit-path=/etc/rc.d/init.d + --with-rc-local-script-path-start=/etc/rc.d/rc.local + --disable-timesyncd + --disable-kdbus + --disable-terminal + --enable-gtk-doc + --enable-compat-libs + --disable-sysusers + --disable-ldconfig + --enable-lz4 +%ifarch s390 s390x ppc %{power64} aarch64 + --disable-lto +%endif +) + +%configure "${CONFIGURE_OPTS[@]}" +make %{?_smp_mflags} GCC_COLORS="" V=1 + +%install +%make_install + +find %{buildroot} \( -name '*.a' -o -name '*.la' \) -delete +sed -i 's/L+/#/' %{buildroot}/usr/lib/tmpfiles.d/etc.conf + +rm -f %{buildroot}%{_datadir}/polkit-1/actions/org.freedesktop.*.policy +install -m 0644 %{SOURCE7} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE8} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE9} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE10} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE11} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE12} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE13} %{buildroot}%{_datadir}/polkit-1/actions/ + +# udev links +mkdir -p %{buildroot}/%{_sbindir} +ln -sf ../bin/udevadm %{buildroot}%{_sbindir}/udevadm + +# Create SysV compatibility symlinks. systemctl/systemd are smart +# enough to detect in which way they are called. +ln -s ../lib/systemd/systemd %{buildroot}%{_sbindir}/init +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/reboot +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/halt +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/poweroff +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/shutdown +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/telinit +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/runlevel + +# legacy links +ln -s loginctl %{buildroot}%{_bindir}/systemd-loginctl +ln -s coredumpctl %{buildroot}%{_bindir}/systemd-coredumpctl + +# We create all wants links manually at installation time to make sure +# they are not owned and hence overriden by rpm after the user deleted +# them. +rm -r %{buildroot}%{_sysconfdir}/systemd/system/*.target.wants + +# Make sure the ghost-ing below works +touch %{buildroot}%{_sysconfdir}/systemd/system/runlevel2.target +touch %{buildroot}%{_sysconfdir}/systemd/system/runlevel3.target +touch %{buildroot}%{_sysconfdir}/systemd/system/runlevel4.target +touch %{buildroot}%{_sysconfdir}/systemd/system/runlevel5.target + +# Make sure these directories are properly owned +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/basic.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/default.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/dbus.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/syslog.target.wants + +# Temporary workaround for #1002806 +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/poweroff.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/rescue.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/multi-user.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/graphical.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/reboot.target.wants +ln -s ../systemd-update-utmp-runlevel.service %{buildroot}%{_prefix}/lib/systemd/system/poweroff.target.wants/ +ln -s ../systemd-update-utmp-runlevel.service %{buildroot}%{_prefix}/lib/systemd/system/rescue.target.wants/ +ln -s ../systemd-update-utmp-runlevel.service %{buildroot}%{_prefix}/lib/systemd/system/multi-user.target.wants/ +ln -s ../systemd-update-utmp-runlevel.service %{buildroot}%{_prefix}/lib/systemd/system/graphical.target.wants/ +ln -s ../systemd-update-utmp-runlevel.service %{buildroot}%{_prefix}/lib/systemd/system/reboot.target.wants/ + +mkdir -p %{buildroot}%{_localstatedir}/{run,log}/ +touch %{buildroot}%{_localstatedir}/run/utmp +touch %{buildroot}%{_localstatedir}/log/{w,b}tmp + +# Make sure the user generators dir exists too +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-generators +mkdir -p %{buildroot}%{_prefix}/lib/systemd/user-generators + +# Create new-style configuration files so that we can ghost-own them +touch %{buildroot}%{_sysconfdir}/hostname +touch %{buildroot}%{_sysconfdir}/vconsole.conf +touch %{buildroot}%{_sysconfdir}/locale.conf +touch %{buildroot}%{_sysconfdir}/machine-id +touch %{buildroot}%{_sysconfdir}/machine-info +touch %{buildroot}%{_sysconfdir}/localtime +mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d +touch %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/00-keyboard.conf + +# Install default preset policy +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-preset/ +mkdir -p %{buildroot}%{_prefix}/lib/systemd/user-preset/ +install -m 0644 %{SOURCE1} %{buildroot}%{_prefix}/lib/systemd/system-preset/ + +# Make sure the shutdown/sleep drop-in dirs exist +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-shutdown/ +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-sleep/ + +# Make sure the NTP units dir exists +mkdir -p %{buildroot}%{_prefix}/lib/systemd/ntp-units.d/ + +# Make sure directories in /var exist +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 +touch %{buildroot}%{_localstatedir}/lib/systemd/clock + + +# Install SysV conversion tool for systemd +install -m 0755 %{SOURCE3} %{buildroot}%{_bindir}/ + +# Install yum protection fragment +mkdir -p %{buildroot}%{_sysconfdir}/yum/protected.d/ +install -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/yum/protected.d/systemd.conf + +# Install rc.local +mkdir -p %{buildroot}%{_sysconfdir}/rc.d/ +install -m 0644 %{SOURCE4} %{buildroot}%{_sysconfdir}/rc.d/rc.local +ln -s rc.d/rc.local %{buildroot}%{_sysconfdir}/rc.local + +# Install rsyslog fragment +mkdir -p %{buildroot}%{_sysconfdir}/rsyslog.d/ +install -m 0644 %{SOURCE6} %{buildroot}%{_sysconfdir}/rsyslog.d/ + +# Delete LICENSE files from _docdir (we'll get them in as %%license) +rm -rf %{buildroot}%{_docdir}/LICENSE* + +# Install script and udev rule for adding phys_port_name for mlxsw and rocker drivers +# And put them in dracut +mkdir -p %{buildroot}%{_prefix}/lib/udev/rules.d +install -m 0755 %{SOURCE14} %{buildroot}%{_prefix}/lib/udev/ +install -m 0644 %{SOURCE15} %{buildroot}%{_prefix}/lib/udev/rules.d/ +mkdir -p %{buildroot}%{_prefix}/lib/dracut/dracut.conf.d +install -m 0644 %{SOURCE16} %{buildroot}%{_prefix}/lib/dracut/dracut.conf.d/ + +%find_lang %{name} + +# To avoid making life hard for Rawhide-using developers, don't package the +# kernel.core_pattern setting until systemd-coredump is a part of an actual +# systemd release and it's made clear how to get the core dumps out of the +# journal. +rm -f %{buildroot}%{_prefix}/lib/sysctl.d/50-coredump.conf + +# For now remove /var/log/README since we are not enabling persistant +# logging yet. +rm -f %{buildroot}%{_localstatedir}/log/README + +# No tmp-on-tmpfs by default in RHEL7. bz#876122 +rm -f %{buildroot}%{_prefix}/lib/systemd/system/local-fs.target.wants/tmp.mount + +# No gpt-auto-generator in RHEL7 +rm -f %{buildroot}%{_prefix}/lib/systemd/system-generators/systemd-gpt-auto-generator + +# 50-bridge.conf rules are in intscripts +rm -f %{buildroot}%{_prefix}/lib/sysctl.d/50-bridge.conf + +# no networkd in rhel7 +rm -f %{buildroot}%{_prefix}/lib/systemd/network/* + +# no sysusers in rhel7 +rm -f %{buildroot}%{_mandir}/man5/sysusers.d.5.gz +rm -f %{buildroot}%{_mandir}/man8/systemd-sysusers.* + +install -m 0644 %{SOURCE5} $RPM_BUILD_ROOT/%{_udevrulesdir}/ + +%pre +getent group cdrom >/dev/null 2>&1 || groupadd -r -g 11 cdrom >/dev/null 2>&1 || : +getent group utmp >/dev/null 2>&1 || groupadd -r -g 22 utmp >/dev/null 2>&1 || : +getent group tape >/dev/null 2>&1 || groupadd -r -g 33 tape >/dev/null 2>&1 || : +getent group dialout >/dev/null 2>&1 || groupadd -r -g 18 dialout >/dev/null 2>&1 || : +getent group input >/dev/null 2>&1 || groupadd -r input >/dev/null 2>&1 || : +getent group floppy >/dev/null 2>&1 || groupadd -r -g 19 floppy >/dev/null 2>&1 || : +getent group systemd-journal >/dev/null 2>&1 || groupadd -r -g 190 systemd-journal 2>&1 || : +getent group systemd-network >/dev/null 2>&1 || groupadd -r -g 192 systemd-network 2>&1 || : +getent passwd systemd-network >/dev/null 2>&1 || useradd -r -u 192 -l -g systemd-network -d / -s /sbin/nologin -c "systemd Network Management" systemd-network >/dev/null 2>&1 || : + +systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service >/dev/null 2>&1 || : + +%post +systemd-machine-id-setup >/dev/null 2>&1 || : +/usr/lib/systemd/systemd-random-seed save >/dev/null 2>&1 || : +systemctl daemon-reexec >/dev/null 2>&1 || : +systemctl start systemd-udevd.service >/dev/null 2>&1 || : +udevadm hwdb --update >/dev/null 2>&1 || : +journalctl --update-catalog >/dev/null 2>&1 || : +systemd-tmpfiles --create >/dev/null 2>&1 || : + +# Make sure new journal files will be owned by the "systemd-journal" group +chgrp systemd-journal /run/log/journal/ /run/log/journal/`cat /etc/machine-id 2> /dev/null` /var/log/journal/ /var/log/journal/`cat /etc/machine-id 2> /dev/null` >/dev/null 2>&1 || : +chmod g+s /run/log/journal/ /run/log/journal/`cat /etc/machine-id 2> /dev/null` /var/log/journal/ /var/log/journal/`cat /etc/machine-id 2> /dev/null` >/dev/null 2>&1 || : + +if [ $1 -eq 1 ] ; then + # Try to read default runlevel from the old inittab if it exists + runlevel=$(awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab 2> /dev/null) + if [ -z "$runlevel" ] ; then + target="/usr/lib/systemd/system/graphical.target" + else + target="/usr/lib/systemd/system/runlevel$runlevel.target" + fi + + # And symlink what we found to the new-style default.target + ln -sf "$target" /etc/systemd/system/default.target >/dev/null 2>&1 || : + + # Services we install by default, and which are controlled by presets. + systemctl preset \ + remote-fs.target \ + getty@.service \ + serial-getty@.service \ + console-getty.service \ + console-shell.service \ + debug-shell.service \ + systemd-readahead-replay.service \ + systemd-readahead-collect.service \ + >/dev/null 2>&1 || : +else + # This systemd service does not exist anymore, we now do it + # internally in PID 1 + rm -f /etc/systemd/system/sysinit.target.wants/hwclock-load.service >/dev/null 2>&1 || : + + # This systemd target does not exist anymore. It's been replaced + # by ntp-units.d. + rm -f /etc/systemd/system/multi-user.target.wants/systemd-timedated-ntp.target >/dev/null 2>&1 || : + + # Enable the units recorded by %%pretrans + if [ -e /var/lib/rpm-state/systemd/ntp-units ] ; then + while read service; do + systemctl enable "$service" >/dev/null 2>&1 || : + done < /var/lib/rpm-state/systemd/ntp-units + rm -r /var/lib/rpm-state/systemd/ntp-units >/dev/null 2>&1 || : + fi +fi + +# Move old stuff around in /var/lib +mv %{_localstatedir}/lib/random-seed %{_localstatedir}/lib/systemd/random-seed >/dev/null 2>&1 || : +mv %{_localstatedir}/lib/backlight %{_localstatedir}/lib/systemd/backlight >/dev/null 2>&1 || : + +# Migrate /etc/sysconfig/clock +if [ ! -L /etc/localtime -a -e /etc/sysconfig/clock ] ; then + . /etc/sysconfig/clock >/dev/null 2>&1 || : + if [ -n "$ZONE" -a -e "/usr/share/zoneinfo/$ZONE" ] ; then + ln -sf "../usr/share/zoneinfo/$ZONE" /etc/localtime >/dev/null 2>&1 || : + fi +fi +rm -f /etc/sysconfig/clock >/dev/null 2>&1 || : + +# Migrate /etc/sysconfig/i18n +if [ -e /etc/sysconfig/i18n -a ! -e /etc/locale.conf ]; then + unset LANG + unset LC_CTYPE + unset LC_NUMERIC + unset LC_TIME + unset LC_COLLATE + unset LC_MONETARY + unset LC_MESSAGES + unset LC_PAPER + unset LC_NAME + unset LC_ADDRESS + unset LC_TELEPHONE + unset LC_MEASUREMENT + unset LC_IDENTIFICATION + . /etc/sysconfig/i18n >/dev/null 2>&1 || : + [ -n "$LANG" ] && echo LANG=$LANG > /etc/locale.conf 2>&1 || : + [ -n "$LC_CTYPE" ] && echo LC_CTYPE=$LC_CTYPE >> /etc/locale.conf 2>&1 || : + [ -n "$LC_NUMERIC" ] && echo LC_NUMERIC=$LC_NUMERIC >> /etc/locale.conf 2>&1 || : + [ -n "$LC_TIME" ] && echo LC_TIME=$LC_TIME >> /etc/locale.conf 2>&1 || : + [ -n "$LC_COLLATE" ] && echo LC_COLLATE=$LC_COLLATE >> /etc/locale.conf 2>&1 || : + [ -n "$LC_MONETARY" ] && echo LC_MONETARY=$LC_MONETARY >> /etc/locale.conf 2>&1 || : + [ -n "$LC_MESSAGES" ] && echo LC_MESSAGES=$LC_MESSAGES >> /etc/locale.conf 2>&1 || : + [ -n "$LC_PAPER" ] && echo LC_PAPER=$LC_PAPER >> /etc/locale.conf 2>&1 || : + [ -n "$LC_NAME" ] && echo LC_NAME=$LC_NAME >> /etc/locale.conf 2>&1 || : + [ -n "$LC_ADDRESS" ] && echo LC_ADDRESS=$LC_ADDRESS >> /etc/locale.conf 2>&1 || : + [ -n "$LC_TELEPHONE" ] && echo LC_TELEPHONE=$LC_TELEPHONE >> /etc/locale.conf 2>&1 || : + [ -n "$LC_MEASUREMENT" ] && echo LC_MEASUREMENT=$LC_MEASUREMENT >> /etc/locale.conf 2>&1 || : + [ -n "$LC_IDENTIFICATION" ] && echo LC_IDENTIFICATION=$LC_IDENTIFICATION >> /etc/locale.conf 2>&1 || : +fi + +# Migrate /etc/sysconfig/keyboard +if [ -e /etc/sysconfig/keyboard -a ! -e /etc/vconsole.conf ]; then + unset SYSFONT + unset SYSFONTACM + unset UNIMAP + unset KEYMAP + [ -e /etc/sysconfig/i18n ] && . /etc/sysconfig/i18n >/dev/null 2>&1 || : + . /etc/sysconfig/keyboard >/dev/null 2>&1 || : + [ -n "$SYSFONT" ] && echo FONT=$SYSFONT > /etc/vconsole.conf 2>&1 || : + [ -n "$SYSFONTACM" ] && echo FONT_MAP=$SYSFONTACM >> /etc/vconsole.conf 2>&1 || : + [ -n "$UNIMAP" ] && echo FONT_UNIMAP=$UNIMAP >> /etc/vconsole.conf 2>&1 || : + [ -n "$KEYTABLE" ] && echo KEYMAP=$KEYTABLE >> /etc/vconsole.conf 2>&1 || : +fi +rm -f /etc/sysconfig/i18n >/dev/null 2>&1 || : +rm -f /etc/sysconfig/keyboard >/dev/null 2>&1 || : + +# Migrate HOSTNAME= from /etc/sysconfig/network +if [ -e /etc/sysconfig/network -a ! -e /etc/hostname ]; then + unset HOSTNAME + . /etc/sysconfig/network >/dev/null 2>&1 || : + [ -n "$HOSTNAME" ] && echo $HOSTNAME > /etc/hostname 2>&1 || : +fi +sed -i '/^HOSTNAME=/d' /etc/sysconfig/network >/dev/null 2>&1 || : + +# Migrate the old systemd-setup-keyboard X11 configuration fragment +if [ ! -e /etc/X11/xorg.conf.d/00-keyboard.conf ] ; then + mv /etc/X11/xorg.conf.d/00-system-setup-keyboard.conf /etc/X11/xorg.conf.d/00-keyboard.conf >/dev/null 2>&1 || : +else + rm -f /etc/X11/xorg.conf.d/00-system-setup-keyboard.conf >/dev/null 2>&1 || : +fi + +# sed-fu to add myhostname to the hosts line of /etc/nsswitch.conf +# Only do that when installing, not when updating. +if [ $1 -eq 1 -a -f /etc/nsswitch.conf ] ; then + sed -i.bak -e ' +/^hosts:/ !b +/\/ b +s/[[:blank:]]*$/ myhostname/ +' /etc/nsswitch.conf >/dev/null 2>&1 || : +fi + +%posttrans +# Convert old /etc/sysconfig/desktop settings +preferred= +if [ -f /etc/sysconfig/desktop ]; then + . /etc/sysconfig/desktop + if [ "$DISPLAYMANAGER" = GNOME ]; then + preferred=gdm + elif [ "$DISPLAYMANAGER" = KDE ]; then + preferred=kdm + elif [ "$DISPLAYMANAGER" = WDM ]; then + preferred=wdm + elif [ "$DISPLAYMANAGER" = XDM ]; then + preferred=xdm + elif [ -n "$DISPLAYMANAGER" ]; then + preferred=${DISPLAYMANAGER##*/} + fi +fi +if [ -z "$preferred" ]; then + if [ -x /usr/sbin/gdm ]; then + preferred=gdm + elif [ -x /usr/bin/kdm ]; then + preferred=kdm + fi +fi +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 + +%postun +if [ $1 -ge 1 ] ; then + systemctl daemon-reload > /dev/null 2>&1 || : +fi + +%preun +if [ $1 -eq 0 ] ; then + systemctl disable \ + remote-fs.target \ + getty@.service \ + serial-getty@.service \ + console-getty.service \ + console-shell.service \ + debug-shell.service \ + systemd-readahead-replay.service \ + systemd-readahead-collect.service \ + >/dev/null 2>&1 || : + + rm -f /etc/systemd/system/default.target >/dev/null 2>&1 || : + + if [ -f /etc/nsswitch.conf ] ; then + sed -i.bak -e ' +/^hosts:/ !b +s/[[:blank:]]\+myhostname\>// +' /etc/nsswitch.conf >/dev/null 2>&1 || : + fi +fi + +%post libs -p /sbin/ldconfig +%postun libs -p /sbin/ldconfig + +%post -n libgudev1 -p /sbin/ldconfig +%postun -n libgudev1 -p /sbin/ldconfig + +%pre journal-gateway +getent group systemd-journal-gateway >/dev/null 2>&1 || groupadd -r -g 191 systemd-journal-gateway 2>&1 || : +getent passwd systemd-journal-gateway >/dev/null 2>&1 || useradd -r -l -u 191 -g systemd-journal-gateway -d %{_localstatedir}/log/journal -s /sbin/nologin -c "Journal Gateway" systemd-journal-gateway >/dev/null 2>&1 || : +getent group systemd-journal-remote >/dev/null 2>&1 || groupadd -r systemd-journal-remote 2>&1 || : +getent passwd systemd-journal-remote >/dev/null 2>&1 || useradd -r -l -g systemd-journal-remote -d /%{_localstatedir}/log/journal/remote -s /sbin/nologin -c "Journal Remote" systemd-journal-remote >/dev/null 2>&1 || : +getent group systemd-journal >/dev/null 2>&1 || groupadd -r -g 190 systemd-journal 2>&1 || : +getent group systemd-journal-upload >/dev/null 2>&1 || groupadd -r systemd-journal-upload 2>&1 || : +getent passwd systemd-journal-upload >/dev/null 2>&1 || useradd -r -l -g systemd-journal-upload -G systemd-journal -d /%{_localstatedir}/log/journal/upload -s /sbin/nologin -c "Journal Upload" systemd-journal-upload >/dev/null 2>&1 || : + +%post journal-gateway +%systemd_post systemd-journal-gatewayd.socket systemd-journal-gatewayd.service +%systemd_post systemd-journal-remote.socket systemd-journal-remote.service +%systemd_post systemd-journal-upload.service + +%preun journal-gateway +%systemd_preun systemd-journal-gatewayd.socket systemd-journal-gatewayd.service +%systemd_preun systemd-journal-remote.socket systemd-journal-remote.service +%systemd_preun systemd-journal-upload.service + +%postun journal-gateway +%systemd_postun_with_restart systemd-journal-gatewayd.service +%systemd_postun_with_restart systemd-journal-remote.service +%systemd_postun_with_restart systemd-journal-upload.service + +%post networkd +%systemd_post systemd-networkd.service systemd-networkd-wait-online.service + +%preun networkd +%systemd_preun systemd-networkd.service systemd-networkd-wait-online.service + +%postun networkd +%systemd_postun_with_restart systemd-networkd.service systemd-networkd-wait-online.service + +%pre resolved +getent group systemd-resolve >/dev/null 2>&1 || groupadd -r -g 193 systemd-resolve 2>&1 || : +getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -u 193 -l -g systemd-resolve -d / -s /sbin/nologin -c "systemd Resolver" systemd-resolve >/dev/null 2>&1 || : + +%post resolved +%systemd_post systemd-resolved.service + +%preun resolved +%systemd_preun systemd-resolved.service + +%postun resolved +%systemd_postun_with_restart systemd-resolved.service + +%triggerin -- systemd < 219-21 +. /etc/sysconfig/network-scripts/network-functions + +RULES_FILE="/etc/udev/rules.d/90-eno-fix.rules" +DRACUT_CONFIG="/etc/dracut.conf.d/90-eno-fix.conf" + +NEED_REBUILD= +WROTE_MSG= + +# systemd-219-30 refuses onboard indexes of network card bigger then 16383 +# and this changes the name of the device. If we are updating on such machine +# let's keep the old name with udev rule +for i in /sys/class/net/eno* ; do + DEVICE=${i##*/} + + [[ "$DEVICE" =~ eno[0-9]+(d[0-9]+)?$ ]] || continue + [ "$(echo $DEVICE | sed -e 's/eno\([0-9]\+\).*/\1/')" -lt "16383" ] && continue + + HWADDR=$(get_hwaddr $DEVICE | tr '[:upper:]' '[:lower:]') + [ -z "$HWADDR" ] && continue + + if [ -z "$WROTE_MSG" ]; then + echo "# This file was automatically generated on systemd update" > "$RULES_FILE" + WROTE_MSG=yes + fi + + echo "SUBSYSTEM==\"net\", ACTION==\"add\", DRIVERS==\"?*\", ATTR{address}==\"$HWADDR\", NAME=\"$DEVICE\"" >> "$RULES_FILE" + NEED_REBUILD=yes +done + +if [ -n "$NEED_REBUILD" ]; then + echo "install_items+=\" $RULES_FILE \"" > "$DRACUT_CONFIG" + dracut -f +fi + +%files -f %{name}.lang +%doc %{_docdir}/systemd +%{!?_licensedir:%global license %%doc} +%license LICENSE.GPL2 LICENSE.LGPL2.1 LICENSE.MIT +%dir %{_sysconfdir}/systemd +%dir %{_sysconfdir}/systemd/system +%dir %{_sysconfdir}/systemd/user +%dir %{_sysconfdir}/tmpfiles.d +%dir %{_sysconfdir}/sysctl.d +%dir %{_sysconfdir}/modules-load.d +%dir %{_sysconfdir}/binfmt.d +%dir %{_sysconfdir}/udev +%dir %{_sysconfdir}/udev/rules.d +%dir %{_prefix}/lib/systemd +%{_prefix}/lib/systemd/system-generators +%{_prefix}/lib/systemd/user-generators +%dir %{_prefix}/lib/systemd/system-preset +%dir %{_prefix}/lib/systemd/user-preset +%dir %{_prefix}/lib/systemd/system-shutdown +%dir %{_prefix}/lib/systemd/system-sleep +%dir %{_prefix}/lib/systemd/catalog +%dir %{_prefix}/lib/systemd/ntp-units.d +%dir %{_prefix}/lib/tmpfiles.d +%dir %{_prefix}/lib/sysctl.d +%dir %{_prefix}/lib/modules-load.d +%dir %{_prefix}/lib/binfmt.d +%dir %{_prefix}/lib/kernel +%dir %{_prefix}/lib/kernel/install.d +%dir %{_datadir}/systemd +%dir %{_datadir}/pkgconfig +%dir %{_datadir}/zsh +%dir %{_datadir}/zsh/site-functions +%ghost %dir %{_localstatedir}/log/journal +%dir %{_localstatedir}/lib/systemd +%dir %{_localstatedir}/lib/systemd/catalog +%ghost %dir %{_localstatedir}/lib/systemd/coredump +%ghost %dir %{_localstatedir}/lib/systemd/backlight +%ghost %dir %{_localstatedir}/lib/systemd/rfkill +%ghost %{_localstatedir}/lib/systemd/random-seed +%ghost %{_localstatedir}/lib/systemd/clock +%ghost %{_localstatedir}/lib/systemd/catalog/database +%ghost %attr(0664,root,utmp) %{_localstatedir}/run/utmp +%ghost %attr(0664,root,utmp) %{_localstatedir}/log/wtmp +%ghost %attr(0600,root,utmp) %{_localstatedir}/log/btmp +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.systemd1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.hostname1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.login1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.locale1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.timedate1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.machine1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.import1.conf +%config(noreplace) %{_sysconfdir}/systemd/system.conf +%config(noreplace) %{_sysconfdir}/systemd/user.conf +%config(noreplace) %{_sysconfdir}/systemd/logind.conf +%config(noreplace) %{_sysconfdir}/systemd/journald.conf +%config(noreplace) %{_sysconfdir}/systemd/bootchart.conf +%config(noreplace) %{_sysconfdir}/systemd/coredump.conf +%config(noreplace) %{_sysconfdir}/udev/udev.conf +%config(noreplace) %{_sysconfdir}/rsyslog.d/listen.conf +%config(noreplace) %{_sysconfdir}/yum/protected.d/systemd.conf +%config(noreplace) %{_sysconfdir}/pam.d/systemd-user +%ghost %{_sysconfdir}/udev/hwdb.bin +%{_rpmconfigdir}/macros.d/macros.systemd +%{_sysconfdir}/xdg/systemd +%{_sysconfdir}/rc.d/init.d/README +%ghost %config(noreplace) %{_sysconfdir}/hostname +%ghost %config(noreplace) %{_sysconfdir}/localtime +%ghost %config(noreplace) %{_sysconfdir}/vconsole.conf +%ghost %config(noreplace) %{_sysconfdir}/locale.conf +%ghost %config(noreplace) %{_sysconfdir}/machine-id +%ghost %config(noreplace) %{_sysconfdir}/machine-info +%dir %{_sysconfdir}/X11/xorg.conf.d +%ghost %config(noreplace) %{_sysconfdir}/X11/xorg.conf.d/00-keyboard.conf +%{_bindir}/systemctl +%{_bindir}/systemd-notify +%{_bindir}/systemd-analyze +%{_bindir}/systemd-escape +%{_bindir}/systemd-ask-password +%{_bindir}/systemd-tty-ask-password-agent +%{_bindir}/systemd-machine-id-setup +%{_bindir}/loginctl +%{_bindir}/systemd-loginctl +%{_bindir}/journalctl +%{_bindir}/machinectl +%{_bindir}/busctl +%{_bindir}/coredumpctl +%{_bindir}/systemd-coredumpctl +%{_bindir}/systemd-tmpfiles +%{_bindir}/systemd-nspawn +%{_bindir}/systemd-stdio-bridge +%{_bindir}/systemd-cat +%{_bindir}/systemd-cgls +%{_bindir}/systemd-cgtop +%{_bindir}/systemd-delta +%{_bindir}/systemd-run +%{_bindir}/systemd-detect-virt +%{_bindir}/systemd-inhibit +%{_bindir}/systemd-path +%{_bindir}/systemd-firstboot +%{_bindir}/hostnamectl +%{_bindir}/localectl +%{_bindir}/timedatectl +%{_bindir}/bootctl +%{_bindir}/udevadm +%{_bindir}/kernel-install +%{_bindir}/systemd-hwdb +%{_prefix}/lib/systemd/systemd +%exclude %{_prefix}/lib/systemd/system/systemd-journal-gatewayd.* +%exclude %{_prefix}/lib/systemd/system/systemd-journal-remote.* +%exclude %{_prefix}/lib/systemd/system/systemd-journal-upload.* +%exclude %{_prefix}/lib/systemd/system/systemd-networkd* +%exclude %{_prefix}/lib/systemd/system/systemd-resolved.service +%exclude %{_prefix}/lib/systemd/system/dbus-org.freedesktop.resolve1.service +%exclude %{_prefix}/lib/systemd/system/dbus-org.freedesktop.network1.service +%{_prefix}/lib/systemd/system +%{_prefix}/lib/systemd/user +%exclude %{_prefix}/lib/systemd/systemd-journal-gatewayd +%exclude %{_prefix}/lib/systemd/systemd-journal-remote +%exclude %{_prefix}/lib/systemd/systemd-networkd +%exclude %{_prefix}/lib/systemd/systemd-networkd-wait-online +%exclude %{_prefix}/lib/systemd/systemd-resolved +%exclude %{_prefix}/lib/systemd/systemd-resolve-host +%exclude %{_prefix}/lib/systemd/systemd-journal-upload +%{_prefix}/lib/systemd/systemd-* +%{_prefix}/lib/systemd/import-pubring.gpg +%{_prefix}/lib/udev +%exclude %{_sysconfdir}/udev/rules.d/80-net-setup-link.rules +%{_prefix}/lib/tmpfiles.d/systemd.conf +%{_prefix}/lib/tmpfiles.d/systemd-nologin.conf +%{_prefix}/lib/tmpfiles.d/x11.conf +%{_prefix}/lib/tmpfiles.d/legacy.conf +%{_prefix}/lib/tmpfiles.d/tmp.conf +%{_prefix}/lib/tmpfiles.d/var.conf +%{_prefix}/lib/tmpfiles.d/etc.conf +%{_prefix}/lib/tmpfiles.d/sap.conf +%{_prefix}/lib/sysctl.d/50-default.conf +%{_prefix}/lib/systemd/system-preset/90-systemd.preset +%{_prefix}/lib/systemd/system-preset/99-default-disable.preset +%{_prefix}/lib/systemd/catalog/systemd.catalog +%{_prefix}/lib/kernel/install.d/50-depmod.install +%{_prefix}/lib/kernel/install.d/90-loaderentry.install +%{_sbindir}/init +%{_sbindir}/reboot +%{_sbindir}/halt +%{_sbindir}/poweroff +%{_sbindir}/shutdown +%{_sbindir}/telinit +%{_sbindir}/runlevel +%{_sbindir}/udevadm +%{_mandir}/man1/* +%exclude %{_mandir}/man5/systemd.network.* +%exclude %{_mandir}/man5/systemd.netdev.* +%exclude %{_mandir}/man5/systemd.link.* +%exclude %{_mandir}/man5/resolved.conf.* +%{_mandir}/man5/* +%{_mandir}/man7/* +%exclude %{_mandir}/man8/systemd-journal-gatewayd.* +%exclude %{_mandir}/man8/systemd-journal-remote.* +%exclude %{_mandir}/man8/systemd-networkd* +%exclude %{_mandir}/man8/systemd-resolved.* +%{_mandir}/man8/* +%{_datadir}/systemd/kbd-model-map +%{_datadir}/dbus-1/services/org.freedesktop.systemd1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.systemd1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.hostname1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.login1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.locale1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.timedate1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.machine1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.import1.service +%dir %{_datadir}/polkit-1 +%dir %{_datadir}/polkit-1/actions +%{_datadir}/polkit-1/actions/org.freedesktop.systemd1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.hostname1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.login1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.locale1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.timedate1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.machine1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.import1.policy +%{_libdir}/pkgconfig/systemd.pc +%{_datadir}/pkgconfig/udev.pc +%{_datadir}/bash-completion/completions/* +%{_datadir}/zsh/site-functions/* +%{_prefix}/lib/systemd/catalog/systemd.*.catalog +%config(noreplace) %{_sysconfdir}/rc.d/rc.local +%{_sysconfdir}/rc.local +%{_datadir}/systemd/language-fallback-map +%{_prefix}/lib/dracut/dracut.conf.d/76-phys-port-name.conf + +# Make sure we don't remove runlevel targets from F14 alpha installs, +# but make sure we don't create then anew. +%ghost %config(noreplace) %{_sysconfdir}/systemd/system/runlevel2.target +%ghost %config(noreplace) %{_sysconfdir}/systemd/system/runlevel3.target +%ghost %config(noreplace) %{_sysconfdir}/systemd/system/runlevel4.target +%ghost %config(noreplace) %{_sysconfdir}/systemd/system/runlevel5.target + +%files libs +%{_libdir}/security/pam_systemd.so +%{_libdir}/libnss_myhostname.so.2 +%{_libdir}/libnss_mymachines.so.2 +%{_libdir}/libudev.so.* +%{_libdir}/libsystemd.so.* +%{_libdir}/libsystemd-daemon.so.* +%{_libdir}/libsystemd-login.so.* +%{_libdir}/libsystemd-journal.so.* +%{_libdir}/libsystemd-id128.so.* + +%files devel +%dir %{_includedir}/systemd +%{_libdir}/libudev.so +%{_libdir}/libsystemd.so +%{_libdir}/libsystemd-daemon.so +%{_libdir}/libsystemd-login.so +%{_libdir}/libsystemd-journal.so +%{_libdir}/libsystemd-id128.so +%{_includedir}/systemd/sd-daemon.h +%{_includedir}/systemd/sd-login.h +%{_includedir}/systemd/sd-journal.h +%{_includedir}/systemd/sd-id128.h +%{_includedir}/systemd/sd-messages.h +%{_includedir}/systemd/_sd-common.h +%{_includedir}/libudev.h +%{_libdir}/pkgconfig/libudev.pc +%{_libdir}/pkgconfig/libsystemd.pc +%{_libdir}/pkgconfig/libsystemd-daemon.pc +%{_libdir}/pkgconfig/libsystemd-login.pc +%{_libdir}/pkgconfig/libsystemd-journal.pc +%{_libdir}/pkgconfig/libsystemd-id128.pc +%{_mandir}/man3/* +%dir %{_datadir}/gtk-doc/html/libudev +%{_datadir}/gtk-doc/html/libudev/* + +%files sysv +%{_bindir}/systemd-sysv-convert + +%files python +%{python_sitearch}/systemd + +%files -n libgudev1 +%{_libdir}/libgudev-1.0.so.* +%{_libdir}/girepository-1.0/GUdev-1.0.typelib + +%files -n libgudev1-devel +%{_libdir}/libgudev-1.0.so +%dir %{_includedir}/gudev-1.0 +%dir %{_includedir}/gudev-1.0/gudev +%{_includedir}/gudev-1.0/gudev/*.h +%{_datadir}/gir-1.0/GUdev-1.0.gir +%dir %{_datadir}/gtk-doc/html/gudev +%{_datadir}/gtk-doc/html/gudev/* +%{_libdir}/pkgconfig/gudev-1.0* + +%files journal-gateway +%config(noreplace) %{_sysconfdir}/systemd/journal-remote.conf +%config(noreplace) %{_sysconfdir}/systemd/journal-upload.conf +%{_prefix}/lib/systemd/system/systemd-journal-gatewayd.* +%{_prefix}/lib/systemd/system/systemd-journal-remote.* +%{_prefix}/lib/systemd/system/systemd-journal-upload.* +%{_prefix}/lib/systemd/systemd-journal-gatewayd +%{_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 + +%files networkd +%dir %{_prefix}/lib/systemd/network +%{_bindir}/networkctl +%{_prefix}/lib/systemd/system/systemd-networkd* +%{_prefix}/lib/systemd/systemd-networkd +%{_prefix}/lib/systemd/systemd-networkd-wait-online +%{_mandir}/man8/systemd-journal-gatewayd.* +%{_mandir}/man8/systemd-journal-remote.* +%{_mandir}/man8/systemd-networkd* +%{_mandir}/man5/systemd.network.* +%{_mandir}/man5/systemd.netdev.* +%{_mandir}/man5/systemd.link.* +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.network1.conf +%{_datadir}/dbus-1/system-services/org.freedesktop.network1.service +%{_prefix}/lib/udev/rules.d/80-net-setup-link.rules +%{_prefix}/lib/systemd/system/dbus-org.freedesktop.network1.service + +%files resolved +%{_prefix}/lib/systemd/systemd-resolved +%{_prefix}/lib/systemd/systemd-resolve-host +%{_sysconfdir}/systemd/resolved.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.resolve1.conf +%{_datadir}/dbus-1/system-services/org.freedesktop.resolve1.service +%{_libdir}/libnss_resolve.so.2 +%{_prefix}/lib/systemd/system/systemd-resolved.service +%{_prefix}/lib/systemd/system/dbus-org.freedesktop.resolve1.service +%{_mandir}/man5/resolved.conf.* +%{_mandir}/man8/systemd-resolved.* + +%changelog +* 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) +- 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-56 +- core: don't choke if a unit another unit triggers vanishes during reload (#1545676) + +* 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) + +* 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-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 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) +- 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) +- 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) +- 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 + +* Tue Jun 27 2017 Lukas Nykryn - 219-42 +- Revert "rules: move cpu hotplug rule to separate file" (#1465108) + +* Mon Jun 12 2017 Lukas Nykryn - 219-41 +- rules: move cpu hotplug rule to separate file (#1266322) + +* Tue May 30 2017 Lukas Nykryn - 219-40 +- readahead-collect: don't print warning message when handling symlink (#1387095) +- tmpfiles: don't recursively descend into journal directories in /var (#1411199) +- tmpfiles: also set acls on /var/log/journal (#1411199) +- tmpfiles: set acls on system.journal explicitly (#1411199) +- sysctl: configure kernel parameters in the order they occur in each sysctl configuration files (#4205) (#1382244) +- units: drop explicit NotifyAccess setting from journald's unit file (#5749) (#1444356) +- systemd-notify: Always pass a valid pid to sd_pid_notify (#1381743) +- sd_pid_notify_with_fds: fix computing msg_controllen (#1381743) + +* Tue May 02 2017 Lukas Nykryn - 219-39 +- tests: set tasks_max to infinity (#1337244) +- Avoid forever loop for journalctl --list-boots command (#4278) (#1294516) +- sd-journal: return SD_JOURNAL_INVALIDATE only if journal files were actually deleted/moved (#5580) (#1446140) +- load-fragment: don't print error about incorrect syntax when IPv6 is disabled (#1377055) +- core: manager: add some missing dbus properties (#1427927) +- core: manager: expose DefaultLimit* as properties on dbus (#1427927) +- fstab-generator: remove bogus condition (#1446171) + +* Thu Apr 20 2017 Lukas Nykryn - 219-38 +- core: properly handle jobs that are suppressed to JOB_NOPs when propagating restarts (#1436021) + +* Wed Apr 19 2017 Lukas Nykryn - 219-37 +- core: add support for the "pids" cgroup controller (#1337244) +- core: add new DefaultTasksMax= setting for system.conf (#1337244) +- logind: add a new UserTasksMax= setting to logind.conf (#1337244) +- core: support percentage specifications on TasksMax= (#1337244) +- core: reinstate propagation of stop/restart jobs via RequsiteOf dependencies (#1436021) +- core: when propagating restart requests due to deps, downgrade restart to try-restart (#1436021) + +* Thu Apr 13 2017 Lukáš Nykrýn - 219-36 +- spec cleanup (#1439787, #1392300, #1368929) + +* Tue Apr 11 2017 Lukas Nykryn - 219-35 +- tmpfiles: add new 'e' action which cleans up a dir without creating it (#1225739) +- util:bind_remount_recursive(): handle return 0 of set_consume() (#1433687) + +* Tue Apr 11 2017 Lukas Nykryn - 219-34 +- rules/40-redhat.rules: rules should be on one line (#1274401) + +* Mon Apr 10 2017 Lukas Nykryn - 219-33 +- execute: Add new PassEnvironment= directive (#1426214) +- test-execute: Add tests for new PassEnvironment= directive (#1426214) +- test-execute: Clarify interaction of PassEnvironment= and MANAGER_USER (#1426214) +- load-fragment: resolve specifiers in RuntimeDirectory (#1428110) +- Add microphone mute keymap for Dell Precision (#1413477) +- hwdb: update micmute YCODE on device node at DELL LATITUDE laptops for mic mute button. (#5012) (#1413477) +- udev/path_id: improve and enhance bus detection for Linux on z Systems (#1274401) +- core: port config_parse_bounding_set to extract_first_word (#1387398) +- core: simplify parsing of capability bounding set settings (#1387398) +- test: add test for capability bounding set parsing (#1387398) +- capabilities: keep bounding set in non-inverted format. (#1387398) +- capabilities: added support for ambient capabilities. (#1387398) +- man: add AmbientCapabilities entry. (#1387398) +- test-capability: rebase to upstream version (#1387398) +- namespace: don't fail on masked mounts (#1433687) +- sysv-generator: Provides: $network should also pull network.target to transaction (#5652) (#1438749) +- Install: correctly report symlink creations (#1435098) + +* Mon Feb 20 2017 Lukas Nykryn - 219-32 +- udev: fix crash with invalid udev.log-priority (#1245293) +- core: make exec code a bit more readable (#1421181) +- core: Private*/Protect* options with RootDirectory (#1421181) +- core: if the start command vanishes during runtime don't hit an assert (#1421658) +- systemctl: make sure that --now is carried out (#5209) (#1417459) +- udev: inform systemd how many workers we can potentially spawn (#4036) (#1361601) +- service: log_unit consumes id of unit not a unit (#1421658) +- automount: add expire support (#1354410) +- fstab-generator: fix memleak (#1354410) +- remove bus-proxyd (#1317518) + +* Tue Feb 07 2017 Lukas Nykryn - 219-31 +- If the notification message length is 0, ignore the message (#4237) (#1380175) +- systemctl: suppress errors with "show" for nonexistent units and properties (#1380259) +- 40-redhat.rules: disable auto-online of hot-plugged memory on IBM z Systems (#1375603) +- pid1: don't return any error in manager_dispatch_notify_fd() (#4240) (#1380259) +- pid1: process zero-length notification messages again (#1380259 +#1380259) +- pid1: more informative error message for ignored notifications (#1380259) +- manager: 219 needs u->id in log_unit_debug (#1380259) +- virt: add possibility to skip the check for chroot (#1379852) +- load-fragment: fix parsing values in bytes and prevent returning -ERANGE incorrectly (#1396277) +- core: fix assertion check (#1396312) +- tmp.mount.hm4: After swap.target (#3087) (#1298355) +- make sure all swap units are ordered before the swap target (#1298355) +- Recognise Lustre as a remote file system (#4530) (#1390542) +- unit: don't add Requires for tmp.mount (#1372249) +- core: return 0 from device_serialize() (#1403249) +- mtd_probe: include stdint (#1404251) +- tests: fix failure of test-execute if /dev/mem is not available (#5028) (#1410056) +- sd-journal: properly export has_{persistent|runtime}_files() (#1409527) +- core: add possibility to set action for ctrl-alt-del burst (#4105) (#1353028) +- failure-action: generalize failure action to emergency action (#1353028) +- core: use emergency_action for ctr+alt+del burst (#1353028) +- udev/path_id: introduce support for NVMe devices (#4169) (#1373150) +- core: fix CapabilityBoundingSet merging (#1409586) +- core: fix capability bounding set parsing (#1409586) +- core: make parsing of RLIMIT_NICE aware of actual nice levels (#1409588) +- shared: fix double free in unmask (#5005) (#1409997) +- shared: fix double free in link (#1409997) +- shared: check strdup != NULL (#1409997) +- core: improve error message when RefuseManualStart(Stop) is hit (#5132) (#1026648) +- systemctl: fix 'is-enabled' exit status on failure when executed in chroot (#4773) (#1413964) +- man: document that the automatic journal limits are capped to 4G by default (#1418547) +- random-seed: raise POOL_SIZE_MIN to 1024 (#1386824) +- bash-completion: add support for --now (#5155) (#1351806) +- basic: fix touch() creating files with 07777 mode (#1416062) +- udev: net_id: add support for phys_port_name attribute (#4506) (#1392426) +- install: introduce UnitFileFlags (#1413041) +- shared, systemctl: teach is-enabled to show installation targets (#1413041) + +* Mon Nov 07 2016 Lukáš Nykrýn - 219-30.6 +- better version of vmware trigger + +* Fri Nov 4 2016 Michal Sekletar - 219-30.5 +- on update from systemd version 219-21 and older generate udev rules that preserve old network interface names on VMware VMs (#1391944) + +* Thu Nov 03 2016 Lukas Nykryn - 219-30.4 +- virt: add possibility to skip the check for chroot (#1379852) + +* Fri Oct 07 2016 Lukas Nykryn - 219-30.3 +- mtd_probe: add include for stdint (#1381573) + +* Fri Oct 07 2016 Lukas Nykryn - 219-30.2 +- manager: 219 needs u->id in log_unit_debug (#1381573) + +* Wed Oct 05 2016 Lukas Nykryn - 219-30.1 +- If the notification message length is 0, ignore the message (#4237) (#1381573) +- systemctl: suppress errors with "show" for nonexistent units and properties (#1380686) +- 40-redhat.rules: disable auto-online of hot-plugged memory on IBM z Systems (#1381123) +- pid1: don't return any error in manager_dispatch_notify_fd() (#4240) (#1381573) +- pid1: process zero-length notification messages again (#1381573) +- pid1: more informative error message for ignored notifications (#1381573) + +* Tue Sep 13 2016 Lukas Nykryn - 219-30 +- systemctl,pid1: do not warn about missing install info with "preset" (#1373950) +- systemctl/core: ignore masked units in preset-all (#1375097) +- shared/install: handle dangling aliases as an explicit case, report nicely (#1375097) +- shared/install: ignore unit symlinks when doing preset-all (#1375097) +- 40-redhat.rules: don't hoplug memory on s390x (#1370161) + +* Mon Sep 05 2016 Lukas Nykryn - 219-29 +- fix gcc warnings about uninitialized variables (#1318994) +- journalctl: rework code that checks whether we have access to /var/log/journal (#1318994) +- journalctl: Improve boot ID lookup (#1318994) +- journalctl: only have a single exit path from main() (#1318994) +- journalctl: free all command line argument objects (#1318994) +- journalctl: rename boot_id_t to BootId (#1318994) +- util: introduce CMSG_FOREACH() macro and make use of it everywhere (#1318994) +- journald: don't employ inner loop for reading from incoming sockets (#1318994) +- journald: fix count of object meta fields (#1318994) +- journal-cat: return a correct error, not -1 (#1318994) +- journalctl: introduce short options for --since and --until (#1318994) +- journal: s/Envalid/Invalid/ (#1318994) +- journald: dispatch SIGTERM/SIGINT with a low priority (#1318994) +- lz4: fix size check which had no chance of working on big-endian (#1318994) +- journal: normalize priority of logging sources (#1318994) +- Fix miscalculated buffer size and uses of size-unlimited sprintf() function. (#1318994) +- journal: Drop monotonicity check when appending to journal file (#1318994) +- journalctl: unify how we free boot id lists a bit (#1318994) +- journalctl: don't trust the per-field entry tables when looking for boot IDs (#1318994) +- units: remove udev control socket when systemd stops the socket unit (#49) (#1370133) +- logind: don't assert if the slice is missing (#1371437) +- core: enable transient unit support for slice units (#1370299) +- sd-bus: bump message queue size (#1371205) +- install: fix disable when /etc/systemd/system is a symlink (#1285996) +- rules: add NVMe rules (#3136) (#1274651) +- rules: introduce disk/by-id (model_serial) symlinks for NVMe drives (#3974) (#1274651) +- rules: fix for possible whitespace in the "model" attribute (#1274651) + +* Fri Aug 19 2016 Lukas Nykryn - 219-27 +- tmpfiles: enforce ordering when executing lines (#1365870) +- Introduce bus_unit_check_load_state() helper (#1256858) +- core: use bus_unit_check_load_state() in transaction_add_job_and_dependencies() (#1256858) +- udev/path_id: correct segmentation fault due to missing NULL check (#1365556) +- rules: load sg driver also when scsi_target appears (#45) (#1322773) + +* Tue Aug 09 2016 Lukas Nykryn - 219-26 +- install: do not crash when processing empty (masked) unit file (#1159308) +- Revert "install: fix disable via unit file path" (#1348208) +- systemctl: allow disable on the unit file path, but warn about it (#3806) (#1348208) + +* Thu Aug 04 2016 Lukas Nykryn - 219-25 +- units: increase watchdog timeout to 3min for all our services (#1267707) +- core: bump net.unix.max_dgram_qlen really early during boot (#1267707) +- core: fix priority ordering in notify-handling (#1267707) +- tests: fix personality tests on ppc64 and aarch64 (#1361049) +- systemctl: consider service running only when it is in active or reloading state (#3874) (#1362461) + +* Mon Jul 18 2016 Lukas Nykryn - 219-24 +- manager: don't skip sigchld handler for main and control pid for services (#3738) (#1342173) + +* Tue Jul 12 2016 Lukas Nykryn - 219-23 +- udevadm: explicitly relabel /etc/udev/hwdb.bin after rename (#1350756) +- systemctl: return diffrent error code if service exist or not (#3385) (#1047466) +- systemctl: Replace init script error codes with enum (#3400) (#1047466) +- systemctl: rework "systemctl status" a bit (#1047466) +- journal-verify: don't hit SIGFPE when determining progress (#1350232) +- journal: avoid mapping empty data and field hash tables (#1350232) +- journal: when verifying journal files, handle empty ones nicely (#1350232) +- journal: explain the error when we find a non-DATA object that is compressed (#1350232) +- journalctl: properly detect empty journal files (#1350232) +- journal: uppercase first character in verify error messages (#1350232) +- journalctl: make sure 'journalctl -f -t unmatched' blocks (#1350232) +- journalctl: don't print -- No entries -- in quiet mode (#1350232) +- sd-event: expose the event loop iteration counter via sd_event_get_iteration() (#1342173) +- manager: Only invoke a single sigchld per unit within a cleanup cycle (#1342173) +- manager: Fixing a debug printf formatting mistake (#1342173) +- core: support IEC suffixes for RLIMIT stuff (#1351415) +- core: accept time units for time-based resource limits (#1351415) +- time-util: add parse_time(), which is like parse_sec() but allows specification of default time unit if none is specified (#1351415) +- core: support ranges for RLIMIT options (#1351415) +- core: fix rlimit parsing (#1351415) +- core: dump rlim_cur too (#1351415) +- install: fix disable via unit file path (#1348208) + +* Wed Jun 22 2016 Lukas Nykryn - 219-22 +- nspawn: when connected to pipes for stdin/stdout, pass them as-is to PID 1 (#1307080) +- mount: remove obsolete -n (#1339721) +- core: don't log job status message in case job was effectively NOP (#3199) (#1280014) +- core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent notification (#1305608) +- logind: process session/inhibitor fds at higher priority (#1305608) +- Teach bus_append_unit_property_assignment() about 'Delegate' property (#1337922) +- sd-netlink: fix deep recursion in message destruction (#1330593) +- add REMOTE_ADDR and REMOTE_PORT for Accept=yes (#1341154) +- core: don't dispatch load queue when setting Slice= for transient units (#1343904) +- run: make --slice= work in conjunction with --scope (#1343904) +- myhostname: fix timeout if ipv6 is disabled (#1330973) +- readahead: do not increase nr_requests for root fs block device (#1314559) +- manager: reduce complexity of unit_gc_sweep (#3507) (#1344556) +- hwdb: selinuxify a bit (#3460) (#1343648) + +* Mon May 23 2016 Lukas Nykryn - 219-21 +- path_id: reintroduce by-path links for virtio block devices (#952567) +- journal: fix error handling when compressing journal objects (#1292447) +- journal: irrelevant coding style fixes (#1292447) +- install: follow unit file symlinks in /usr, but not /etc when looking for [Install] data (#1159308) +- core: look for instance when processing template name (#1159308) +- core: improve error message when starting template without instance (#1142369) +- man/tmpfiles.d: add note about permissions and ownership of symlinks (#1296288) +- tmpfiles: don't follow symlinks when adjusting ACLs, fille attributes, access modes or ownership (#1296288) +- udev: filter out non-sensically high onboard indexes reported by the kernel (#1230210) +- test-execute: add tests for RuntimeDirectory (#1324826) +- core: fix group ownership when Group is set (#1324826) +- fstab-generator: cescape device name in root-fsck service (#1306126) +- core: add new RandomSec= setting for time units (#1305279) +- core: rename Random* to RandomizedDelay* (#1305279) +- journal-remote: change owner of /var/log/journal/remote and create /var/lib/systemd/journal-upload (#1327303) +- Add Seal option in the configuration file for journald-remote (#1329233) +- tests: fix make check failure (#1159308) +- device: make sure to not ignore re-plugged device (#1332606) +- device: Ensure we have sysfs path before comparing. (#1332606) +- core: fix memory leak on set-default, enable, disable etc (#1331667) +- nspawn: fix minor memory leak (#1331667) +- basic: fix error/memleak in socket-util (#1331667) +- core: fix memory leak in manager_run_generators() (#1331667) +- modules-load: fix memory leak (#1331667) +- core: fix memory leak on failed preset-all (#1331667) +- sd-bus: fix memory leak in test-bus-chat (#1331667) +- core: fix memory leak in transient units (#1331667) +- bus: fix leak in error path (#1331667) +- shared/logs-show: fix memleak in add_matches_for_unit (#1331667) +- logind: introduce LockedHint and SetLockedHint (#3238) (#1335499) +- import: use the old curl api (#1284974) +- importd: drop dkr support (#1284974) +- import: add support for gpg2 for verifying imported images (#1284974) + +* Thu Mar 10 2016 Lukas Nykryn - 219-20 +- run: synchronously wait until the scope unit we create is started (#1272368) +- device: rework how we enter tentative state (#1283579) +- core: Do not bind a mount unit to a device, if it was from mountinfo (#1283579) +- logind: set RemoveIPC=no by default (#1284588) +- sysv-generator: follow symlinks in /etc/rc.d/init.d (#1285492) +- sysv-generator test: always log to console (#1279034) +- man: RemoveIPC is set to no on rhel (#1284588) +- Avoid /tmp being mounted as tmpfs without the user's will (#1298109) +- test sysv-generator: Check for network-online.target. (#1279034) +- arm/aarch64: detect-virt: check dmi (#1278165) +- detect-virt: dmi: look for KVM (#1278165) +- Revert "journald: turn ForwardToSyslog= off by default" (#1285642) +- terminal-util: when resetting terminals, don't wait for carrier (#1266745) +- basic/terminal-util: introduce SYSTEMD_COLORS environment variable (#1247963) +- ask-password: don't abort when message is missing (#1261136) +- sysv-generator: do not join dependencies on one line, split them (#1288600) +- udev: fibre channel: fix NPIV support (#1266934) +- ata_id: unreverse WWN identifier (#1273306) +- Fixup WWN bytes for big-endian systems (#1273306) +- sd-journal: introduce has_runtime_files and has_persistent_files (#1082179) +- journalctl: improve error messages when the specified boot is not found (#1082179) +- journalctl: show friendly info when using -b on runtime journal only (#1082179) +- journalctl: make "journalctl /dev/sda" work (#947636) +- journalctl: add match for the current boot when called with devpath (#947636) +- man: clarify what happens when journalctl is called with devpath (#947636) +- core: downgrade warning about duplicate device names (#1296249) +- udev: downgrade a few warnings to debug messages (#1289461) +- man: LEVEL in systemd-analyze set-log level is not optional (#1268336) +- Revert "udev: fibre channel: fix NPIV support" (#1266934) +- udev: path-id: fibre channel NPIV - use fc_vport's port_name (#1266934) +- systemctl: is-active/failed should return 0 if at least one unit is in given state (#1254650) +- rules: set SYSTEMD_READY=0 on DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 only with ADD event (#1312011) +- s390: add personality support (#1300344) +- socket_address_listen - do not rely on errno (#1316452) + +* Mon Oct 12 2015 Lukas Nykryn - 219-19 +- udev: make naming for virtio devices opt-in (#1269216) +- tmpfiles.d: don't clean SAP sockets either (#1186044) + +* Tue Oct 06 2015 Lukas Nykryn - 219-18 +- tmpfiles.d: don't clean SAP lockfiles and logs (#1186044) + +* Mon Sep 28 2015 Lukas Nykryn - 219-17 +- sd-event: fix prepare priority queue comparison function (#1266479) +- units: run ldconfig also when cache is unpopulated (#1265539) +- selinux: fix regression of systemctl subcommands when absolute unit file paths are specified (#1185120) + +* Wed Sep 23 2015 Lukas Nykryn - 219-16 +- login: fix gcc warning, include missing header file (#1264073) +- shutdown: make sure /run/nologin has correct label (#1264073) + +* Tue Sep 22 2015 Lukas Nykryn - 219-15 +- login: fix label on /run/nologin (#1264073) +- udev-rules: prandom character device node permissions (#1264112) + +* Tue Sep 15 2015 Lukas Nykryn - 219-14 +- Revert "sysctl.d: default to fq_codel, fight bufferbloat" (#1263158) +- loginctl: print nontrivial properties in logictl show-* (#1260465) + +* Wed Sep 02 2015 Lukas Nykryn - 219-13 +- udev: net_id - support predictable ifnames on virtio buses (#1259015) + +* Tue Sep 01 2015 Lukas Nykryn - 219-12 +- selinux: fix check for transient units (#1255129) +- socket: fix setsockopt call. SOL_SOCKET changed to SOL_TCP. (#1135599) +- selinux: fix missing SELinux unit access check (#1185120) +- selinux: always use *_raw API from libselinux (#1256888) + +* Wed Aug 12 2015 Lukas Nykryn - 219-11 +- journald-server: don't read audit events (#1252409) +- everything: remove traces of --user (#1071363) + +* Fri Aug 07 2015 Lukas Nykryn - 219-10 +- Revert "journald: move /dev/log socket to /run" (#1249968) + +* Fri Jul 31 2015 Lukas Nykryn - 219-9 +- units: add [Install] section to tmp.mount +- bus-util: add articles to explanation messages (#1016680) +- bus-util: print correct warnings for units that fail but for which we have a NULL result only (#1016680) + +* Thu Jul 16 2015 Lukas Nykryn - 219-8 +- sysv-generator test: Fix assertion (#1222517) +- man: avoid line break in url (#1222517) +- Add VARIANT as a standard value for /etc/os-release (#1222517) +- Fix permissions on /run/systemd/nspawn/locks (#1222517) +- generators: rename add_{root,usr}_mount to add_{sysroot,sysroot_usr}_mount (#1222517) +- Generate systemd-fsck-root.service in the initramfs (#1222517) +- units: fix typo in systemd-resolved.service (#1222517) +- core: don't consider umask for SocketMode= (#1222517) +- timedate: fix memory leak in timedated (#1222517) +- coredump: make sure we vacuum by default (#1222517) +- tmpfiles: don't fail if we cannot create a subvolume because a file system is read-only but a dir already exists anyway (#1222517) +- resolved: fix crash when shutting down (#1222517) +- resolved: allow DnsAnswer objects with no space for RRs (#1222517) +- id128: add new sd_id128_is_null() call (#1222517) +- journalctl: Improve boot ID lookup (#1222517) +- test-hashmap: fix an assert (#1222517) +- units: make sure systemd-nspawn@.slice instances are actually located in machine.slice (#1222517) +- Revert "journald-audit: exit gracefully in the case we can't join audit multicast group" (#1222517) +- journald: handle more gracefully when bind() fails on audit sockets (#1222517) +- udev: link-config - fix corruption (#1222517) +- udev/net_id: Only read the first 64 bytes of PCI config space (#1222517) +- shared: generator - correct path to systemd-fsck (#1222517) +- logind: Save the user’s state when a session enters SESSION_ACTIVE (#1222517) +- small fix ru translation (#1222517) +- kmod-setup: don't warn when ipv6 can't be loaded (#1222517) +- Partially revert "ma-setup: simplify" (#1222517) +- ima-setup: write policy one line at a time (#1222517) +- ata_id: unbotch format specifier (#1222517) +- install: explicitly return 0 on success (#1222517) +- systemd.service.xml: document that systemd removes the PIDFile (#1222517) +- core: handle --log-target=null when calling systemd-shutdown (#1222517) +- man: ProtectHome= protects /root as well (#1222517) +- timedatectl: trim non-local RTC warning to 80 chars wide (#1222517) +- escape: fix exit code (#1222517) +- man: information about available properties (#1222517) +- journal: in persistent mode create /var/log/journal, with all parents. (#1222517) +- sysv-generator: fix wrong "Overwriting existing symlink" warnings (#1222517) +- mount: don't claim a device is gone from /proc/self/mountinfo before it is gone from *all* lines (#1222517) +- mount: properly check for mounts currently in /proc/self/mountinfo (#1222517) + +* Tue Jul 14 2015 Lukas Nykryn - 219-7 +- udev: fix crash in path_id builtin (#957112) + +* Fri Jul 10 2015 Lukas Nykryn - 219-6 +- sd-bus: don't inherit connection creds into message creds when we have a direct connection (#1230190) + +* Tue Jun 30 2015 Lukas Nykryn - 219-5 +- Revert "core: one step back again, for nspawn we actually can't wait for cgroups running empty since systemd will get exactly zero notifications about it" (#1199644) +- bus-creds: always set SD_BUS_CREDS_PID when we set pid in the mask (#1230190) +- sd-bus: do not use per-datagram auxiliary information (#1230190) +- sd-bus: store selinux context at connection time (#1230190) +- journald: simplify context handling (#1230190) +- bash-completion: add verb set-property (#1235635) + +* Fri Jun 19 2015 Lukas Nykryn - 219-4 +- core: Fix assertion with empty Exec*= paths (#1222517) +- rules: load sg module (#1186462) +- util: add shell_maybe_quote() call for preparing a string for shell cmdline inclusion (#1016680) +- bus-util: be more verbose if dbus job fails (#1016680) +- notify: fix badly backported help message (#1199644) +- cryptsetup: craft a unique ID with the source device (#1226333) +- systemctl: introduce --now for enable, disable and mask (#1233081) +- udev: also create old sas paths (#957112) +- journald: do not strip leading whitespace from messages (#1227396) + +* Mon May 18 2015 Lukas Nykryn - 219-3 +- console-getty.service: don't start when /dev/console is missing (#1222517) +- resolved: Do not add .busname dependencies, when compiling without kdbus. (#1222517) +- man: add journal-remote.conf(5) (#1222517) +- mount: don't run quotaon only for network filesystems (#1222517) +- mount: fix up wording in the comment (#1222517) +- udev: net_id - fix copy-paste error (#1222517) +- man: don't mention "journalctl /dev/sda" (#1222517) +- units: move After=systemd-hwdb-update.service dependency from udev to udev-trigger (#1222517) +- units: explicitly order systemd-user-sessions.service after nss-user-lookup.target (#1222517) +- zsh-completion: update loginctl (#1222517) +- zsh-completion: add missing -M completion for journalctl (#1222517) +- zsh-completion: update hostnamectl (#1222517) +- shell-completion: systemctl switch-root verb (#1222517) +- core/automount: beef up error message (#1222517) +- man: remove 'fs' from 'rootfsflags' (#1222517) +- shared: fix memleak (#1222517) +- udevd: fix synchronization with settle when handling inotify events (#1222517) +- python-systemd: fix is_socket_inet to cope with ports (#1222517) +- man: fix examples indentation in tmpfiles.d(5) (#1222517) +- systemctl: avoid bumping NOFILE rlimit unless needed (#1222517) +- exit-status: Fix "NOTINSSTALLED" typo (#1222517) +- tmpfiles: there's no systemd-forbid-user-logins.service service (#1222517) +- kmod-setup: load ip_tables kmod at boot (#1222517) +- util: Fix assertion in split() on missing ' (#1222517) +- units: set KillMode=mixed for our daemons that fork worker processes (#1222517) +- unit: don't add automatic dependencies on device units if they aren't supported (#1222517) +- update-done: ignore nanosecond file timestamp components, they are not reliable (#1222517) +- sd-daemon: simplify sd_pid_notify_with_fds (#1222517) +- fstab-generator: add x-systemd.requires and x-systemd.requires-mounts-for (#1164334) + +* Thu May 14 2015 Lukas Nykryn - 219-2 +- udev: restore udevadm settle timeout (#1210981) +- udev: settle should return immediately when timeout is 0 (#1210981) +- udev: Fix ping timeout when settle timeout is 0 (#1210981) +- detect-virt: use /proc/device-tree (#1207773) +- ARM: detect-virt: detect Xen (#1207773) +- ARM: detect-virt: detect QEMU/KVM (#1207773) +- Persistent by_path links for ata devices (#1045498) +- man: document forwarding to syslog better (#1177336) +- man: fix typos in previous comimt (#1177336) +- LSB: always add network-online.target to services with priority over 10 (#1189253) +- rules: enable memory hotplug (#1105020) +- rules: reload sysctl settings when the bridge module is loaded (#1182105) + +* Tue Apr 14 2015 Lukáš Nykrýn - 219-1 +- workaround build issues on ppc and s390 +- some more patches + +* Tue Mar 17 2015 Lukáš Nykrýn - 219-0.4 +- steal more patches from fedora + +* Fri Mar 13 2015 Lukáš Nykrýn - 219-0.3 +- steal patches from fedora + +* Fri Mar 06 2015 Lukáš Nykrýn - 219-0.1 +- rebase to 219 + +* Mon Dec 15 2014 Lukáš Nykrýn - 218-0.3 +- rebase to 218 +- remove networkd tmpfiles snipets due to packaging issues +- add resolved subpackage +- backport some nspawn features from upstream + +* Thu Nov 20 2014 Lukáš Nykrýn - 217-0.3 +- split systemd and networkd tmpfiles snippets + +* Thu Nov 20 2014 Lukáš Nykrýn - 217-0.2 +- spec fixes +- core: introduce new Delegate=yes/no property controlling creation of cgroup subhierarchies + +* Mon Nov 17 2014 Lukáš Nykrýn - 217-0.1 +- rebase to 217 + +* Mon Nov 10 2014 Lukas Nykryn - 208-19 +- cgroups-agent: really down-grade log level (#1044386) + +* Mon Nov 10 2014 Lukas Nykryn - 208-18 +- login: rerun vconsole-setup when switching from vgacon to fbcon (#1002450) + +* Fri Nov 07 2014 Lukas Nykryn - 208-17 +- udev: net_id dev_port is base 10 (#1155996) +- udev: Fix parsing of udev.event-timeout kernel parameter (#1154778) + +* Thu Oct 30 2014 Lukas Nykryn - 208-16 +- logind: use correct "who" enum values with KillUnit. (#1155502) +- logind: always kill session when termination is requested (#1155502) +- udev: net_id - correctly name netdevs based on dev_port when set (#1155996) + +* Tue Oct 21 2014 Lukas Nykryn - 208-15 +- core: do not segfault if /proc/swaps cannot be opened (#1151239) +- man: we don't have 'Wanted' dependency (#1152487) +- environment: append unit_id to error messages regarding EnvironmentFile (#1147691) +- udevd: add --event-timeout commandline option (#1154778) + +* Wed Oct 08 2014 Lukas Nykryn - 208-14 +- core: don't allow enabling if unit is masked (#1149299) + +* Tue Oct 07 2014 Lukas Nykryn - 208-13 +- tmpfiles: minor modernizations (#1147524) +- install: when looking for a unit file for enabling, search for templates only after traversing all search directories (#1147524) +- install: remove unused variable (#1147524) +- bootctl: typo fix in help message (#1147524) +- logind: ignore failing close() on session-devices (#1147524) +- sysfs-show.c: return negative error (#1147524) +- core: only send SIGHUP when doing first kill, not when doing final sigkill (#1147524) +- cgroup: make sure to properly send SIGCONT to all processes of a cgroup if that's requested (#1147524) +- core: don't send duplicate SIGCONT when killing units (#1147524) +- efi: fix Undefined reference efi_loader_get_boot_usec when EFI support is disabled (#1147524) +- macro: better make IN_SET() macro use const arrays (#1147524) +- macro: make sure we can use IN_SET() also with complex function calls as first argument (#1147524) +- core: fix property changes in transient units (#1147524) +- load-modules: properly return a failing error code if some module fails to load (#1147524) +- core/unit: fix unit_add_target_dependencies() for units with no dependencies (#1147524) +- man: there is no ExecStopPre= for service units (#1147524) +- man: document that per-interface sysctl variables are applied as network interfaces show up (#1147524) +- journal: downgrade vaccuum message to debug level (#1147524) +- logs-show: fix corrupt output with empty messages (#1147524) +- journalctl: refuse extra arguments with --verify and similar (#1147524) +- journal: assume that next entry is after previous entry (#1147524) +- journal: forget file after encountering an error (#1147524) +- man: update link to LSB (#1147524) +- man: systemd-bootchart - fix spacing in command (#1147524) +- man: add missing comma (#1147524) +- units: Do not unescape instance name in systemd-backlight@.service (#1147524) +- manager: flush memory stream before using the buffer (#1147524) +- man: multiple sleep modes are to be separated by whitespace, not commas (#1147524) +- man: fix description of systemctl --after/--before (#1147524) +- udev: properly detect reference to unexisting part of PROGRAM's result (#1147524) +- gpt-auto-generator: don't return OOM on parentless devices (#1147524) +- man: improve wording of systemctl's --after/--before (#1147524) +- cgroup: it's not OK to invoke alloca() in loops (#1147524) +- core: don't try to relabel mounts before we loaded the policy (#1147524) +- systemctl: --kill-mode is long long gone, don't mention it in the man page (#1147524) +- ask-password: when the user types a overly long password, beep and refuse (#1147524) +- logind: don't print error if devices vanish during ACL-init (#1147524) +- tty-ask-password-agent: return negative errno (#1147524) +- journal: cleanup up error handling in update_catalog() (#1147524) +- bash completion: fix __get_startable_units (#1147524) +- core: check the right variable for failed open() (#1147524) +- man: sd_journal_send does nothing when journald is not available (#1147524) +- man: clarify that the ExecReload= command should be synchronous (#1147524) +- conf-parser: never consider it an error if we cannot load a drop-in file because it is missing (#1147524) +- socket: properly handle if our service vanished during runtime (#1147524) +- Do not unescape unit names in [Install] section (#1147524) +- util: ignore_file should not allow files ending with '~' (#1147524) +- core: fix invalid free() in killall() (#1147524) +- install: fix invalid free() in unit_file_mask() (#1147524) +- unit-name: fix detection of unit templates/instances (#1147524) +- journald: make MaxFileSec really default to 1month (#1147524) +- bootchart: it's not OK to return -1 from a main program (#1147524) +- journald: Fix off-by-one error in "Missed X kernel messages" warning (#1147524) +- man: drop references to removed and obsolete 'systemctl load' command (#1147524) +- units: fix BindsTo= logic when applied relative to services with Type=oneshot (#1147524) + +* Mon Sep 29 2014 Lukas Nykryn - 208-12 +- units/serial-getty@.service: add [Install] section (#1083936) +- units: order network-online.target after network.target (#1072431) +- util: consider both fuse.glusterfs and glusterfs network file systems (#1080229) +- core: make StopWhenUnneeded work in conjunction with units that fail during their start job (#986949) +- cgroups-agent: down-grade log level (#1044386) +- random-seed: raise POOL_SIZE_MIN constant to 1024 (#1066517) +- delta: do not use unicode chars in C locale (#1088419) +- core: print debug instead of error message (#1105608) +- journald: always add syslog facility for messages coming from kmsg (#1113215) +- fsck,fstab-generator: be lenient about missing fsck. (#1098310) +- rules/60-persistent-storage: add nvme pcie ssd scsi_id ENV (#1042990) +- cgls: fix running with -M option (#1085455) +- getty: Start getty on 3270 terminals available on Linux on System z (#1075729) +- core: Added support for ERRNO NOTIFY_SOCKET message parsing (#1106457) +- socket: add SocketUser= and SocketGroup= for chown()ing sockets in the file system (#1111761) +- tmpfiles: add --root option to operate on an alternate fs tree (#1111199) +- units: make ExecStopPost action part of ExecStart (#1036276) +- machine-id: only look into KVM uuid when we are not running in a container (#1123452) +- util: reset signals when we fork off agents (#1134818) +- udev: do not skip the execution of RUN when renaming a network device fails (#1102135) +- man: mention System Administrator's Guide in systemctl manpage (#978948) +- vconsole: also copy character maps (not just fonts) from vt1 to vt2, vt3, ... (#1002450) +- localed: consider an unset model as a wildcard (#903776) +- systemd-detect-virt: detect s390 virtualization (#1139149) +- socket: introduce SELinuxContextFromNet option (#1113790) +- sysctl: make --prefix allow all kinds of sysctl paths (#1138591) +- man: mention localectl in locale.conf (#1049286) +- rules: automatically online hot-added CPUs (#968811) +- rules: add rule for naming Dell iDRAC USB Virtual NIC as 'idrac' (#1054477) +- bash-completion: add verb set-property (#1064487) +- man: update journald rate limit defaults (#1145352) +- core: don't try to connect to d-bus after switchroot (#1083300) +- localed: check for partially matching converted keymaps (#1109145) +- fileio: make parse_env_file() return number of parsed items (#1069420) + +* Wed Apr 02 2014 Lukáš Nykrýn - 208-11 +- logind-session: save stopping flag (#1082692) +- unit: add waiting jobs to run queue in unit_coldplug (#1083159) + +* Fri Mar 28 2014 Harald Hoyer 208-10 +- require redhat-release >= 7.0 +Resolves: rhbz#1070114 + +* Fri Mar 14 2014 Lukáš Nykrýn - 208-9 +- fixes crashes in logind and systemd (#1073994) +- run fsck before mouting root in initramfs (#1056661) + +* Thu Mar 06 2014 Lukáš Nykrýn - 208-8 +- rules: mark loop device as SYSTEMD_READY=0 if no file is attached (#1067422) +- utmp: make sure we don't write the utmp reboot record twice on each boot (#1053600) +- rework session shutdown logic (#1047614) +- introduce new stop protocol for unit scopes (#1064976) + +* Wed Mar 05 2014 Lukáš Nykrýn - 208-7 +- setup tty permissions and group for /dev/sclp_line0 (#1070310) +- cdrom_id: use the old MMC fallback (#1038015) +- mount: don't send out PropertiesChanged message if actually nothing got changed (#1069718) + +* Wed Feb 26 2014 Lukáš Nykrýn - 208-6 +- fix boot if SELINUX=permissive in configuration file and trying to boot in enforcing=1 (#907841) + +* Tue Feb 25 2014 Lukáš Nykrýn - 208-5 +- reintroduce 60-alias-kmsg.rules (#1032711) + +* Mon Feb 17 2014 Lukáš Nykrýn - 208-4 +- fstab-generator: revert wrongly applied patch + +* Fri Feb 14 2014 Lukáš Nykrýn - 208-3 +- dbus-manager: fix selinux check for enable/disable + +* Wed Feb 12 2014 Michal Sekletar - 208-2 +- require redhat-release package +- call systemd-tmpfiles after package installation (#1059345) +- move preset policy out of systemd package (#903690) + +* Tue Feb 11 2014 Michal Sekletar - 208-1 +- rebase to systemd-208 (#1063332) +- do not create symlink /etc/systemd/system/syslog.service (#1055421) + +* Fri Jan 24 2014 Daniel Mach - 207-14 +- Mass rebuild 2014-01-24 + +* Thu Jan 16 2014 Lukáš Nykrýn - 207-13 +- fix SELinux check for transient units (#1008864) + +* Wed Jan 15 2014 Lukáš Nykrýn - 207-12 +- shell-completion: remove load and dump from systemctl (#1048066) +- delta: ensure that d_type will be set on every fs (#1050795) +- tmpfiles: don't allow label_fix to print ENOENT when we want to ignore it (#1044871) +- udev/net_id: Introduce predictable network names for Linux on System z (#870859) +- coredumpctl: in case of error free pattern after print (#1052786) + +* Fri Dec 27 2013 Daniel Mach - 207-11 +- Mass rebuild 2013-12-27 + +* Thu Dec 19 2013 Lukas Nykryn - 207-10 +- cgroup_show: don't call show_pid_array on empty arrays + +* Wed Dec 18 2013 Lukas Nykryn - 207-9 +- treat reload failure as failure (#1036848) +- improve journal performance (#1029604) +- backport bugfixes (#1043525) +- fix handling of trailing whitespace in split_quoted (#984832) +- localed: match converted keymaps before legacy (#903776) +- improve the description of parameter X in tmpfiles.d page (#1029604) +- obsolete ConsoleKit (#1039761) +- make rc.local more backward comaptible (#1039465) + +* Tue Nov 19 2013 Lukas Nykryn - 207-8 +- tmpfiles: introduce m (#1030961) + +* Tue Nov 12 2013 Lukas Nykryn - 207-7 +- introduce DefaultStartLimit (#821723) + +* Mon Nov 11 2013 Harald Hoyer 207-6 +- changed systemd-journal-gateway login shell to /sbin/nologin +- backported a lot of bugfixes +- udev: path_id - fix by-path link generation for scm devices +Resolves: rhbz#888707 + +* Tue Nov 05 2013 Lukas Nykryn - 207-5 +- create /etc/rc.d/rc.local (#968401) +- cgroup: always enable memory.use_hierarchy= for all cgroups (#1011575) +- remove user@.service (#1019738) +- drop some out-of-date references to cgroup settings (#1000004) +- explain NAME in systemctl man page (#978954) + +* Tue Oct 15 2013 Lukas Nykryn - 207-4 +- core: whenever a new PID is passed to us, make sure we watch it + +* Tue Oct 01 2013 Lukas Nykryn - 207-3 +- presets: add tuned.service + +* Thu Sep 19 2013 Lukas Nykryn - 207-2 +- Advertise hibernation only if there's enough free swap +- swap: create .wants symlink to 'auto' swap devices +- Verify validity of session name when received from outside +- polkit: Avoid race condition in scraping /proc +Resolves: rhbz#1005142 + +* Fri Sep 13 2013 Harald Hoyer 207-1 +- version 207 + +* Fri Sep 06 2013 Harald Hoyer 206-8 +- support "debug" kernel command line parameter +- journald: fix fd leak in journal_file_empty +- journald: fix vacuuming of archived journals +- libudev: enumerate - do not try to match against an empty subsystem +- cgtop: fixup the online help +- libudev: fix memleak when enumerating childs + +* Wed Aug 28 2013 Harald Hoyer 206-7 +- fixed cgroup hashmap corruption +Resolves: rhbz#997742 rhbz#995197 + +* Fri Aug 23 2013 Harald Hoyer 206-6 +- cgroup.c: check return value of unit_realize_cgroup_now() +Resolves: rhbz#997742 rhbz#995197 + +* Thu Aug 22 2013 Harald Hoyer 206-5 +- obsolete upstart +Resolves: rhbz#978014 +- obsolete hal +Resolves: rhbz#975589 +- service: always unwatch PIDs before forgetting old ones +Resolves: rhbz#995197 +- units: disable kmod-static-nodes.service in containers +- use CAP_MKNOD ConditionCapability +- fstab-generator: read rd.fstab=on/off switch correctly +- backlight: add minimal tool to save/restore screen brightness +- backlight: instead of syspath use sysname for identifying +- sysctl: allow overwriting of values specified in "later" +- systemd-python: fix initialization of _Reader objects +- udevd: simplify sigterm check +- libudev: fix hwdb validation to look for the *new* file +- units: make fsck units remain after exit +- udev: replace CAP_MKNOD by writable /sys condition +- libudev-enumerate.c:udev_enumerate_get_list_entry() fixed +- journal: fix parsing of facility in syslog messages + +* Fri Aug 09 2013 Harald Hoyer 206-4 +- journal: handle multiline syslog messages +- man: Fix copy&paste error +- core: synchronously block when logging +- journal: immediately sync to disk as soon as we receieve an EMERG/ALERT/CRIT message +- initctl: use irreversible jobs when switching runlevels +- udev: log error if chmod/chown of static dev nodes fails +- udev: static_node - don't touch permissions uneccessarily +- tmpfiles: support passing --prefix multiple times +- tmpfiles: introduce --exclude-prefix +- tmpfiles-setup: exclude /dev prefixes files +- logind: update state file after generating the session fifo, not before +- journalctl: use _COMM= match for scripts +- man: systemd.unit: fix volatile path +- man: link up scope+slice units from systemd.unit(5) +- man: there is no session mode, only user mode +- journal: fix hashmap leak in mmap-cache +- systemd-delta: Only print colors when on a tty +- systemd: fix segv in snapshot creation +- udev: hwdb - try reading modalias for usb before falling back to the composed one +- udevd: respect the log-level set in /etc/udev/udev.conf +- fstab-generator: respect noauto/nofail when adding sysroot mount + +* Fri Aug 02 2013 Lukáš Nykrýn - 206-3 +- add dependency on kmod >= 14 +- remove /var/log/journal to make journal non-persistant (#989750) +- add hypervkvpd.service to presets (#924321) + +* Thu Aug 01 2013 Lukáš Nykrýn - 206-2 +- 80-net-name-slot.rules: only rename network interfaces on ACTION==add + +* Tue Jul 23 2013 Kay Sievers - 206-1 +- New upstream release +Resolves (#984152) + +* Wed Jul 3 2013 Lennart Poettering - 205-1 +- New upstream release + +* Wed Jun 26 2013 Michal Schmidt 204-10 +- Split systemd-journal-gateway subpackage (#908081). + +* Mon Jun 24 2013 Michal Schmidt 204-9 +- Rename nm_dispatcher to NetworkManager-dispatcher in default preset (#977433) + +* Fri Jun 14 2013 Harald Hoyer 204-8 +- fix, which helps to sucessfully browse journals with +duplicated seqnums + +* Fri Jun 14 2013 Harald Hoyer 204-7 +- fix duplicate message ID bug +Resolves: rhbz#974132 + +* Thu Jun 06 2013 Harald Hoyer 204-6 +- introduce 99-default-disable.preset + +* Thu Jun 6 2013 Lennart Poettering - 204-5 +- Rename 90-display-manager.preset to 85-display-manager.preset so that it actually takes precedence over 90-default.preset's "disable *" line (#903690) + +* Tue May 28 2013 Harald Hoyer 204-4 +- Fix kernel-install (#965897) + +* Wed May 22 2013 Kay Sievers - 204-3 +- Fix kernel-install (#965897) + +* Thu May 9 2013 Lennart Poettering - 204-2 +- New upstream release +- disable isdn by default (#959793) + +* Tue May 07 2013 Harald Hoyer 203-2 +- forward port kernel-install-grubby.patch + +* Tue May 7 2013 Lennart Poettering - 203-1 +- New upstream release + +* Wed Apr 24 2013 Harald Hoyer 202-3 +- fix ENOENT for getaddrinfo +- Resolves: rhbz#954012 rhbz#956035 +- crypt-setup-generator: correctly check return of strdup +- logind-dbus: initialize result variable +- prevent library underlinking + +* Fri Apr 19 2013 Harald Hoyer 202-2 +- nspawn create empty /etc/resolv.conf if necessary +- python wrapper: add sd_journal_add_conjunction() +- fix s390 booting +- Resolves: rhbz#953217 + +* Thu Apr 18 2013 Lennart Poettering - 202-1 +- New upstream release + +* Tue Apr 09 2013 Michal Schmidt - 201-2 +- Automatically discover whether to run autoreconf and add autotools and git +BuildRequires based on the presence of patches to be applied. +- Use find -delete. + +* Mon Apr 8 2013 Lennart Poettering - 201-1 +- New upstream release + +* Mon Apr 8 2013 Lennart Poettering - 200-4 +- Update preset file + +* Fri Mar 29 2013 Lennart Poettering - 200-3 +- Remove NetworkManager-wait-online.service from presets file again, it should default to off + +* Fri Mar 29 2013 Lennart Poettering - 200-2 +- New upstream release + +* Tue Mar 26 2013 Lennart Poettering - 199-2 +- Add NetworkManager-wait-online.service to the presets file + +* Tue Mar 26 2013 Lennart Poettering - 199-1 +- New upstream release + +* Mon Mar 18 2013 Michal Schmidt 198-7 +- Drop /usr/s?bin/ prefixes. + +* Fri Mar 15 2013 Harald Hoyer 198-6 +- run autogen to pickup all changes + +* Fri Mar 15 2013 Harald Hoyer 198-5 +- do not mount anything, when not running as pid 1 +- add initrd.target for systemd in the initrd + +* Wed Mar 13 2013 Harald Hoyer 198-4 +- fix switch-root and local-fs.target problem +- patch kernel-install to use grubby, if available + +* Fri Mar 08 2013 Harald Hoyer 198-3 +- add Conflict with dracut < 026 because of the new switch-root isolate + +* Thu Mar 7 2013 Lennart Poettering - 198-2 +- Create required users + +* Thu Mar 7 2013 Lennart Poettering - 198-1 +- New release +- Enable journal persistancy by default + +* Sun Feb 10 2013 Peter Robinson 197-3 +- Bump for ARM + +* Fri Jan 18 2013 Michal Schmidt - 197-2 +- Added qemu-guest-agent.service to presets (Lennart, #885406). +- Add missing pygobject3-base to systemd-analyze deps (Lennart). +- Do not require hwdata, it is all in the hwdb now (Kay). +- Drop dependency on dbus-python. + +* Tue Jan 8 2013 Lennart Poettering - 197-1 +- New upstream release + +* Mon Dec 10 2012 Michal Schmidt - 196-4 +- Enable rngd.service by default (#857765). + +* Mon Dec 10 2012 Michal Schmidt - 196-3 +- Disable hardening on s390(x) because PIE is broken there and produces +text relocations with __thread (#868839). + +* Wed Dec 05 2012 Michal Schmidt - 196-2 +- added spice-vdagentd.service to presets (Lennart, #876237) +- BR cryptsetup-devel instead of the legacy cryptsetup-luks-devel provide name +(requested by Milan Brož). +- verbose make to see the actual build flags + +* Wed Nov 21 2012 Lennart Poettering - 196-1 +- New upstream release + +* Tue Nov 20 2012 Lennart Poettering - 195-8 +- https://bugzilla.redhat.com/show_bug.cgi?id=873459 +- https://bugzilla.redhat.com/show_bug.cgi?id=878093 + +* Thu Nov 15 2012 Michal Schmidt - 195-7 +- Revert udev killing cgroup patch for F18 Beta. +- https://bugzilla.redhat.com/show_bug.cgi?id=873576 + +* Fri Nov 09 2012 Michal Schmidt - 195-6 +- Fix cyclical dep between systemd and systemd-libs. +- Avoid broken build of test-journal-syslog. +- https://bugzilla.redhat.com/show_bug.cgi?id=873387 +- https://bugzilla.redhat.com/show_bug.cgi?id=872638 + +* Thu Oct 25 2012 Kay Sievers - 195-5 +- require 'sed', limit HOSTNAME= match + +* Wed Oct 24 2012 Michal Schmidt - 195-4 +- add dmraid-activation.service to the default preset +- add yum protected.d fragment +- https://bugzilla.redhat.com/show_bug.cgi?id=869619 +- https://bugzilla.redhat.com/show_bug.cgi?id=869717 + +* Wed Oct 24 2012 Kay Sievers - 195-3 +- Migrate /etc/sysconfig/ i18n, keyboard, network files/variables to +systemd native files + +* Tue Oct 23 2012 Lennart Poettering - 195-2 +- Provide syslog because the journal is fine as a syslog implementation + +* Tue Oct 23 2012 Lennart Poettering - 195-1 +- New upstream release +- https://bugzilla.redhat.com/show_bug.cgi?id=831665 +- https://bugzilla.redhat.com/show_bug.cgi?id=847720 +- https://bugzilla.redhat.com/show_bug.cgi?id=858693 +- https://bugzilla.redhat.com/show_bug.cgi?id=863481 +- https://bugzilla.redhat.com/show_bug.cgi?id=864629 +- https://bugzilla.redhat.com/show_bug.cgi?id=864672 +- https://bugzilla.redhat.com/show_bug.cgi?id=864674 +- https://bugzilla.redhat.com/show_bug.cgi?id=865128 +- https://bugzilla.redhat.com/show_bug.cgi?id=866346 +- https://bugzilla.redhat.com/show_bug.cgi?id=867407 +- https://bugzilla.redhat.com/show_bug.cgi?id=868603 + +* Wed Oct 10 2012 Michal Schmidt - 194-2 +- Add scriptlets for migration away from systemd-timedated-ntp.target + +* Wed Oct 3 2012 Lennart Poettering - 194-1 +- New upstream release +- https://bugzilla.redhat.com/show_bug.cgi?id=859614 +- https://bugzilla.redhat.com/show_bug.cgi?id=859655 + +* Fri Sep 28 2012 Lennart Poettering - 193-1 +- New upstream release + +* Tue Sep 25 2012 Lennart Poettering - 192-1 +- New upstream release + +* Fri Sep 21 2012 Lennart Poettering - 191-2 +- Fix journal mmap header prototype definition to fix compilation on 32bit + +* Fri Sep 21 2012 Lennart Poettering - 191-1 +- New upstream release +- Enable all display managers by default, as discussed with Adam Williamson + +* Thu Sep 20 2012 Lennart Poettering - 190-1 +- New upstream release +- Take possession of /etc/localtime, and remove /etc/sysconfig/clock +- https://bugzilla.redhat.com/show_bug.cgi?id=858780 +- https://bugzilla.redhat.com/show_bug.cgi?id=858787 +- https://bugzilla.redhat.com/show_bug.cgi?id=858771 +- https://bugzilla.redhat.com/show_bug.cgi?id=858754 +- https://bugzilla.redhat.com/show_bug.cgi?id=858746 +- https://bugzilla.redhat.com/show_bug.cgi?id=858266 +- https://bugzilla.redhat.com/show_bug.cgi?id=858224 +- https://bugzilla.redhat.com/show_bug.cgi?id=857670 +- https://bugzilla.redhat.com/show_bug.cgi?id=856975 +- https://bugzilla.redhat.com/show_bug.cgi?id=855863 +- https://bugzilla.redhat.com/show_bug.cgi?id=851970 +- https://bugzilla.redhat.com/show_bug.cgi?id=851275 +- https://bugzilla.redhat.com/show_bug.cgi?id=851131 +- https://bugzilla.redhat.com/show_bug.cgi?id=847472 +- https://bugzilla.redhat.com/show_bug.cgi?id=847207 +- https://bugzilla.redhat.com/show_bug.cgi?id=846483 +- https://bugzilla.redhat.com/show_bug.cgi?id=846085 +- https://bugzilla.redhat.com/show_bug.cgi?id=845973 +- https://bugzilla.redhat.com/show_bug.cgi?id=845194 +- https://bugzilla.redhat.com/show_bug.cgi?id=845028 +- https://bugzilla.redhat.com/show_bug.cgi?id=844630 +- https://bugzilla.redhat.com/show_bug.cgi?id=839736 +- https://bugzilla.redhat.com/show_bug.cgi?id=835848 +- https://bugzilla.redhat.com/show_bug.cgi?id=831740 +- https://bugzilla.redhat.com/show_bug.cgi?id=823485 +- https://bugzilla.redhat.com/show_bug.cgi?id=821813 +- https://bugzilla.redhat.com/show_bug.cgi?id=807886 +- https://bugzilla.redhat.com/show_bug.cgi?id=802198 +- https://bugzilla.redhat.com/show_bug.cgi?id=767795 +- https://bugzilla.redhat.com/show_bug.cgi?id=767561 +- https://bugzilla.redhat.com/show_bug.cgi?id=752774 +- https://bugzilla.redhat.com/show_bug.cgi?id=732874 +- https://bugzilla.redhat.com/show_bug.cgi?id=858735 + +* Thu Sep 13 2012 Lennart Poettering - 189-4 +- Don't pull in pkg-config as dep +- https://bugzilla.redhat.com/show_bug.cgi?id=852828 + +* Wed Sep 12 2012 Lennart Poettering - 189-3 +- Update preset policy +- Rename preset policy file from 99-default.preset to 90-default.preset so that people can order their own stuff after the Fedora default policy if they wish + +* Thu Aug 23 2012 Lennart Poettering - 189-2 +- Update preset policy +- https://bugzilla.redhat.com/show_bug.cgi?id=850814 + +* Thu Aug 23 2012 Lennart Poettering - 189-1 +- New upstream release + +* Thu Aug 16 2012 Ray Strode 188-4 +- more scriptlet fixes +(move dm migration logic to %%posttrans so the service +files it's looking for are available at the time +the logic is run) + +* Sat Aug 11 2012 Lennart Poettering - 188-3 +- Remount file systems MS_PRIVATE before switching roots +- https://bugzilla.redhat.com/show_bug.cgi?id=847418 + +* Wed Aug 08 2012 Rex Dieter - 188-2 +- fix scriptlets + +* Wed Aug 8 2012 Lennart Poettering - 188-1 +- New upstream release +- Enable gdm and avahi by default via the preset file +- Convert /etc/sysconfig/desktop to display-manager.service symlink +- Enable hardened build + +* Mon Jul 30 2012 Kay Sievers - 187-3 +- Obsolete: system-setup-keyboard + +* Wed Jul 25 2012 Kalev Lember - 187-2 +- Run ldconfig for the new -libs subpackage + +* Thu Jul 19 2012 Lennart Poettering - 187-1 +- New upstream release + +* Mon Jul 09 2012 Harald Hoyer 186-2 +- fixed dracut conflict version + +* Tue Jul 3 2012 Lennart Poettering - 186-1 +- New upstream release + +* Fri Jun 22 2012 Nils Philippsen - 185-7.gite7aee75 +- add obsoletes/conflicts so multilib systemd -> systemd-libs updates work + +* Thu Jun 14 2012 Michal Schmidt - 185-6.gite7aee75 +- Update to current git + +* Wed Jun 06 2012 Kay Sievers - 185-5.gita2368a3 +- disable plymouth in configure, to drop the .wants/ symlinks + +* Wed Jun 06 2012 Michal Schmidt - 185-4.gita2368a3 +- Update to current git snapshot +- Add systemd-readahead-analyze +- Drop upstream patch +- Split systemd-libs +- Drop duplicate doc files +- Fixed License headers of subpackages + +* Wed Jun 06 2012 Ray Strode - 185-3 +- Drop plymouth files +- Conflict with old plymouth + +* Tue Jun 05 2012 Kay Sievers - 185-2 +- selinux udev labeling fix +- conflict with older dracut versions for new udev file names + +* Mon Jun 04 2012 Kay Sievers - 185-1 +- New upstream release +- udev selinux labeling fixes +- new man pages +- systemctl help + +* Thu May 31 2012 Lennart Poettering - 184-1 +- New upstream release + +* Thu May 24 2012 Kay Sievers - 183-1 +- New upstream release including udev merge. + +* Wed Mar 28 2012 Michal Schmidt - 44-4 +- Add triggers from Bill Nottingham to correct the damage done by +the obsoleted systemd-units's preun scriptlet (#807457). + +* Mon Mar 26 2012 Dennis Gilmore - 44-3 +- apply patch from upstream so we can build systemd on arm and ppc +- and likely the rest of the secondary arches + +* Tue Mar 20 2012 Michal Schmidt - 44-2 +- Don't build the gtk parts anymore. They're moving into systemd-ui. +- Remove a dead patch file. + +* Fri Mar 16 2012 Lennart Poettering - 44-1 +- New upstream release +- Closes #798760, #784921, #783134, #768523, #781735 + +* Mon Feb 27 2012 Dennis Gilmore - 43-2 +- don't conflict with fedora-release systemd never actually provided +- /etc/os-release so there is no actual conflict + +* Wed Feb 15 2012 Lennart Poettering - 43-1 +- New upstream release +- Closes #789758, #790260, #790522 + +* Sat Feb 11 2012 Lennart Poettering - 42-1 +- New upstream release +- Save a bit of entropy during system installation (#789407) +- Don't own /etc/os-release anymore, leave that to fedora-release + +* Thu Feb 9 2012 Adam Williamson - 41-2 +- rebuild for fixed binutils + +* Thu Feb 9 2012 Lennart Poettering - 41-1 +- New upstream release + +* Tue Feb 7 2012 Lennart Poettering - 40-1 +- New upstream release + +* Thu Jan 26 2012 Kay Sievers - 39-3 +- provide /sbin/shutdown + +* Wed Jan 25 2012 Harald Hoyer 39-2 +- increment release + +* Wed Jan 25 2012 Kay Sievers - 39-1.1 +- install everything in /usr +https://fedoraproject.org/wiki/Features/UsrMove + +* Wed Jan 25 2012 Lennart Poettering - 39-1 +- New upstream release + +* Sun Jan 22 2012 Michal Schmidt - 38-6.git9fa2f41 +- Update to a current git snapshot. +- Resolves: #781657 + +* Sun Jan 22 2012 Michal Schmidt - 38-5 +- Build against libgee06. Reenable gtk tools. +- Delete unused patches. +- Add easy building of git snapshots. +- Remove legacy spec file elements. +- Don't mention implicit BuildRequires. +- Configure with --disable-static. +- Merge -units into the main package. +- Move section 3 manpages to -devel. +- Fix unowned directory. +- Run ldconfig in scriptlets. +- Split systemd-analyze to a subpackage. + +* Sat Jan 21 2012 Dan Horák - 38-4 +- fix build on big-endians + +* Wed Jan 11 2012 Lennart Poettering - 38-3 +- Disable building of gtk tools for now + +* Wed Jan 11 2012 Lennart Poettering - 38-2 +- Fix a few (build) dependencies + +* Wed Jan 11 2012 Lennart Poettering - 38-1 +- New upstream release + +* Tue Nov 15 2011 Michal Schmidt - 37-4 +- Run authconfig if /etc/pam.d/system-auth is not a symlink. +- Resolves: #753160 + +* Wed Nov 02 2011 Michal Schmidt - 37-3 +- Fix remote-fs-pre.target and its ordering. +- Resolves: #749940 + +* Wed Oct 19 2011 Michal Schmidt - 37-2 +- A couple of fixes from upstream: +- Fix a regression in bash-completion reported in Bodhi. +- Fix a crash in isolating. +- Resolves: #717325 + +* Tue Oct 11 2011 Lennart Poettering - 37-1 +- New upstream release +- Resolves: #744726, #718464, #713567, #713707, #736756 + +* Thu Sep 29 2011 Michal Schmidt - 36-5 +- Undo the workaround. Kay says it does not belong in systemd. +- Unresolves: #741655 + +* Thu Sep 29 2011 Michal Schmidt - 36-4 +- Workaround for the crypto-on-lvm-on-crypto disk layout +- Resolves: #741655 + +* Sun Sep 25 2011 Michal Schmidt - 36-3 +- Revert an upstream patch that caused ordering cycles +- Resolves: #741078 + +* Fri Sep 23 2011 Lennart Poettering - 36-2 +- Add /etc/timezone to ghosted files + +* Fri Sep 23 2011 Lennart Poettering - 36-1 +- New upstream release +- Resolves: #735013, #736360, #737047, #737509, #710487, #713384 + +* Thu Sep 1 2011 Lennart Poettering - 35-1 +- New upstream release +- Update post scripts +- Resolves: #726683, #713384, #698198, #722803, #727315, #729997, #733706, #734611 + +* Thu Aug 25 2011 Lennart Poettering - 34-1 +- New upstream release + +* Fri Aug 19 2011 Harald Hoyer 33-2 +- fix ABRT on service file reloading +- Resolves: rhbz#732020 + +* Wed Aug 3 2011 Lennart Poettering - 33-1 +- New upstream release + +* Fri Jul 29 2011 Lennart Poettering - 32-1 +- New upstream release + +* Wed Jul 27 2011 Lennart Poettering - 31-2 +- Fix access mode of modprobe file, restart logind after upgrade + +* Wed Jul 27 2011 Lennart Poettering - 31-1 +- New upstream release + +* Wed Jul 13 2011 Lennart Poettering - 30-1 +- New upstream release + +* Thu Jun 16 2011 Lennart Poettering - 29-1 +- New upstream release + +* Mon Jun 13 2011 Michal Schmidt - 28-4 +- Apply patches from current upstream. +- Fixes memory size detection on 32-bit with >4GB RAM (BZ712341) + +* Wed Jun 08 2011 Michal Schmidt - 28-3 +- Apply patches from current upstream +- https://bugzilla.redhat.com/show_bug.cgi?id=709909 +- https://bugzilla.redhat.com/show_bug.cgi?id=710839 +- https://bugzilla.redhat.com/show_bug.cgi?id=711015 + +* Sat May 28 2011 Lennart Poettering - 28-2 +- Pull in nss-myhostname + +* Thu May 26 2011 Lennart Poettering - 28-1 +- New upstream release + +* Wed May 25 2011 Lennart Poettering - 26-2 +- Bugfix release +- https://bugzilla.redhat.com/show_bug.cgi?id=707507 +- https://bugzilla.redhat.com/show_bug.cgi?id=707483 +- https://bugzilla.redhat.com/show_bug.cgi?id=705427 +- https://bugzilla.redhat.com/show_bug.cgi?id=707577 + +* Sat Apr 30 2011 Lennart Poettering - 26-1 +- New upstream release +- https://bugzilla.redhat.com/show_bug.cgi?id=699394 +- https://bugzilla.redhat.com/show_bug.cgi?id=698198 +- https://bugzilla.redhat.com/show_bug.cgi?id=698674 +- https://bugzilla.redhat.com/show_bug.cgi?id=699114 +- https://bugzilla.redhat.com/show_bug.cgi?id=699128 + +* Thu Apr 21 2011 Lennart Poettering - 25-1 +- New upstream release +- https://bugzilla.redhat.com/show_bug.cgi?id=694788 +- https://bugzilla.redhat.com/show_bug.cgi?id=694321 +- https://bugzilla.redhat.com/show_bug.cgi?id=690253 +- https://bugzilla.redhat.com/show_bug.cgi?id=688661 +- https://bugzilla.redhat.com/show_bug.cgi?id=682662 +- https://bugzilla.redhat.com/show_bug.cgi?id=678555 +- https://bugzilla.redhat.com/show_bug.cgi?id=628004 + +* Wed Apr 6 2011 Lennart Poettering - 24-1 +- New upstream release +- https://bugzilla.redhat.com/show_bug.cgi?id=694079 +- https://bugzilla.redhat.com/show_bug.cgi?id=693289 +- https://bugzilla.redhat.com/show_bug.cgi?id=693274 +- https://bugzilla.redhat.com/show_bug.cgi?id=693161 + +* Tue Apr 5 2011 Lennart Poettering - 23-1 +- New upstream release +- Include systemd-sysv-convert + +* Fri Apr 1 2011 Lennart Poettering - 22-1 +- New upstream release + +* Wed Mar 30 2011 Lennart Poettering - 21-2 +- The quota services are now pulled in by mount points, hence no need to enable them explicitly + +* Tue Mar 29 2011 Lennart Poettering - 21-1 +- New upstream release + +* Mon Mar 28 2011 Matthias Clasen - 20-2 +- Apply upstream patch to not send untranslated messages to plymouth + +* Tue Mar 8 2011 Lennart Poettering - 20-1 +- New upstream release + +* Tue Mar 1 2011 Lennart Poettering - 19-1 +- New upstream release + +* Wed Feb 16 2011 Lennart Poettering - 18-1 +- New upstream release + +* Mon Feb 14 2011 Bill Nottingham - 17-6 +- bump upstart obsoletes (#676815) + +* Wed Feb 9 2011 Tom Callaway - 17-5 +- add macros.systemd file for %%{_unitdir} + +* Wed Feb 09 2011 Fedora Release Engineering - 17-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Feb 9 2011 Lennart Poettering - 17-3 +- Fix popen() of systemctl, #674916 + +* Mon Feb 7 2011 Bill Nottingham - 17-2 +- add epoch to readahead obsolete + +* Sat Jan 22 2011 Lennart Poettering - 17-1 +- New upstream release + +* Tue Jan 18 2011 Lennart Poettering - 16-2 +- Drop console.conf again, since it is not shipped in pamtmp.conf + +* Sat Jan 8 2011 Lennart Poettering - 16-1 +- New upstream release + +* Thu Nov 25 2010 Lennart Poettering - 15-1 +- New upstream release + +* Thu Nov 25 2010 Lennart Poettering - 14-1 +- Upstream update +- Enable hwclock-load by default +- Obsolete readahead +- Enable /var/run and /var/lock on tmpfs + +* Fri Nov 19 2010 Lennart Poettering - 13-1 +- new upstream release + +* Wed Nov 17 2010 Bill Nottingham 12-3 +- Fix clash + +* Wed Nov 17 2010 Lennart Poettering - 12-2 +- Don't clash with initscripts for now, so that we don't break the builders + +* Wed Nov 17 2010 Lennart Poettering - 12-1 +- New upstream release + +* Fri Nov 12 2010 Matthias Clasen - 11-2 +- Rebuild with newer vala, libnotify + +* Thu Oct 7 2010 Lennart Poettering - 11-1 +- New upstream release + +* Wed Sep 29 2010 Jesse Keating - 10-6 +- Rebuilt for gcc bug 634757 + +* Thu Sep 23 2010 Bill Nottingham - 10-5 +- merge -sysvinit into main package + +* Mon Sep 20 2010 Bill Nottingham - 10-4 +- obsolete upstart-sysvinit too + +* Fri Sep 17 2010 Bill Nottingham - 10-3 +- Drop upstart requires + +* Tue Sep 14 2010 Lennart Poettering - 10-2 +- Enable audit +- https://bugzilla.redhat.com/show_bug.cgi?id=633771 + +* Tue Sep 14 2010 Lennart Poettering - 10-1 +- New upstream release +- https://bugzilla.redhat.com/show_bug.cgi?id=630401 +- https://bugzilla.redhat.com/show_bug.cgi?id=630225 +- https://bugzilla.redhat.com/show_bug.cgi?id=626966 +- https://bugzilla.redhat.com/show_bug.cgi?id=623456 + +* Fri Sep 3 2010 Bill Nottingham - 9-3 +- move fedora-specific units to initscripts; require newer version thereof + +* Fri Sep 3 2010 Lennart Poettering - 9-2 +- Add missing tarball + +* Fri Sep 3 2010 Lennart Poettering - 9-1 +- New upstream version +- Closes 501720, 614619, 621290, 626443, 626477, 627014, 627785, 628913 + +* Fri Aug 27 2010 Lennart Poettering - 8-3 +- Reexecute after installation, take ownership of /var/run/user +- https://bugzilla.redhat.com/show_bug.cgi?id=627457 +- https://bugzilla.redhat.com/show_bug.cgi?id=627634 + +* Thu Aug 26 2010 Lennart Poettering - 8-2 +- Properly create default.target link + +* Wed Aug 25 2010 Lennart Poettering - 8-1 +- New upstream release + +* Thu Aug 12 2010 Lennart Poettering - 7-3 +- Fix https://bugzilla.redhat.com/show_bug.cgi?id=623561 + +* Thu Aug 12 2010 Lennart Poettering - 7-2 +- Fix https://bugzilla.redhat.com/show_bug.cgi?id=623430 + +* Tue Aug 10 2010 Lennart Poettering - 7-1 +- New upstream release + +* Fri Aug 6 2010 Lennart Poettering - 6-2 +- properly hide output on package installation +- pull in coreutils during package installtion + +* Fri Aug 6 2010 Lennart Poettering - 6-1 +- New upstream release +- Fixes #621200 + +* Wed Aug 4 2010 Lennart Poettering - 5-2 +- Add tarball + +* Wed Aug 4 2010 Lennart Poettering - 5-1 +- Prepare release 5 + +* Tue Jul 27 2010 Bill Nottingham - 4-4 +- Add 'sysvinit-userspace' provide to -sysvinit package to fix upgrade/install (#618537) + +* Sat Jul 24 2010 Lennart Poettering - 4-3 +- Add libselinux to build dependencies + +* Sat Jul 24 2010 Lennart Poettering - 4-2 +- Use the right tarball + +* Sat Jul 24 2010 Lennart Poettering - 4-1 +- New upstream release, and make default + +* Tue Jul 13 2010 Lennart Poettering - 3-3 +- Used wrong tarball + +* Tue Jul 13 2010 Lennart Poettering - 3-2 +- Own /cgroup jointly with libcgroup, since we don't dpend on it anymore + +* Tue Jul 13 2010 Lennart Poettering - 3-1 +- New upstream release + +* Fri Jul 9 2010 Lennart Poettering - 2-0 +- New upstream release + +* Wed Jul 7 2010 Lennart Poettering - 1-0 +- First upstream release + +* Tue Jun 29 2010 Lennart Poettering - 0-0.7.20100629git4176e5 +- New snapshot +- Split off -units package where other packages can depend on without pulling in the whole of systemd + +* Tue Jun 22 2010 Lennart Poettering - 0-0.6.20100622gita3723b +- Add missing libtool dependency. + +* Tue Jun 22 2010 Lennart Poettering - 0-0.5.20100622gita3723b +- Update snapshot + +* Mon Jun 14 2010 Rahul Sundaram - 0-0.4.20100614git393024 +- Pull the latest snapshot that fixes a segfault. Resolves rhbz#603231 + +* Fri Jun 11 2010 Rahul Sundaram - 0-0.3.20100610git2f198e +- More minor fixes as per review + +* Thu Jun 10 2010 Rahul Sundaram - 0-0.2.20100610git2f198e +- Spec improvements from David Hollis + +* Wed Jun 09 2010 Rahul Sundaram - 0-0.1.20090609git2f198e +- Address review comments + +* Tue Jun 01 2010 Rahul Sundaram - 0-0.0.git2010-06-02 +- Initial spec (adopted from Kay Sievers)