diff --git a/0001-resolved-Move-symlink-creation-from-tmpfiles-to-daem.patch b/0001-resolved-Move-symlink-creation-from-tmpfiles-to-daem.patch deleted file mode 100644 index 8cb516a..0000000 --- a/0001-resolved-Move-symlink-creation-from-tmpfiles-to-daem.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 73403e8de2c5bc6d54f89ae2f1c9aa12b92ecb7a Mon Sep 17 00:00:00 2001 -From: Colin Walters -Date: Mon, 7 Jul 2014 08:27:43 -0400 -Subject: [PATCH] resolved: Move symlink creation from tmpfiles to daemon - runtime - -At least Fedora right now doesn't by default use resolved; the service -is disabled by default in the 90-default.preset file. - -The change to unconditionally create the resolv.conf symlink broke -Anaconda and related tools (lorax) which expect it to be a regular -file. In particular, Anaconda expects to be able to persist -networking state from the installation environment to the target -system. ---- - tmpfiles.d/etc.conf | 1 - - 2 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/tmpfiles.d/etc.conf b/tmpfiles.d/etc.conf -index b23272cb27..125d6e0a17 100644 ---- a/tmpfiles.d/etc.conf -+++ b/tmpfiles.d/etc.conf -@@ -10,6 +10,5 @@ - L /etc/os-release - - - - ../usr/lib/os-release - L /etc/localtime - - - - ../usr/share/zoneinfo/UTC - L+ /etc/mtab - - - - ../proc/self/mounts --L /etc/resolv.conf - - - - ../run/systemd/resolve/resolv.conf - C /etc/nsswitch.conf - - - - - C /etc/pam.d - - - - --- -1.9.3 - diff --git a/0001-systemctl-fail-in-the-case-that-no-unit-files-were-f.patch b/0001-systemctl-fail-in-the-case-that-no-unit-files-were-f.patch new file mode 100644 index 0000000..b9c05d7 --- /dev/null +++ b/0001-systemctl-fail-in-the-case-that-no-unit-files-were-f.patch @@ -0,0 +1,52 @@ +From fdbdf6ec29bda40763d7d3e7bb2a63e2f5d60c4c Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 19 Aug 2014 20:53:29 +0200 +Subject: [PATCH] systemctl: fail in the case that no unit files were found + +Previously systemctl died with message + +-bash-4.2# systemctl --root /rawhi list-unit-files +(src/systemctl/systemctl.c:868) Out of memory. + +in the case that no unit files were found in the --root +or the directory did not exist. + +So lets return ENOENT in the case that --root does not exist +and empty list in the case that there are no unit files. +--- + src/shared/install.c | 6 ++++++ + src/systemctl/systemctl.c | 4 ++++ + 2 files changed, 10 insertions(+) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 0fe1371129..03c7a9da2e 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2044,6 +2044,12 @@ int unit_file_get_list( + if (root_dir && scope != UNIT_FILE_SYSTEM) + return -EINVAL; + ++ if (root_dir) { ++ r = access(root_dir, F_OK); ++ if (r < 0) ++ return -errno; ++ } ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 36db652316..072f615ad5 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1350,6 +1350,10 @@ static int list_unit_files(sd_bus *bus, char **args) { + } + + n_units = hashmap_size(h); ++ ++ if (n_units == 0) ++ return 0; ++ + units = new(UnitFileList, n_units); + if (!units) { + unit_file_list_free(h); diff --git a/0002-build-remove-repeated-KMOD-section.patch b/0002-build-remove-repeated-KMOD-section.patch new file mode 100644 index 0000000..374c755 --- /dev/null +++ b/0002-build-remove-repeated-KMOD-section.patch @@ -0,0 +1,26 @@ +From 413f6df864083130a380b2f7adbb5aa970139fe7 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 20 Aug 2014 11:25:23 +0200 +Subject: [PATCH] build: remove repeated KMOD section + +--- + src/core/build.h | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/core/build.h b/src/core/build.h +index d380382aba..a7f12a33e4 100644 +--- a/src/core/build.h ++++ b/src/core/build.h +@@ -123,12 +123,6 @@ + #define _KMOD_FEATURE_ "-KMOD" + #endif + +-#ifdef HAVE_KMOD +-#define _KMOD_FEATURE_ "+KMOD" +-#else +-#define _KMOD_FEATURE_ "-KMOD" +-#endif +- + #ifdef HAVE_LIBIDN + #define _IDN_FEATURE_ "+IDN" + #else diff --git a/0002-timesyncd-check-if-stratum-is-valid.patch b/0002-timesyncd-check-if-stratum-is-valid.patch deleted file mode 100644 index 73194e3..0000000 --- a/0002-timesyncd-check-if-stratum-is-valid.patch +++ /dev/null @@ -1,27 +0,0 @@ -From df5380ac8abfc615b4baa0d001afe0e605d34d9b Mon Sep 17 00:00:00 2001 -From: Miroslav Lichvar -Date: Wed, 27 Aug 2014 16:47:17 +0200 -Subject: [PATCH 02/12] timesyncd: check if stratum is valid - -(cherry picked from commit 07610e108e2d3f046da683a3a69c4d5cccd2cf8e) ---- - src/timesync/timesyncd-manager.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index d80c72f..60f39c6 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -574,7 +574,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - return manager_connect(m); - } - -- if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC) { -+ if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC || -+ ntpmsg.stratum == 0 || ntpmsg.stratum >= 16) { - log_debug("Server is not synchronized. Disconnecting."); - return manager_connect(m); - } --- -2.1.0 - diff --git a/0003-machine-id-setup-don-t-try-to-read-UUID-from-VM-cont.patch b/0003-machine-id-setup-don-t-try-to-read-UUID-from-VM-cont.patch new file mode 100644 index 0000000..3cd2b39 --- /dev/null +++ b/0003-machine-id-setup-don-t-try-to-read-UUID-from-VM-cont.patch @@ -0,0 +1,120 @@ +From 5dd6d0f8ff1681fff9369e0aa2532979954dbfde Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 20 Aug 2014 13:49:39 +0200 +Subject: [PATCH] machine-id-setup: don't try to read UUID from VM/container + manager if we operate on a root directory that's not / + +This should make sure no UUID from the host systemd-machine-id-setup is +running on leaks onto a disk image that is provisioned with the tool. +--- + src/core/machine-id-setup.c | 79 +++++++++++++++++++++++---------------------- + 1 file changed, 41 insertions(+), 38 deletions(-) + +diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c +index 712f60cb11..efb074fcbd 100644 +--- a/src/core/machine-id-setup.c ++++ b/src/core/machine-id-setup.c +@@ -64,15 +64,16 @@ static int generate(char id[34], const char *root) { + int fd, r; + unsigned char *p; + sd_id128_t buf; +- char *q; ++ char *q; + ssize_t k; +- const char *vm_id; +- _cleanup_free_ char *dbus_machine_id = NULL; ++ const char *vm_id, *dbus_machine_id; + + assert(id); + +- if (asprintf(&dbus_machine_id, "%s/var/lib/dbus/machine-id", root) < 0) +- return log_oom(); ++ if (isempty(root)) ++ dbus_machine_id = "/var/lib/dbus/machine-id"; ++ else ++ dbus_machine_id = strappenda(root, "/var/lib/dbus/machine-id"); + + /* First, try reading the D-Bus machine id, unless it is a symlink */ + fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); +@@ -93,46 +94,48 @@ static int generate(char id[34], const char *root) { + } + } + +- /* If that didn't work, see if we are running in a container, +- * and a machine ID was passed in via $container_uuid the way +- * libvirt/LXC does it */ +- r = detect_container(NULL); +- if (r > 0) { +- _cleanup_free_ char *e = NULL; +- +- r = getenv_for_pid(1, "container_uuid", &e); ++ if (isempty(root)) { ++ /* If that didn't work, see if we are running in a container, ++ * and a machine ID was passed in via $container_uuid the way ++ * libvirt/LXC does it */ ++ r = detect_container(NULL); + if (r > 0) { +- if (strlen(e) >= 36) { +- r = shorten_uuid(id, e); +- if (r >= 0) { +- log_info("Initializing machine ID from container UUID."); +- return 0; +- } +- } +- } +- +- } else { +- /* If we are not running in a container, see if we are +- * running in qemu/kvm and a machine ID was passed in +- * via -uuid on the qemu/kvm command line */ ++ _cleanup_free_ char *e = NULL; + +- r = detect_vm(&vm_id); +- if (r > 0 && streq(vm_id, "kvm")) { +- char uuid[37]; +- +- fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); +- if (fd >= 0) { +- k = loop_read(fd, uuid, 36, false); +- safe_close(fd); +- +- if (k >= 36) { +- r = shorten_uuid(id, uuid); ++ r = getenv_for_pid(1, "container_uuid", &e); ++ if (r > 0) { ++ if (strlen(e) >= 36) { ++ r = shorten_uuid(id, e); + if (r >= 0) { +- log_info("Initializing machine ID from KVM UUID."); ++ log_info("Initializing machine ID from container UUID."); + return 0; + } + } + } ++ ++ } else { ++ /* If we are not running in a container, see if we are ++ * running in qemu/kvm and a machine ID was passed in ++ * via -uuid on the qemu/kvm command line */ ++ ++ r = detect_vm(&vm_id); ++ if (r > 0 && streq(vm_id, "kvm")) { ++ char uuid[37]; ++ ++ fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); ++ if (fd >= 0) { ++ k = loop_read(fd, uuid, 36, false); ++ safe_close(fd); ++ ++ if (k >= 36) { ++ r = shorten_uuid(id, uuid); ++ if (r >= 0) { ++ log_info("Initializing machine ID from KVM UUID."); ++ return 0; ++ } ++ } ++ } ++ } + } + } + diff --git a/0003-timesyncd-fix-calculation-of-transmit-time.patch b/0003-timesyncd-fix-calculation-of-transmit-time.patch deleted file mode 100644 index 323616c..0000000 --- a/0003-timesyncd-fix-calculation-of-transmit-time.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 6840db7f47122699d420a80c2e6b6a34c7818759 Mon Sep 17 00:00:00 2001 -From: Miroslav Lichvar -Date: Wed, 27 Aug 2014 16:47:18 +0200 -Subject: [PATCH 03/12] timesyncd: fix calculation of transmit time - -The kernel timestamp (recv_time) is made earlier than current time -(now_ts), use the timestamp captured before sending packet directly. - -(cherry picked from commit 73c76e6330d31e1d04454fd7408dd56b4eedca9f) ---- - src/timesync/timesyncd-manager.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index 60f39c6..3339606 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -500,7 +500,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - .msg_namelen = sizeof(server_addr), - }; - struct cmsghdr *cmsg; -- struct timespec now_ts; - struct timeval *recv_time; - ssize_t len; - double origin, receive, trans, dest; -@@ -613,8 +612,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - * The round-trip delay, d, and system clock offset, t, are defined as: - * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2" - */ -- assert_se(clock_gettime(clock_boottime_or_monotonic(), &now_ts) >= 0); -- origin = tv_to_d(recv_time) - (ts_to_d(&now_ts) - ts_to_d(&m->trans_time_mon)) + OFFSET_1900_1970; -+ origin = ts_to_d(&m->trans_time) + OFFSET_1900_1970; - receive = ntp_ts_to_d(&ntpmsg.recv_time); - trans = ntp_ts_to_d(&ntpmsg.trans_time); - dest = tv_to_d(recv_time) + OFFSET_1900_1970; --- -2.1.0 - diff --git a/0004-resolved-dns-rr-fix-typo.patch b/0004-resolved-dns-rr-fix-typo.patch new file mode 100644 index 0000000..d5f4f72 --- /dev/null +++ b/0004-resolved-dns-rr-fix-typo.patch @@ -0,0 +1,36 @@ +From 03664a62914782dbd8f069bbcf8a0c8ca1df7010 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 20 Aug 2014 14:34:23 +0200 +Subject: [PATCH] resolved-dns-rr: fix typo + +a->rrsig.type_covered != a->rrsig.type_covered" is always false +regardless of the values of its operands because those operands are identical. +--- + src/resolve/resolved-dns-rr.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c +index c792deda47..c5f7cb931e 100644 +--- a/src/resolve/resolved-dns-rr.c ++++ b/src/resolve/resolved-dns-rr.c +@@ -425,13 +425,13 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor + + case DNS_TYPE_RRSIG: + /* do the fast comparisons first */ +- if (a->rrsig.type_covered != a->rrsig.type_covered || +- a->rrsig.algorithm != a->rrsig.algorithm || +- a->rrsig.labels != a->rrsig.labels || +- a->rrsig.original_ttl != a->rrsig.original_ttl || +- a->rrsig.expiration != a->rrsig.expiration || +- a->rrsig.inception != a->rrsig.inception || +- a->rrsig.key_tag != a->rrsig.key_tag || ++ if (a->rrsig.type_covered != b->rrsig.type_covered || ++ a->rrsig.algorithm != b->rrsig.algorithm || ++ a->rrsig.labels != b->rrsig.labels || ++ a->rrsig.original_ttl != b->rrsig.original_ttl || ++ a->rrsig.expiration != b->rrsig.expiration || ++ a->rrsig.inception != b->rrsig.inception || ++ a->rrsig.key_tag != b->rrsig.key_tag || + a->rrsig.signature_size != b->rrsig.signature_size || + memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0) + return false; diff --git a/0004-timesyncd-get-kernel-timestamp-in-nanoseconds.patch b/0004-timesyncd-get-kernel-timestamp-in-nanoseconds.patch deleted file mode 100644 index 53e59d3..0000000 --- a/0004-timesyncd-get-kernel-timestamp-in-nanoseconds.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 6ec4258a64383467322da227adfe4780a4777f3a Mon Sep 17 00:00:00 2001 -From: Miroslav Lichvar -Date: Wed, 27 Aug 2014 16:47:19 +0200 -Subject: [PATCH 04/12] timesyncd: get kernel timestamp in nanoseconds - -(cherry picked from commit 487a36821ea214a73e1d0dcbd6d84123b50d1135) ---- - src/timesync/timesyncd-manager.c | 14 +++++--------- - 1 file changed, 5 insertions(+), 9 deletions(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index 3339606..2b0580c 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -136,10 +136,6 @@ static double ts_to_d(const struct timespec *ts) { - return ts->tv_sec + (1.0e-9 * ts->tv_nsec); - } - --static double tv_to_d(const struct timeval *tv) { -- return tv->tv_sec + (1.0e-6 * tv->tv_usec); --} -- - static double square(double d) { - return d * d; - } -@@ -500,7 +496,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - .msg_namelen = sizeof(server_addr), - }; - struct cmsghdr *cmsg; -- struct timeval *recv_time; -+ struct timespec *recv_time; - ssize_t len; - double origin, receive, trans, dest; - double delay, offset; -@@ -543,8 +539,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - continue; - - switch (cmsg->cmsg_type) { -- case SCM_TIMESTAMP: -- recv_time = (struct timeval *) CMSG_DATA(cmsg); -+ case SCM_TIMESTAMPNS: -+ recv_time = (struct timespec *) CMSG_DATA(cmsg); - break; - } - } -@@ -615,7 +611,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - origin = ts_to_d(&m->trans_time) + OFFSET_1900_1970; - receive = ntp_ts_to_d(&ntpmsg.recv_time); - trans = ntp_ts_to_d(&ntpmsg.trans_time); -- dest = tv_to_d(recv_time) + OFFSET_1900_1970; -+ dest = ts_to_d(recv_time) + OFFSET_1900_1970; - - offset = ((receive - origin) + (trans - dest)) / 2; - delay = (dest - origin) - (trans - receive); -@@ -697,7 +693,7 @@ static int manager_listen_setup(Manager *m) { - if (r < 0) - return -errno; - -- r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)); -+ r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMPNS, &on, sizeof(on)); - if (r < 0) - return -errno; - --- -2.1.0 - diff --git a/0005-resolved-fix-which-return-codes-we-check.patch b/0005-resolved-fix-which-return-codes-we-check.patch new file mode 100644 index 0000000..36395e4 --- /dev/null +++ b/0005-resolved-fix-which-return-codes-we-check.patch @@ -0,0 +1,25 @@ +From be754d5443e5fe44ead733ad509b127409cdb0f0 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 20 Aug 2014 14:47:35 +0200 +Subject: [PATCH] resolved: fix which return codes we check + +Discovered by Lukas Nykryn +--- + src/resolve/resolved-dns-domain.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/resolve/resolved-dns-domain.c b/src/resolve/resolved-dns-domain.c +index 6152047ecb..8ed1ecf0a4 100644 +--- a/src/resolve/resolved-dns-domain.c ++++ b/src/resolve/resolved-dns-domain.c +@@ -434,8 +434,8 @@ int dns_name_endswith(const char *name, const char *suffix) { + saved_n = n; + + q = dns_label_unescape(&s, ls, sizeof(ls)); +- if (r < 0) +- return r; ++ if (q < 0) ++ return q; + w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); + if (w < 0) + return w; diff --git a/0005-timesyncd-check-root-distance.patch b/0005-timesyncd-check-root-distance.patch deleted file mode 100644 index a850bc5..0000000 --- a/0005-timesyncd-check-root-distance.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 60bfbd03ff57e6096b13c292ff33fd5570508a05 Mon Sep 17 00:00:00 2001 -From: Miroslav Lichvar -Date: Wed, 27 Aug 2014 16:47:20 +0200 -Subject: [PATCH 05/12] timesyncd: check root distance - -NTPv4 servers don't reply with unsynchronized status when they lost -synchronization, they only keep increasing the root dispersion and it's -up to the client to decide at which point they no longer consider it -synchronized. - -Ignore replies with root distance over 5 seconds. - -(cherry picked from commit 3af0442c52090f34ae7a1c8e6b6587c540c06896) ---- - src/timesync/timesyncd-manager.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index 2b0580c..9b8b7d3 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -89,6 +89,9 @@ - #define NTP_FIELD_MODE(f) ((f) & 7) - #define NTP_FIELD(l, v, m) (((l) << 6) | ((v) << 3) | (m)) - -+/* Maximum acceptable root distance in seconds. */ -+#define NTP_MAX_ROOT_DISTANCE 5.0 -+ - /* - * "NTP timestamps are represented as a 64-bit unsigned fixed-point number, - * in seconds relative to 0h on 1 January 1900." -@@ -128,6 +131,10 @@ struct ntp_msg { - static int manager_arm_timer(Manager *m, usec_t next); - static int manager_clock_watch_setup(Manager *m); - -+static double ntp_ts_short_to_d(const struct ntp_ts_short *ts) { -+ return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0); -+} -+ - static double ntp_ts_to_d(const struct ntp_ts *ts) { - return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX); - } -@@ -500,6 +507,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - ssize_t len; - double origin, receive, trans, dest; - double delay, offset; -+ double root_distance; - bool spike; - int leap_sec; - int r; -@@ -585,6 +593,12 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - return manager_connect(m); - } - -+ root_distance = ntp_ts_short_to_d(&ntpmsg.root_delay) / 2 + ntp_ts_short_to_d(&ntpmsg.root_dispersion); -+ if (root_distance > NTP_MAX_ROOT_DISTANCE) { -+ log_debug("Server has too large root distance. Disconnecting."); -+ return manager_connect(m); -+ } -+ - /* valid packet */ - m->pending = false; - m->retry_interval = 0; -@@ -626,6 +640,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - " mode : %u\n" - " stratum : %u\n" - " precision : %.6f sec (%d)\n" -+ " root distance: %.6f sec\n" - " reference : %.4s\n" - " origin : %.3f\n" - " receive : %.3f\n" -@@ -641,6 +656,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - NTP_FIELD_MODE(ntpmsg.field), - ntpmsg.stratum, - exp2(ntpmsg.precision), ntpmsg.precision, -+ root_distance, - ntpmsg.stratum == 1 ? ntpmsg.refid : "n/a", - origin - OFFSET_1900_1970, - receive - OFFSET_1900_1970, --- -2.1.0 - diff --git a/0006-journal-remote-remove-unreachable-code.patch b/0006-journal-remote-remove-unreachable-code.patch new file mode 100644 index 0000000..f02be65 --- /dev/null +++ b/0006-journal-remote-remove-unreachable-code.patch @@ -0,0 +1,21 @@ +From 7a855149eaf6dbd336d9defab5b4a9c70b75d5e6 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 20 Aug 2014 14:51:27 +0200 +Subject: [PATCH] journal-remote: remove unreachable code + +--- + src/journal-remote/journal-remote.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index aa659d1bd4..7f422bfb37 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -579,7 +579,6 @@ static int request_handler( + log_error("MHD_get_connection_info failed: cannot get remote fd"); + return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, + "Cannot check remote address"); +- return code; + } + + fd = ci->connect_fd; diff --git a/0006-timesyncd-manager-don-t-clear-current_server_name-if.patch b/0006-timesyncd-manager-don-t-clear-current_server_name-if.patch deleted file mode 100644 index 2c6700b..0000000 --- a/0006-timesyncd-manager-don-t-clear-current_server_name-if.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 8573eb093a4ccd6e966b60a68236f403dbd67d56 Mon Sep 17 00:00:00 2001 -From: Steven Noonan -Date: Sat, 30 Aug 2014 05:58:06 -0700 -Subject: [PATCH 06/12] timesyncd-manager: don't clear current_server_name if - ServerAddress is NULL - -https://bugs.freedesktop.org/show_bug.cgi?id=83091 - -[zj: add comment] - -(cherry picked from commit 20f8d3cf1be4ad76234ffb85eeae7f9892ee72cd) ---- - src/timesync/timesyncd-manager.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index 9b8b7d3..696dd10 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -766,8 +766,11 @@ void manager_set_server_address(Manager *m, ServerAddress *a) { - if (m->current_server_address == a) - return; - -- m->current_server_name = a ? a->name : NULL; - m->current_server_address = a; -+ /* If a is NULL, we are just clearing the address, without -+ * changing the name. Keep the existing name in that case. */ -+ if (a) -+ m->current_server_name = a->name; - - manager_disconnect(m); - --- -2.1.0 - diff --git a/0007-timesyncd-wait-before-reconnecting-to-first-server.patch b/0007-timesyncd-wait-before-reconnecting-to-first-server.patch deleted file mode 100644 index 8cdcf97..0000000 --- a/0007-timesyncd-wait-before-reconnecting-to-first-server.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 6aa136216f2f78a840215e53ababeea7b65fc061 Mon Sep 17 00:00:00 2001 -From: Miroslav Lichvar -Date: Wed, 27 Aug 2014 16:47:24 +0200 -Subject: [PATCH 07/12] timesyncd: wait before reconnecting to first server - -When all servers are exhausted, wait for one poll interval before trying -to connect again to the first server in the list. Also, keep increasing -the polling interval to make sure a client not getting any valid replies -will not send requests to any server more frequently than is allowed by -the maximum polling interval. - -(cherry picked from commit 63463bf091949e0178b749016828ec400c106582) ---- - src/timesync/timesyncd-manager.c | 24 +++++++++++++++++++++++- - src/timesync/timesyncd-manager.h | 1 + - 2 files changed, 24 insertions(+), 1 deletion(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index 696dd10..b7b39ef 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -875,6 +875,7 @@ int manager_connect(Manager *m) { - manager_set_server_name(m, m->current_server_name->names_next); - else { - ServerName *f; -+ bool restart = true; - - /* Our current server name list is exhausted, - * let's find the next one to iterate. First -@@ -891,6 +892,8 @@ int manager_connect(Manager *m) { - f = m->link_servers; - if (!f) - f = m->system_servers; -+ else -+ restart = false; - } - - if (!f) -@@ -902,6 +905,25 @@ int manager_connect(Manager *m) { - return 0; - } - -+ if (restart && !m->exhausted_servers && m->poll_interval_usec) { -+ log_debug("Waiting after exhausting servers."); -+ r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + m->poll_interval_usec, 0, manager_retry_connect, m); -+ if (r < 0) { -+ log_error("Failed to create retry timer: %s", strerror(-r)); -+ return r; -+ } -+ -+ m->exhausted_servers = true; -+ -+ /* Increase the polling interval */ -+ if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC) -+ m->poll_interval_usec *= 2; -+ -+ return 0; -+ } -+ -+ m->exhausted_servers = false; -+ - manager_set_server_name(m, f); - } - -@@ -1042,7 +1064,7 @@ static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t re - online = network_is_online(); - - /* check if the client is currently connected */ -- connected = m->server_socket >= 0 || m->resolve_query; -+ connected = m->server_socket >= 0 || m->resolve_query || m->exhausted_servers; - - if (connected && !online) { - log_info("No network connectivity, watching for changes."); -diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h -index 2345bf8..bb3e509 100644 ---- a/src/timesync/timesyncd-manager.h -+++ b/src/timesync/timesyncd-manager.h -@@ -41,6 +41,7 @@ struct Manager { - LIST_HEAD(ServerName, fallback_servers); - - RateLimit ratelimit; -+ bool exhausted_servers; - - /* network */ - sd_event_source *network_event_source; --- -2.1.0 - diff --git a/0007-util-return-after-freeing-all-members-of-array.patch b/0007-util-return-after-freeing-all-members-of-array.patch new file mode 100644 index 0000000..0a6c0ff --- /dev/null +++ b/0007-util-return-after-freeing-all-members-of-array.patch @@ -0,0 +1,27 @@ +From 081e009bef5a09c986bfabdf46e96810afaed1c3 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 20 Aug 2014 15:02:09 +0200 +Subject: [PATCH] util: return after freeing all members of array + +--- + src/shared/util.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 85a570a2a4..9d254e0464 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -7113,10 +7113,10 @@ int unquote_many_words(const char **p, ...) { + if (r < 0) { + int j; + +- for (j = 0; j < c; j++) { ++ for (j = 0; j < c; j++) + free(l[j]); +- return r; +- } ++ ++ return r; + } + + if (r == 0) diff --git a/0008-journal-upload-make-sure-that-r-is-initialized.patch b/0008-journal-upload-make-sure-that-r-is-initialized.patch new file mode 100644 index 0000000..7952e85 --- /dev/null +++ b/0008-journal-upload-make-sure-that-r-is-initialized.patch @@ -0,0 +1,22 @@ +From e1ad6e245dcf63faa8f183063eb97678f4f9ac94 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 20 Aug 2014 15:13:06 +0200 +Subject: [PATCH] journal-upload: make sure that 'r' is initialized + +--- + src/journal-remote/journal-upload.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c +index 7a7aee8170..bdeeff6778 100644 +--- a/src/journal-remote/journal-upload.c ++++ b/src/journal-remote/journal-upload.c +@@ -324,7 +324,7 @@ static int dispatch_fd_input(sd_event_source *event, + } + + static int open_file_for_upload(Uploader *u, const char *filename) { +- int fd, r; ++ int fd, r = 0; + + if (streq(filename, "-")) + fd = STDIN_FILENO; diff --git a/0008-timesyncd-remove-retry_timer-logic-which-is-covered-.patch b/0008-timesyncd-remove-retry_timer-logic-which-is-covered-.patch deleted file mode 100644 index 9f5bea6..0000000 --- a/0008-timesyncd-remove-retry_timer-logic-which-is-covered-.patch +++ /dev/null @@ -1,59 +0,0 @@ -From aebe463f08041d5c38023b414153a79295a5457f Mon Sep 17 00:00:00 2001 -From: Kay Sievers -Date: Tue, 2 Sep 2014 14:27:00 +0200 -Subject: [PATCH 08/12] timesyncd: remove retry_timer logic which is covered by - the server timeout - -(cherry picked from commit 665c6a9eab46b0b253af6566ca9fc70c866b3fcd) ---- - src/timesync/timesyncd-manager.c | 14 -------------- - src/timesync/timesyncd-manager.h | 1 - - 2 files changed, 15 deletions(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index b7b39ef..19a28f3 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -206,19 +206,6 @@ static int manager_send_request(Manager *m) { - return manager_connect(m); - } - -- /* re-arm timer with increasing timeout, in case the packets never arrive back */ -- if (m->retry_interval > 0) { -- if (m->retry_interval < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC) -- m->retry_interval *= 2; -- } else -- m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; -- -- r = manager_arm_timer(m, m->retry_interval); -- if (r < 0) { -- log_error("Failed to rearm timer: %s", strerror(-r)); -- return r; -- } -- - r = sd_event_add_time( - m->event, - &m->event_timeout, -@@ -601,7 +588,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - - /* valid packet */ - m->pending = false; -- m->retry_interval = 0; - - /* announce leap seconds */ - if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC) -diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h -index bb3e509..0ac0e17 100644 ---- a/src/timesync/timesyncd-manager.h -+++ b/src/timesync/timesyncd-manager.h -@@ -59,7 +59,6 @@ struct Manager { - /* last sent packet */ - struct timespec trans_time_mon; - struct timespec trans_time; -- usec_t retry_interval; - bool pending; - - /* poll timer */ --- -2.1.0 - diff --git a/0009-resolved-write-resolv.conf-search-switch-arguments.patch b/0009-resolved-write-resolv.conf-search-switch-arguments.patch new file mode 100644 index 0000000..55961ca --- /dev/null +++ b/0009-resolved-write-resolv.conf-search-switch-arguments.patch @@ -0,0 +1,26 @@ +From a9feff3d774eaa1cc1b59189e8f344c01e69f888 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 20 Aug 2014 15:56:14 +0200 +Subject: [PATCH] resolved: write resolv.conf search - switch arguments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Found by Lukáš Nykrýn. +--- + src/resolve/resolved-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index 04ee204074..56baf8730d 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -699,7 +699,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { + } + + static void write_resolv_conf_search(const char *domain, FILE *f, +- unsigned *length, unsigned *count) { ++ unsigned *count, unsigned *length) { + assert(domain); + assert(f); + assert(length); diff --git a/0009-timesyncd-allow-two-missed-replies-before-reselectin.patch b/0009-timesyncd-allow-two-missed-replies-before-reselectin.patch deleted file mode 100644 index 5b76446..0000000 --- a/0009-timesyncd-allow-two-missed-replies-before-reselectin.patch +++ /dev/null @@ -1,90 +0,0 @@ -From e558311df376973727c9924c1416a2101e55673d Mon Sep 17 00:00:00 2001 -From: Miroslav Lichvar -Date: Tue, 2 Sep 2014 14:29:51 +0200 -Subject: [PATCH 09/12] timesyncd: allow two missed replies before reselecting - server - -After receiving a reply from the server, allow two missed replies before -switching to another server to avoid unnecessary clock hopping when -packets are getting lost in the network. - -(cherry picked from commit e8206972be6a7ebeb198cd0d400bc7a94a6a5fc5) ---- - src/timesync/timesyncd-manager.c | 27 ++++++++++++++++++--------- - src/timesync/timesyncd-manager.h | 1 + - 2 files changed, 19 insertions(+), 9 deletions(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index 19a28f3..a66852d 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -92,6 +92,9 @@ - /* Maximum acceptable root distance in seconds. */ - #define NTP_MAX_ROOT_DISTANCE 5.0 - -+/* Maximum number of missed replies before selecting another source. */ -+#define NTP_MAX_MISSED_REPLIES 2 -+ - /* - * "NTP timestamps are represented as a 64-bit unsigned fixed-point number, - * in seconds relative to 0h on 1 January 1900." -@@ -206,15 +209,18 @@ static int manager_send_request(Manager *m) { - return manager_connect(m); - } - -- r = sd_event_add_time( -- m->event, -- &m->event_timeout, -- clock_boottime_or_monotonic(), -- now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0, -- manager_timeout, m); -- if (r < 0) { -- log_error("Failed to arm timeout timer: %s", strerror(-r)); -- return r; -+ m->missed_replies++; -+ if (m->missed_replies > NTP_MAX_MISSED_REPLIES) { -+ r = sd_event_add_time( -+ m->event, -+ &m->event_timeout, -+ clock_boottime_or_monotonic(), -+ now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0, -+ manager_timeout, m); -+ if (r < 0) { -+ log_error("Failed to arm timeout timer: %s", strerror(-r)); -+ return r; -+ } - } - - return 0; -@@ -549,6 +555,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - return 0; - } - -+ m->missed_replies = 0; -+ - /* check our "time cookie" (we just stored nanoseconds in the fraction field) */ - if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 || - be32toh(ntpmsg.origin_time.frac) != m->trans_time.tv_nsec) { -@@ -712,6 +720,7 @@ static int manager_begin(Manager *m) { - assert_return(m->current_server_name, -EHOSTUNREACH); - assert_return(m->current_server_address, -EHOSTUNREACH); - -+ m->missed_replies = NTP_MAX_MISSED_REPLIES; - m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; - - server_address_pretty(m->current_server_address, &pretty); -diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h -index 0ac0e17..8296d41 100644 ---- a/src/timesync/timesyncd-manager.h -+++ b/src/timesync/timesyncd-manager.h -@@ -53,6 +53,7 @@ struct Manager { - ServerName *current_server_name; - ServerAddress *current_server_address; - int server_socket; -+ int missed_replies; - uint64_t packet_count; - sd_event_source *event_timeout; - --- -2.1.0 - diff --git a/0010-sd-event-add-API-to-access-epoll_fd.patch b/0010-sd-event-add-API-to-access-epoll_fd.patch new file mode 100644 index 0000000..00903c6 --- /dev/null +++ b/0010-sd-event-add-API-to-access-epoll_fd.patch @@ -0,0 +1,56 @@ +From 9b364545435d2b65fcf73519b3064bb7c28093b7 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 15 Aug 2014 21:04:07 +0200 +Subject: [PATCH] sd-event: add API to access epoll_fd + +This is a prerequisite for integrating sd-event into an external +event loop. +--- + src/libsystemd/libsystemd.sym.m4 | 1 + + src/libsystemd/sd-event/sd-event.c | 8 ++++++++ + src/systemd/sd-event.h | 1 + + 3 files changed, 10 insertions(+) + +diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 +index 415d89afbe..3fc9983f98 100644 +--- a/src/libsystemd/libsystemd.sym.m4 ++++ b/src/libsystemd/libsystemd.sym.m4 +@@ -374,6 +374,7 @@ global: + sd_event_loop; + sd_event_exit; + sd_event_now; ++ sd_event_get_fd; + sd_event_get_state; + sd_event_get_tid; + sd_event_get_exit_code; +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 7917ab934a..e062997a80 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2361,6 +2361,14 @@ finish: + return r; + } + ++_public_ int sd_event_get_fd(sd_event *e) { ++ ++ assert_return(e, -EINVAL); ++ assert_return(!event_pid_changed(e), -ECHILD); ++ ++ return e->epoll_fd; ++} ++ + _public_ int sd_event_get_state(sd_event *e) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index 5d9b3be6c7..d96852a763 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -90,6 +90,7 @@ int sd_event_exit(sd_event *e, int code); + + int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec); + ++int sd_event_get_fd(sd_event *e); + int sd_event_get_state(sd_event *e); + int sd_event_get_tid(sd_event *e, pid_t *tid); + int sd_event_get_exit_code(sd_event *e, int *code); diff --git a/0010-timesyncd-don-t-reset-polling-interval-when-reselect.patch b/0010-timesyncd-don-t-reset-polling-interval-when-reselect.patch deleted file mode 100644 index a16c58b..0000000 --- a/0010-timesyncd-don-t-reset-polling-interval-when-reselect.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0c4d8d57d2581ea8e90f5b22ac81b249b6b28671 Mon Sep 17 00:00:00 2001 -From: Kay Sievers -Date: Tue, 2 Sep 2014 14:33:59 +0200 -Subject: [PATCH 10/12] timesyncd: don't reset polling interval when - reselecting server - -Original patch from: Miroslav Lichvar - -(cherry picked from commit 80cd2606b91ce2735a0609c6f964917cf12685aa) ---- - src/timesync/timesyncd-manager.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index a66852d..3261bc1 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -721,7 +721,8 @@ static int manager_begin(Manager *m) { - assert_return(m->current_server_address, -EHOSTUNREACH); - - m->missed_replies = NTP_MAX_MISSED_REPLIES; -- m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; -+ if (m->poll_interval_usec == 0) -+ m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; - - server_address_pretty(m->current_server_address, &pretty); - log_info("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string); --- -2.1.0 - diff --git a/0011-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch b/0011-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch deleted file mode 100644 index 8a8d47c..0000000 --- a/0011-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 1d282632e027281c81a97c2bf2d7a803553651dc Mon Sep 17 00:00:00 2001 -From: Kay Sievers -Date: Tue, 2 Sep 2014 15:28:56 +0200 -Subject: [PATCH 11/12] Revert "timesyncd: remove retry_timer logic which is - covered by the server timeout" - -This reverts commit 665c6a9eab46b0b253af6566ca9fc70c866b3fcd. - -On Tue, Sep 2, 2014 at 3:17 PM, Miroslav Lichvar wrote: -> -> With the other patch allowing missed replies included it's now getting -> stuck as there is no timer to send the 2nd and 3rd request. - -(cherry picked from commit ab4df227d466e881e4279821b5fc1563f0e7e933) ---- - src/timesync/timesyncd-manager.c | 14 ++++++++++++++ - src/timesync/timesyncd-manager.h | 1 + - 2 files changed, 15 insertions(+) - -diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c -index 3261bc1..a5678cc 100644 ---- a/src/timesync/timesyncd-manager.c -+++ b/src/timesync/timesyncd-manager.c -@@ -209,6 +209,19 @@ static int manager_send_request(Manager *m) { - return manager_connect(m); - } - -+ /* re-arm timer with increasing timeout, in case the packets never arrive back */ -+ if (m->retry_interval > 0) { -+ if (m->retry_interval < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC) -+ m->retry_interval *= 2; -+ } else -+ m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; -+ -+ r = manager_arm_timer(m, m->retry_interval); -+ if (r < 0) { -+ log_error("Failed to rearm timer: %s", strerror(-r)); -+ return r; -+ } -+ - m->missed_replies++; - if (m->missed_replies > NTP_MAX_MISSED_REPLIES) { - r = sd_event_add_time( -@@ -596,6 +609,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re - - /* valid packet */ - m->pending = false; -+ m->retry_interval = 0; - - /* announce leap seconds */ - if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC) -diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h -index 8296d41..c7efdc5 100644 ---- a/src/timesync/timesyncd-manager.h -+++ b/src/timesync/timesyncd-manager.h -@@ -60,6 +60,7 @@ struct Manager { - /* last sent packet */ - struct timespec trans_time_mon; - struct timespec trans_time; -+ usec_t retry_interval; - bool pending; - - /* poll timer */ --- -2.1.0 - diff --git a/0011-journalctl-add-t-identifier-STRING-option.patch b/0011-journalctl-add-t-identifier-STRING-option.patch new file mode 100644 index 0000000..688d202 --- /dev/null +++ b/0011-journalctl-add-t-identifier-STRING-option.patch @@ -0,0 +1,143 @@ +From 730836403aee5f5bb998e6e3622ea7068fce0699 Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Tue, 19 Aug 2014 11:27:34 +0200 +Subject: [PATCH] journalctl: add "-t --identifier=STRING" option + +This turns journalctl to the counterpart of systemd-cat. +Messages sent with + +systemd-cat --identifier foo --prioritiy debug + +can now be shown with + +journalctl --identifier foo --prioritiy debug + +"--identifier" is not merged with "--unit" to make a clear +distinction between syslog and systemd units. +syslog identifiers can be chosen freely by anyone. +--- + man/journalctl.xml | 14 ++++++++++++++ + src/journal/journalctl.c | 43 ++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 56 insertions(+), 1 deletion(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index e10918a9c6..d4e031619a 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -498,6 +498,20 @@ + + + ++ ++ ++ ++ Show messages for the ++ specified syslog identifier ++ SYSLOG_IDENTIFIER, or ++ for any of the messages with a SYSLOG_IDENTIFIER ++ matched by PATTERN. ++ ++ This parameter can be specified ++ multiple times. ++ ++ ++ + + + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 5c4a71d618..f3680d1ce2 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -89,6 +89,7 @@ static bool arg_force = false; + #endif + static usec_t arg_since, arg_until; + static bool arg_since_set = false, arg_until_set = false; ++static char **arg_syslog_identifier = NULL; + static char **arg_system_units = NULL; + static char **arg_user_units = NULL; + static const char *arg_field = NULL; +@@ -180,6 +181,7 @@ static void help(void) { + " -k --dmesg Show kernel message log from the current boot\n" + " -u --unit=UNIT Show data only from the specified unit\n" + " --user-unit=UNIT Show data only from the specified user session unit\n" ++ " -t --identifier=STRING Show only messages with the specified syslog identifier\n" + " -p --priority=RANGE Show only messages within the specified priority range\n" + " -e --pager-end Immediately jump to end of the journal in the pager\n" + " -f --follow Follow the journal\n" +@@ -276,6 +278,7 @@ static int parse_argv(int argc, char *argv[]) { + { "file", required_argument, NULL, ARG_FILE }, + { "root", required_argument, NULL, ARG_ROOT }, + { "header", no_argument, NULL, ARG_HEADER }, ++ { "identifier", required_argument, NULL, 't' }, + { "priority", required_argument, NULL, 'p' }, + { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, + { "interval", required_argument, NULL, ARG_INTERVAL }, +@@ -304,7 +307,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:u:F:xrM:", options, NULL)) >= 0) ++ while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0) + + switch (c) { + +@@ -590,6 +593,12 @@ static int parse_argv(int argc, char *argv[]) { + arg_until_set = true; + break; + ++ case 't': ++ r = strv_extend(&arg_syslog_identifier, optarg); ++ if (r < 0) ++ return log_oom(); ++ break; ++ + case 'u': + r = strv_extend(&arg_system_units, optarg); + if (r < 0) +@@ -1212,6 +1221,32 @@ static int add_priorities(sd_journal *j) { + return 0; + } + ++ ++static int add_syslog_identifier(sd_journal *j) { ++ int r; ++ char **i; ++ ++ assert(j); ++ ++ STRV_FOREACH(i, arg_syslog_identifier) { ++ char *u; ++ ++ u = strappenda("SYSLOG_IDENTIFIER=", *i); ++ r = sd_journal_add_match(j, u, 0); ++ if (r < 0) ++ return r; ++ r = sd_journal_add_disjunction(j); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_journal_add_conjunction(j); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ + static int setup_keys(void) { + #ifdef HAVE_GCRYPT + size_t mpk_size, seed_size, state_size, i; +@@ -1705,6 +1740,12 @@ int main(int argc, char *argv[]) { + return EXIT_FAILURE; + } + ++ r = add_syslog_identifier(j); ++ if (r < 0) { ++ log_error("Failed to add filter for syslog identifiers: %s", strerror(-r)); ++ return EXIT_FAILURE; ++ } ++ + r = add_priorities(j); + if (r < 0) { + log_error("Failed to add filter for priorities: %s", strerror(-r)); diff --git a/0012-CODING_STYLE-document-that-we-don-t-break-lines-at-8.patch b/0012-CODING_STYLE-document-that-we-don-t-break-lines-at-8.patch new file mode 100644 index 0000000..9f7f02d --- /dev/null +++ b/0012-CODING_STYLE-document-that-we-don-t-break-lines-at-8.patch @@ -0,0 +1,24 @@ +From 3fdbc8205885f117b7dea289b44217310663e731 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:10:37 +0200 +Subject: [PATCH] CODING_STYLE: document that we don't break lines at 80ch + +--- + CODING_STYLE | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/CODING_STYLE b/CODING_STYLE +index ca3b5183f9..a3fc26c1e1 100644 +--- a/CODING_STYLE ++++ b/CODING_STYLE +@@ -1,6 +1,9 @@ +- + - 8ch indent, no tabs + ++- Don't break code lines too eagerly. We do *not* force line breaks at ++ 80ch, all of today's screens should be much larger than that. But ++ then again, don't overdo it, ~140ch should be enough really. ++ + - Variables and functions *must* be static, unless they have a + prototype, and are supposed to be exported. + diff --git a/0013-util-change-return-value-of-startswith-to-non-const.patch b/0013-util-change-return-value-of-startswith-to-non-const.patch new file mode 100644 index 0000000..bf993a5 --- /dev/null +++ b/0013-util-change-return-value-of-startswith-to-non-const.patch @@ -0,0 +1,48 @@ +From 11adc1aef7a1a6e9ba3fda8eb34eb5fadedc0385 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:10:59 +0200 +Subject: [PATCH] util: change return value of startswith() to non-const + +This way we can use it on non-const strings, and don't end up with a +const'ified result. + +This is similar to libc's strstr() which also takes a const string but +returns a non-const one. +--- + src/shared/util.h | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/src/shared/util.h b/src/shared/util.h +index 87ad317319..8cd47b8294 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -158,15 +158,23 @@ static inline bool isempty(const char *p) { + return !p || !p[0]; + } + +-static inline const char *startswith(const char *s, const char *prefix) { +- if (strncmp(s, prefix, strlen(prefix)) == 0) +- return s + strlen(prefix); ++static inline char *startswith(const char *s, const char *prefix) { ++ size_t l; ++ ++ l = strlen(prefix); ++ if (strncmp(s, prefix, l) == 0) ++ return (char*) s + l; ++ + return NULL; + } + +-static inline const char *startswith_no_case(const char *s, const char *prefix) { +- if (strncasecmp(s, prefix, strlen(prefix)) == 0) +- return s + strlen(prefix); ++static inline char *startswith_no_case(const char *s, const char *prefix) { ++ size_t l; ++ ++ l = strlen(prefix); ++ if (strncasecmp(s, prefix, l) == 0) ++ return (char*) s + l; ++ + return NULL; + } + diff --git a/0014-util-simplify-close_nointr-a-bit.patch b/0014-util-simplify-close_nointr-a-bit.patch new file mode 100644 index 0000000..11128bc --- /dev/null +++ b/0014-util-simplify-close_nointr-a-bit.patch @@ -0,0 +1,55 @@ +From a9f85faf43ae2289e19ba9105c36496aefe66072 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:13:15 +0200 +Subject: [PATCH] util: simplify close_nointr() a bit + +--- + src/shared/util.c | 33 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 17 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 9d254e0464..a54e879953 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -175,25 +175,24 @@ char* first_word(const char *s, const char *word) { + } + + int close_nointr(int fd) { +- int r; +- + assert(fd >= 0); +- r = close(fd); +- if (r >= 0) +- return r; +- else if (errno == EINTR) +- /* +- * Just ignore EINTR; a retry loop is the wrong +- * thing to do on Linux. +- * +- * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html +- * https://bugzilla.gnome.org/show_bug.cgi?id=682819 +- * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR +- * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain +- */ ++ ++ if (close(fd) >= 0) + return 0; +- else +- return -errno; ++ ++ /* ++ * Just ignore EINTR; a retry loop is the wrong thing to do on ++ * Linux. ++ * ++ * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html ++ * https://bugzilla.gnome.org/show_bug.cgi?id=682819 ++ * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR ++ * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain ++ */ ++ if (errno == EINTR) ++ return 0; ++ ++ return -errno; + } + + int safe_close(int fd) { diff --git a/0015-util-make-asynchronous_close-really-work-like-an-asy.patch b/0015-util-make-asynchronous_close-really-work-like-an-asy.patch new file mode 100644 index 0000000..5be3bf6 --- /dev/null +++ b/0015-util-make-asynchronous_close-really-work-like-an-asy.patch @@ -0,0 +1,42 @@ +From 5ed1227238724959f020169f5332086439709b55 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:13:43 +0200 +Subject: [PATCH] util: make asynchronous_close() really work like an + asynchronous version of safe_close() + +Save/restore errno, like we do in safe_close(). And don't fork a thread +if the parameter is already negative. +--- + src/shared/async.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/shared/async.c b/src/shared/async.c +index 3876deda70..115901e637 100644 +--- a/src/shared/async.c ++++ b/src/shared/async.c +@@ -73,7 +73,7 @@ int asynchronous_sync(void) { + } + + static void *close_thread(void *p) { +- safe_close(PTR_TO_INT(p)); ++ assert_se(close_nointr(PTR_TO_INT(p)) != -EBADF); + return NULL; + } + +@@ -86,9 +86,13 @@ int asynchronous_close(int fd) { + * but it doesn't, so we work around it, and hide this as a + * far away as we can. */ + +- r = asynchronous_job(close_thread, INT_TO_PTR(fd)); +- if (r < 0) +- safe_close(fd); ++ if (fd >= 0) { ++ PROTECT_ERRNO; ++ ++ r = asynchronous_job(close_thread, INT_TO_PTR(fd)); ++ if (r < 0) ++ assert_se(close_nointr(fd) != -EBADF); ++ } + + return -1; + } diff --git a/0016-core-unify-how-we-generate-the-prefix-string-when-du.patch b/0016-core-unify-how-we-generate-the-prefix-string-when-du.patch new file mode 100644 index 0000000..80fcc99 --- /dev/null +++ b/0016-core-unify-how-we-generate-the-prefix-string-when-du.patch @@ -0,0 +1,127 @@ +From 4c94096027f21d4ed0efe991534a926d39d52369 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:15:49 +0200 +Subject: [PATCH] core: unify how we generate the prefix string when dumping + unit state + +--- + src/core/execute.c | 19 ++++++------------- + src/core/service.c | 6 ++---- + src/core/socket.c | 1 + + src/core/unit.c | 7 ++----- + 4 files changed, 11 insertions(+), 22 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index d8452a666c..2544a2470c 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2398,12 +2398,11 @@ void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) { + assert(s); + assert(f); + +- if (!prefix) +- prefix = ""; +- + if (s->pid <= 0) + return; + ++ prefix = strempty(prefix); ++ + fprintf(f, + "%sPID: "PID_FMT"\n", + prefix, s->pid); +@@ -2463,21 +2462,16 @@ char *exec_command_line(char **argv) { + } + + void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) { +- _cleanup_free_ char *p2 = NULL; +- const char *prefix2; +- + _cleanup_free_ char *cmd = NULL; ++ const char *prefix2; + + assert(c); + assert(f); + +- if (!prefix) +- prefix = ""; +- p2 = strappend(prefix, "\t"); +- prefix2 = p2 ? p2 : prefix; ++ prefix = strempty(prefix); ++ prefix2 = strappenda(prefix, "\t"); + + cmd = exec_command_line(c->argv); +- + fprintf(f, + "%sCommand Line: %s\n", + prefix, cmd ? cmd : strerror(ENOMEM)); +@@ -2488,8 +2482,7 @@ void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) { + void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) { + assert(f); + +- if (!prefix) +- prefix = ""; ++ prefix = strempty(prefix); + + LIST_FOREACH(command, c, c) + exec_command_dump(c, f, prefix); +diff --git a/src/core/service.c b/src/core/service.c +index 6a4665a1ae..887b1c8514 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -463,16 +463,14 @@ static int service_load(Unit *u) { + } + + static void service_dump(Unit *u, FILE *f, const char *prefix) { +- + ServiceExecCommand c; + Service *s = SERVICE(u); + const char *prefix2; +- _cleanup_free_ char *p2 = NULL; + + assert(s); + +- p2 = strappend(prefix, "\t"); +- prefix2 = p2 ? p2 : prefix; ++ prefix = strempty(prefix); ++ prefix2 = strappenda(prefix, "\t"); + + fprintf(f, + "%sService State: %s\n" +diff --git a/src/core/socket.c b/src/core/socket.c +index 1189f451d2..7ca8edbda8 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -471,6 +471,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { + assert(s); + assert(f); + ++ prefix = strempty(prefix); + prefix2 = strappenda(prefix, "\t"); + + fprintf(f, +diff --git a/src/core/unit.c b/src/core/unit.c +index 08e74b4160..56102b360d 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -791,7 +791,6 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { + char *t, **j; + UnitDependency d; + Iterator i; +- _cleanup_free_ char *p2 = NULL; + const char *prefix2; + char + timestamp1[FORMAT_TIMESTAMP_MAX], +@@ -806,10 +805,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { + assert(u); + assert(u->type >= 0); + +- if (!prefix) +- prefix = ""; +- p2 = strappend(prefix, "\t"); +- prefix2 = p2 ? p2 : prefix; ++ prefix = strempty(prefix); ++ prefix2 = strappenda(prefix, "\t"); + + fprintf(f, + "%s-> Unit %s:\n" diff --git a/0017-service-asynchronous_close-already-checks-for-negati.patch b/0017-service-asynchronous_close-already-checks-for-negati.patch new file mode 100644 index 0000000..1b6a2bf --- /dev/null +++ b/0017-service-asynchronous_close-already-checks-for-negati.patch @@ -0,0 +1,24 @@ +From abb4c1cc0161cc6b371ee7ea2550df17a3bfc21e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:17:02 +0200 +Subject: [PATCH] service: asynchronous_close() already checks for negative + parameters, no need to duplicate that + +--- + src/core/service.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 887b1c8514..008e81437d 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -180,9 +180,6 @@ static int service_set_main_pid(Service *s, pid_t pid) { + static void service_close_socket_fd(Service *s) { + assert(s); + +- if (s->socket_fd < 0) +- return; +- + s->socket_fd = asynchronous_close(s->socket_fd); + } + diff --git a/0018-service-remove-some-pointless-linebreaks-to-make-thi.patch b/0018-service-remove-some-pointless-linebreaks-to-make-thi.patch new file mode 100644 index 0000000..17b76ec --- /dev/null +++ b/0018-service-remove-some-pointless-linebreaks-to-make-thi.patch @@ -0,0 +1,526 @@ +From 8bb2d17d2b89e87b2e9d8f6c147a757f4670b0fc Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:19:25 +0200 +Subject: [PATCH] service: remove some pointless linebreaks, to make things + more readable + +--- + src/core/service.c | 200 +++++++++++++++++------------------------------------ + 1 file changed, 65 insertions(+), 135 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 008e81437d..f10582d89e 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -135,8 +135,7 @@ static void service_unwatch_pid_file(Service *s) { + if (!s->pid_file_pathspec) + return; + +- log_debug_unit(UNIT(s)->id, "Stopping watch for %s's PID file %s", +- UNIT(s)->id, s->pid_file_pathspec->path); ++ log_debug_unit(UNIT(s)->id, "Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path); + path_spec_unwatch(s->pid_file_pathspec); + path_spec_done(s->pid_file_pathspec); + free(s->pid_file_pathspec); +@@ -166,10 +165,7 @@ static int service_set_main_pid(Service *s, pid_t pid) { + s->main_pid_known = true; + + if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) { +- log_warning_unit(UNIT(s)->id, +- "%s: Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", +- UNIT(s)->id, pid); +- ++ log_warning_unit(UNIT(s)->id, "%s: Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", UNIT(s)->id, pid); + s->main_pid_alien = true; + } else + s->main_pid_alien = false; +@@ -362,14 +358,12 @@ static int service_add_default_dependencies(Service *s) { + * majority of services. */ + + /* First, pull in base system */ +- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, +- SPECIAL_BASIC_TARGET, NULL, true); ++ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true); + if (r < 0) + return r; + + /* Second, activate normal shutdown */ +- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, +- SPECIAL_SHUTDOWN_TARGET, NULL, true); ++ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); + return r; + } + +@@ -392,8 +386,8 @@ static void service_fix_output(Service *s) { + } + + static int service_load(Unit *u) { +- int r; + Service *s = SERVICE(u); ++ int r; + + assert(s); + +@@ -556,25 +550,20 @@ static int service_load_pid_file(Service *s, bool may_warn) { + r = read_one_line_file(s->pid_file, &k); + if (r < 0) { + if (may_warn) +- log_info_unit(UNIT(s)->id, +- "PID file %s not readable (yet?) after %s.", +- s->pid_file, service_state_to_string(s->state)); ++ log_info_unit(UNIT(s)->id, "PID file %s not readable (yet?) after %s.", s->pid_file, service_state_to_string(s->state)); + return r; + } + + r = parse_pid(k, &pid); + if (r < 0) { + if (may_warn) +- log_info_unit(UNIT(s)->id, +- "Failed to read PID from file %s: %s", +- s->pid_file, strerror(-r)); ++ log_info_unit(UNIT(s)->id, "Failed to read PID from file %s: %s", s->pid_file, strerror(-r)); + return r; + } + + if (!pid_is_alive(pid)) { + if (may_warn) + log_info_unit(UNIT(s)->id, "PID "PID_FMT" read from file %s does not exist or is a zombie.", pid, s->pid_file); +- + return -ESRCH; + } + +@@ -582,14 +571,12 @@ static int service_load_pid_file(Service *s, bool may_warn) { + if (pid == s->main_pid) + return 0; + +- log_debug_unit(UNIT(s)->id, +- "Main PID changing: "PID_FMT" -> "PID_FMT, +- s->main_pid, pid); ++ log_debug_unit(UNIT(s)->id, "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid); ++ + service_unwatch_main_pid(s); + s->main_pid_known = false; + } else +- log_debug_unit(UNIT(s)->id, +- "Main PID loaded: "PID_FMT, pid); ++ log_debug_unit(UNIT(s)->id, "Main PID loaded: "PID_FMT, pid); + + r = service_set_main_pid(s, pid); + if (r < 0) +@@ -598,9 +585,7 @@ static int service_load_pid_file(Service *s, bool may_warn) { + r = unit_watch_pid(UNIT(s), pid); + if (r < 0) { + /* FIXME: we need to do something here */ +- log_warning_unit(UNIT(s)->id, +- "Failed to watch PID "PID_FMT" from service %s", +- pid, UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id); + return r; + } + +@@ -627,19 +612,19 @@ static int service_search_main_pid(Service *s) { + if (pid <= 0) + return -ENOENT; + +- log_debug_unit(UNIT(s)->id, +- "Main PID guessed: "PID_FMT, pid); ++ log_debug_unit(UNIT(s)->id, "Main PID guessed: "PID_FMT, pid); + r = service_set_main_pid(s, pid); + if (r < 0) + return r; + + r = unit_watch_pid(UNIT(s), pid); +- if (r < 0) ++ if (r < 0) { + /* FIXME: we need to do something here */ +- log_warning_unit(UNIT(s)->id, +- "Failed to watch PID "PID_FMT" from service %s", +- pid, UNIT(s)->id); +- return r; ++ log_warning_unit(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id); ++ return r; ++ } ++ ++ return 0; + } + + static void service_set_state(Service *s, ServiceState state) { +@@ -1096,9 +1081,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run install restart timer: %s", +- UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run install restart timer: %s", UNIT(s)->id, strerror(-r)); + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false); + } + +@@ -1136,9 +1119,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run 'stop-post' task: %s", +- UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); + } + +@@ -1183,8 +1164,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); + + if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) + service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES); +@@ -1227,8 +1207,7 @@ static void service_enter_stop(Service *s, ServiceResult f) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run 'stop' task: %s", UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run 'stop' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); + } + +@@ -1282,8 +1261,7 @@ static void service_enter_start_post(Service *s) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); + } + +@@ -1375,8 +1353,7 @@ static void service_enter_start(Service *s) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run 'start' task: %s", UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run 'start' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); + } + +@@ -1489,9 +1466,7 @@ static void service_enter_reload(Service *s) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run 'reload' task: %s", +- UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run 'reload' task: %s", UNIT(s)->id, strerror(-r)); + s->reload_result = SERVICE_FAILURE_RESOURCES; + service_enter_running(s, SERVICE_SUCCESS); + } +@@ -1525,9 +1500,7 @@ static void service_run_next_control(Service *s) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run next control task: %s", +- UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run next control task: %s", UNIT(s)->id, strerror(-r)); + + if (s->state == SERVICE_START_PRE) + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); +@@ -1572,8 +1545,7 @@ static void service_run_next_main(Service *s) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to run next main task: %s", UNIT(s)->id, strerror(-r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to run next main task: %s", UNIT(s)->id, strerror(-r)); + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); + } + +@@ -1588,41 +1560,35 @@ static int service_execute_action(Service *s, FailureAction action, const char * + + case SERVICE_FAILURE_ACTION_NONE: + if (log_action_none) +- log_warning_unit(UNIT(s)->id, +- "%s %s, refusing to start.", UNIT(s)->id, reason); ++ log_warning_unit(UNIT(s)->id, "%s %s, refusing to start.", UNIT(s)->id, reason); + break; + + case SERVICE_FAILURE_ACTION_REBOOT: { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + +- log_warning_unit(UNIT(s)->id, +- "%s %s, rebooting.", UNIT(s)->id, reason); ++ log_warning_unit(UNIT(s)->id, "%s %s, rebooting.", UNIT(s)->id, reason); + +- r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, +- SPECIAL_REBOOT_TARGET, JOB_REPLACE, +- true, &error, NULL); ++ r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL); + if (r < 0) +- log_error_unit(UNIT(s)->id, +- "Failed to reboot: %s.", bus_error_message(&error, r)); ++ log_error_unit(UNIT(s)->id, "Failed to reboot: %s.", bus_error_message(&error, r)); + + break; + } + + case SERVICE_FAILURE_ACTION_REBOOT_FORCE: +- log_warning_unit(UNIT(s)->id, +- "%s %s, forcibly rebooting.", UNIT(s)->id, reason); ++ log_warning_unit(UNIT(s)->id, "%s %s, forcibly rebooting.", UNIT(s)->id, reason); + UNIT(s)->manager->exit_code = MANAGER_REBOOT; + break; + + case SERVICE_FAILURE_ACTION_REBOOT_IMMEDIATE: +- log_warning_unit(UNIT(s)->id, +- "%s %s, rebooting immediately.", UNIT(s)->id, reason); ++ log_warning_unit(UNIT(s)->id, "%s %s, rebooting immediately.", UNIT(s)->id, reason); ++ + sync(); ++ + if (s->reboot_arg) { + log_info("Rebooting with argument '%s'.", s->reboot_arg); +- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, +- LINUX_REBOOT_CMD_RESTART2, s->reboot_arg); ++ syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, s->reboot_arg); + } + + log_info("Rebooting."); +@@ -1630,8 +1596,7 @@ static int service_execute_action(Service *s, FailureAction action, const char * + break; + + default: +- log_error_unit(UNIT(s)->id, +- "failure action=%i", action); ++ log_error_unit(UNIT(s)->id, "failure action=%i", action); + assert_not_reached("Unknown FailureAction."); + } + +@@ -1990,7 +1955,7 @@ _pure_ static bool service_check_snapshot(Unit *u) { + + assert(s); + +- return (s->socket_fd < 0); ++ return s->socket_fd < 0; + } + + static int service_retry_pid_file(Service *s) { +@@ -2012,24 +1977,19 @@ static int service_retry_pid_file(Service *s) { + static int service_watch_pid_file(Service *s) { + int r; + +- log_debug_unit(UNIT(s)->id, +- "Setting watch for %s's PID file %s", +- UNIT(s)->id, s->pid_file_pathspec->path); ++ log_debug_unit(UNIT(s)->id, "Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path); ++ + r = path_spec_watch(s->pid_file_pathspec, service_dispatch_io); + if (r < 0) + goto fail; + + /* the pidfile might have appeared just before we set the watch */ +- log_debug_unit(UNIT(s)->id, +- "Trying to read %s's PID file %s in case it changed", +- UNIT(s)->id, s->pid_file_pathspec->path); ++ log_debug_unit(UNIT(s)->id, "Trying to read %s's PID file %s in case it changed", UNIT(s)->id, s->pid_file_pathspec->path); + service_retry_pid_file(s); + + return 0; + fail: +- log_error_unit(UNIT(s)->id, +- "Failed to set a watch for %s's PID file %s: %s", +- UNIT(s)->id, s->pid_file_pathspec->path, strerror(-r)); ++ log_error_unit(UNIT(s)->id, "Failed to set a watch for %s's PID file %s: %s", UNIT(s)->id, s->pid_file_pathspec->path, strerror(-r)); + service_unwatch_pid_file(s); + return r; + } +@@ -2116,8 +2076,8 @@ static void service_notify_cgroup_empty_event(Unit *u) { + /* If we were hoping for the daemon to write its PID file, + * we can give up now. */ + if (s->pid_file_pathspec) { +- log_warning_unit(u->id, +- "%s never wrote its PID file. Failing.", UNIT(s)->id); ++ log_warning_unit(u->id, "%s never wrote its PID file. Failing.", UNIT(s)->id); ++ + service_unwatch_pid_file(s); + if (s->state == SERVICE_START) + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); +@@ -2223,9 +2183,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + /* There is another command to * + * execute, so let's do that. */ + +- log_debug_unit(u->id, +- "%s running next main command for state %s", +- u->id, service_state_to_string(s->state)); ++ log_debug_unit(u->id, "%s running next main command for state %s", u->id, service_state_to_string(s->state)); + service_run_next_main(s); + + } else { +@@ -2285,8 +2243,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + s->control_pid = 0; + + if (s->control_command) { +- exec_status_exit(&s->control_command->exec_status, +- &s->exec_context, pid, code, status); ++ exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); + + if (s->control_command->ignore) + f = SERVICE_SUCCESS; +@@ -2311,9 +2268,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + /* There is another command to * + * execute, so let's do that. */ + +- log_debug_unit(u->id, +- "%s running next control command for state %s", +- u->id, service_state_to_string(s->state)); ++ log_debug_unit(u->id, "%s running next control command for state %s", u->id, service_state_to_string(s->state)); + service_run_next_control(s); + + } else { +@@ -2323,9 +2278,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + s->control_command = NULL; + s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; + +- log_debug_unit(u->id, +- "%s got final SIGCHLD for state %s", +- u->id, service_state_to_string(s->state)); ++ log_debug_unit(u->id, "%s got final SIGCHLD for state %s", u->id, service_state_to_string(s->state)); + + switch (s->state) { + +@@ -2453,40 +2406,32 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us + + case SERVICE_START_PRE: + case SERVICE_START: +- log_warning_unit(UNIT(s)->id, +- "%s %s operation timed out. Terminating.", +- UNIT(s)->id, +- s->state == SERVICE_START ? "start" : "start-pre"); ++ log_warning_unit(UNIT(s)->id, "%s %s operation timed out. Terminating.", UNIT(s)->id, s->state == SERVICE_START ? "start" : "start-pre"); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_START_POST: +- log_warning_unit(UNIT(s)->id, +- "%s start-post operation timed out. Stopping.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s start-post operation timed out. Stopping.", UNIT(s)->id); + service_enter_stop(s, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_RELOAD: +- log_warning_unit(UNIT(s)->id, +- "%s reload operation timed out. Stopping.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s reload operation timed out. Stopping.", UNIT(s)->id); + s->reload_result = SERVICE_FAILURE_TIMEOUT; + service_enter_running(s, SERVICE_SUCCESS); + break; + + case SERVICE_STOP: +- log_warning_unit(UNIT(s)->id, +- "%s stopping timed out. Terminating.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_STOP_SIGTERM: + if (s->kill_context.send_sigkill) { +- log_warning_unit(UNIT(s)->id, +- "%s stop-sigterm timed out. Killing.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s stop-sigterm timed out. Killing.", UNIT(s)->id); + service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT); + } else { +- log_warning_unit(UNIT(s)->id, +- "%s stop-sigterm timed out. Skipping SIGKILL.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s stop-sigterm timed out. Skipping SIGKILL.", UNIT(s)->id); + service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT); + } + +@@ -2497,34 +2442,28 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us + * Must be something we cannot kill, so let's just be + * weirded out and continue */ + +- log_warning_unit(UNIT(s)->id, +- "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); + service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_STOP_POST: +- log_warning_unit(UNIT(s)->id, +- "%s stop-post timed out. Terminating.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s stop-post timed out. Terminating.", UNIT(s)->id); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_FINAL_SIGTERM: + if (s->kill_context.send_sigkill) { +- log_warning_unit(UNIT(s)->id, +- "%s stop-final-sigterm timed out. Killing.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s stop-final-sigterm timed out. Killing.", UNIT(s)->id); + service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT); + } else { +- log_warning_unit(UNIT(s)->id, +- "%s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode.", +- UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode.", UNIT(s)->id); + service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false); + } + + break; + + case SERVICE_FINAL_SIGKILL: +- log_warning_unit(UNIT(s)->id, +- "%s still around after final SIGKILL. Entering failed mode.", UNIT(s)->id); ++ log_warning_unit(UNIT(s)->id, "%s still around after final SIGKILL. Entering failed mode.", UNIT(s)->id); + service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true); + break; + +@@ -2551,10 +2490,9 @@ static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void + assert(s); + assert(source == s->watchdog_event_source); + +- log_error_unit(UNIT(s)->id, +- "%s watchdog timeout (limit %s)!", +- UNIT(s)->id, ++ log_error_unit(UNIT(s)->id, "%s watchdog timeout (limit %s)!", UNIT(s)->id, + format_timespan(t, sizeof(t), s->watchdog_usec, 1)); ++ + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_WATCHDOG); + + return 0; +@@ -2571,9 +2509,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { + u->id, pid, tags && *tags ? tags[0] : "(empty)"); + + if (s->notify_access == NOTIFY_NONE) { +- log_warning_unit(u->id, +- "%s: Got notification message from PID "PID_FMT", but reception is disabled.", +- u->id, pid); ++ log_warning_unit(u->id, "%s: Got notification message from PID "PID_FMT", but reception is disabled.", u->id, pid); + return; + } + +@@ -2693,17 +2629,11 @@ static void service_bus_name_owner_change( + assert(old_owner || new_owner); + + if (old_owner && new_owner) +- log_debug_unit(u->id, +- "%s's D-Bus name %s changed owner from %s to %s", +- u->id, name, old_owner, new_owner); ++ log_debug_unit(u->id, "%s's D-Bus name %s changed owner from %s to %s", u->id, name, old_owner, new_owner); + else if (old_owner) +- log_debug_unit(u->id, +- "%s's D-Bus name %s no longer registered by %s", +- u->id, name, old_owner); ++ log_debug_unit(u->id, "%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner); + else +- log_debug_unit(u->id, +- "%s's D-Bus name %s now registered by %s", +- u->id, name, new_owner); ++ log_debug_unit(u->id, "%s's D-Bus name %s now registered by %s", u->id, name, new_owner); + + s->bus_name_good = !!new_owner; + diff --git a/0019-service-don-t-invoke-functions-at-the-same-time-as-d.patch b/0019-service-don-t-invoke-functions-at-the-same-time-as-d.patch new file mode 100644 index 0000000..2e04ac5 --- /dev/null +++ b/0019-service-don-t-invoke-functions-at-the-same-time-as-d.patch @@ -0,0 +1,30 @@ +From f49650cee2c5256dc0491432e1f12a4ae19be6c5 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:20:17 +0200 +Subject: [PATCH] service: don't invoke functions at the same time as declaring + variables + +--- + src/core/service.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index f10582d89e..fc952e848f 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -694,9 +694,13 @@ static void service_set_state(Service *s, ServiceState state) { + /* For remain_after_exit services, let's see if we can "release" the + * hold on the console, since unit_notify() only does that in case of + * change of state */ +- if (state == SERVICE_EXITED && s->remain_after_exit && ++ if (state == SERVICE_EXITED && ++ s->remain_after_exit && + UNIT(s)->manager->n_on_console > 0) { +- ExecContext *ec = unit_get_exec_context(UNIT(s)); ++ ++ ExecContext *ec; ++ ++ ec = unit_get_exec_context(UNIT(s)); + if (ec && exec_context_may_touch_console(ec)) { + Manager *m = UNIT(s)->manager; + diff --git a/0020-service-strv-introduce-strv_find_startswith-and-make.patch b/0020-service-strv-introduce-strv_find_startswith-and-make.patch new file mode 100644 index 0000000..d9e003e --- /dev/null +++ b/0020-service-strv-introduce-strv_find_startswith-and-make.patch @@ -0,0 +1,139 @@ +From 28849dbadb7cd127f7f89e8892ec94c6a05070da Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:22:34 +0200 +Subject: [PATCH] service,strv: introduce strv_find_startswith() and make use + of it + +Unlike strv_find_prefix() the new call will return a pointer to the +suffix of the item we found, instead of the whole item. This is more +closer inline with what startswith() does, and allows us to simplify a +couple of invocations. +--- + src/core/service.c | 44 +++++++++++++++++++++----------------------- + src/shared/strv.c | 17 +++++++++++++++++ + src/shared/strv.h | 1 + + 3 files changed, 39 insertions(+), 23 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index fc952e848f..262a40cc8b 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -2526,12 +2526,13 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { + } + + /* Interpret MAINPID= */ +- e = strv_find_prefix(tags, "MAINPID="); ++ e = strv_find_startswith(tags, "MAINPID="); + if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) { +- if (parse_pid(e + 8, &pid) < 0) ++ if (parse_pid(e, &pid) < 0) + log_warning_unit(u->id, "Failed to parse MAINPID= field in notification message: %s", e); + else { +- log_debug_unit(u->id, "%s: got %s", u->id, e); ++ log_debug_unit(u->id, "%s: got MAINPID=%s", u->id, e); ++ + service_set_main_pid(s, pid); + unit_watch_pid(UNIT(s), pid); + notify_dbus = true; +@@ -2546,44 +2547,41 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { + } + + /* Interpret STATUS= */ +- e = strv_find_prefix(tags, "STATUS="); ++ e = strv_find_startswith(tags, "STATUS="); + if (e) { +- char *t; ++ _cleanup_free_ char *t = NULL; + +- if (e[7]) { +- if (!utf8_is_valid(e+7)) { ++ if (!isempty(e)) { ++ if (!utf8_is_valid(e)) + log_warning_unit(u->id, "Status message in notification is not UTF-8 clean."); +- return; +- } ++ else { ++ log_debug_unit(u->id, "%s: got STATUS=%s", u->id, e); + +- log_debug_unit(u->id, "%s: got %s", u->id, e); +- +- t = strdup(e+7); +- if (!t) { +- log_oom(); +- return; ++ t = strdup(e); ++ if (!t) ++ log_oom(); + } +- +- } else +- t = NULL; ++ } + + if (!streq_ptr(s->status_text, t)) { ++ + free(s->status_text); + s->status_text = t; ++ t = NULL; ++ + notify_dbus = true; +- } else +- free(t); ++ } + } + + /* Interpret ERRNO= */ +- e = strv_find_prefix(tags, "ERRNO="); ++ e = strv_find_startswith(tags, "ERRNO="); + if (e) { + int status_errno; + +- if (safe_atoi(e + 6, &status_errno) < 0 || status_errno < 0) ++ if (safe_atoi(e, &status_errno) < 0 || status_errno < 0) + log_warning_unit(u->id, "Failed to parse ERRNO= field in notification message: %s", e); + else { +- log_debug_unit(u->id, "%s: got %s", u->id, e); ++ log_debug_unit(u->id, "%s: got ERRNO=%s", u->id, e); + + if (s->status_errno != status_errno) { + s->status_errno = status_errno; +diff --git a/src/shared/strv.c b/src/shared/strv.c +index 6448f3170f..0df978d23b 100644 +--- a/src/shared/strv.c ++++ b/src/shared/strv.c +@@ -52,6 +52,23 @@ char *strv_find_prefix(char **l, const char *name) { + return NULL; + } + ++char *strv_find_startswith(char **l, const char *name) { ++ char **i, *e; ++ ++ assert(name); ++ ++ /* Like strv_find_prefix, but actually returns only the ++ * suffix, not the whole item */ ++ ++ STRV_FOREACH(i, l) { ++ e = startswith(*i, name); ++ if (e) ++ return e; ++ } ++ ++ return NULL; ++} ++ + void strv_free(char **l) { + char **k; + +diff --git a/src/shared/strv.h b/src/shared/strv.h +index ee55c148aa..9c9633c515 100644 +--- a/src/shared/strv.h ++++ b/src/shared/strv.h +@@ -28,6 +28,7 @@ + + char *strv_find(char **l, const char *name) _pure_; + char *strv_find_prefix(char **l, const char *name) _pure_; ++char *strv_find_startswith(char **l, const char *name) _pure_; + + void strv_free(char **l); + DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); diff --git a/0021-manager-reuse-sockaddr_union-instead-of-redefining-o.patch b/0021-manager-reuse-sockaddr_union-instead-of-redefining-o.patch new file mode 100644 index 0000000..55e0d68 --- /dev/null +++ b/0021-manager-reuse-sockaddr_union-instead-of-redefining-o.patch @@ -0,0 +1,30 @@ +From 55836941ff642d42403921fa9d5fd2f8376ae722 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:51:44 +0200 +Subject: [PATCH] manager: reuse sockaddr_union instead of redefining our own + version of it + +--- + src/core/manager.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 445461b6b9..e488aba5f8 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -527,13 +527,10 @@ static int manager_setup_notify(Manager *m) { + + if (m->notify_fd < 0) { + _cleanup_close_ int fd = -1; +- union { +- struct sockaddr sa; +- struct sockaddr_un un; +- } sa = { ++ union sockaddr_union sa = { + .sa.sa_family = AF_UNIX, + }; +- int one = 1; ++ static const int one = 1; + + /* First free all secondary fields */ + free(m->notify_socket); diff --git a/0022-manager-don-t-dispatch-sd_notify-messages-and-SIGCHL.patch b/0022-manager-don-t-dispatch-sd_notify-messages-and-SIGCHL.patch new file mode 100644 index 0000000..d37e73b --- /dev/null +++ b/0022-manager-don-t-dispatch-sd_notify-messages-and-SIGCHL.patch @@ -0,0 +1,99 @@ +From 70af4d17dafe81acc96f71f4ec06fbea7386bc38 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 16:52:41 +0200 +Subject: [PATCH] manager: don#t dispatch sd_notify() messages and SIGCHLD + multiple times to the same units + +--- + src/core/manager.c | 44 +++++++++++++++++++++++--------------------- + 1 file changed, 23 insertions(+), 21 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index e488aba5f8..c91ece116f 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -562,7 +562,7 @@ static int manager_setup_notify(Manager *m) { + strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1); + r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + if (r < 0) { +- log_error("bind(@%s) failed: %m", sa.un.sun_path+1); ++ log_error("bind(%s) failed: %m", sa.un.sun_path); + return -errno; + } + +@@ -1398,7 +1398,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + .msg_controllen = sizeof(control), + }; + struct ucred *ucred; +- Unit *u; ++ Unit *u1, *u2, *u3; + + n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT); + if (n <= 0) { +@@ -1424,21 +1424,23 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + assert((size_t) n < sizeof(buf)); + buf[n] = 0; + +- u = manager_get_unit_by_pid(m, ucred->pid); +- if (u) { +- manager_invoke_notify_message(m, u, ucred->pid, buf, n); ++ /* 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); + found = true; + } + +- u = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); +- if (u) { +- manager_invoke_notify_message(m, u, ucred->pid, buf, n); ++ 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); + found = true; + } + +- u = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); +- if (u) { +- manager_invoke_notify_message(m, u, ucred->pid, buf, n); ++ 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); + found = true; + } + +@@ -1485,7 +1487,7 @@ static int manager_dispatch_sigchld(Manager *m) { + + if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) { + _cleanup_free_ char *name = NULL; +- Unit *u; ++ Unit *u1, *u2, *u3; + + get_process_comm(si.si_pid, &name); + +@@ -1499,15 +1501,15 @@ static int manager_dispatch_sigchld(Manager *m) { + + /* And now figure out the unit this belongs + * to, it might be multiple... */ +- u = manager_get_unit_by_pid(m, si.si_pid); +- if (u) +- invoke_sigchld_event(m, u, &si); +- u = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid)); +- if (u) +- invoke_sigchld_event(m, u, &si); +- u = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid)); +- if (u) +- invoke_sigchld_event(m, u, &si); ++ u1 = manager_get_unit_by_pid(m, si.si_pid); ++ if (u1) ++ invoke_sigchld_event(m, u1, &si); ++ u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid)); ++ if (u2 && u2 != u1) ++ invoke_sigchld_event(m, u2, &si); ++ u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid)); ++ if (u3 && u3 != u2 && u3 != u1) ++ invoke_sigchld_event(m, u3, &si); + } + + /* And now, we actually reap the zombie. */ diff --git a/0023-core-allow-informing-systemd-about-service-status-ch.patch b/0023-core-allow-informing-systemd-about-service-status-ch.patch new file mode 100644 index 0000000..de3968c --- /dev/null +++ b/0023-core-allow-informing-systemd-about-service-status-ch.patch @@ -0,0 +1,471 @@ +From 308d72dc1e2106f94ae637e2ea510e8d466d2af1 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 17:03:15 +0200 +Subject: [PATCH] core: allow informing systemd about service status changes + with RELOADING=1 and STOPPING=1 sd_notify() messages + +--- + man/sd_notify.xml | 93 ++++++++++++++++++++++++++++--------------- + src/core/service.c | 105 +++++++++++++++++++++++++++++++++++++++++++------ + src/core/service.h | 13 ++++++ + src/test/test-daemon.c | 22 +++++++++-- + 4 files changed, 185 insertions(+), 48 deletions(-) + +diff --git a/man/sd_notify.xml b/man/sd_notify.xml +index 6bf8230763..fbb882dfd2 100644 +--- a/man/sd_notify.xml ++++ b/man/sd_notify.xml +@@ -46,7 +46,7 @@ + + sd_notify + sd_notifyf +- Notify service manager about start-up completion and other daemon status changes ++ Notify service manager about start-up completion and other service status changes + + + +@@ -70,12 +70,12 @@ + + + Description +- sd_notify() shall be called +- by a daemon to notify the init system about status +- changes. It can be used to send arbitrary information, +- encoded in an environment-block-like string. Most +- importantly it can be used for start-up completion +- notification. ++ sd_notify() may be called ++ by a service to notify the service manager about ++ state changes. It can be used to send arbitrary ++ information, encoded in an environment-block-like ++ string. Most importantly it can be used for start-up ++ completion notification. + + If the unset_environment + parameter is non-zero, sd_notify() +@@ -99,58 +99,87 @@ + + READY=1 + +- Tells the init system +- that daemon startup is finished. This +- is only used by systemd if the service +- definition file has Type=notify +- set. The passed argument is a boolean +- "1" or "0". Since there is little ++ Tells the service ++ manager that service startup is ++ finished. This is only used by systemd ++ if the service definition file has ++ Type=notify set. Since there is little + value in signaling non-readiness, the +- only value daemons should send is +- "READY=1". ++ only value services should send is ++ READY=1 ++ (i.e. READY=0 is ++ not defined). ++ ++ ++ ++ RELOADING=1 ++ ++ Tells the service manager ++ that the service is reloading its ++ configuration. This is useful to allow ++ the service manager to track the service's ++ internal state, and present it to the ++ user. Note that a service that sends ++ this notification must also send a ++ READY=1 ++ notification when it completed ++ reloading its ++ configuration. ++ ++ ++ ++ STOPPING=1 ++ ++ Tells the service manager ++ that the service is beginning its ++ shutdown. This is useful to allow the ++ service manager to track the service's ++ internal state, and present it to the ++ user. + + + + STATUS=... + + Passes a single-line +- status string back to the init system +- that describes the daemon state. This ++ UTF-8 status string back to the service manager ++ that describes the service state. This + is free-form and can be used for + various purposes: general state + feedback, fsck-like programs could + pass completion percentages and + failing programs could pass a human + readable error message. Example: +- "STATUS=Completed 66% of file system +- check..." ++ STATUS=Completed 66% of file ++ system ++ check... + + + + ERRNO=... + +- If a daemon fails, the ++ If a service fails, the + errno-style error code, formatted as +- string. Example: "ERRNO=2" for ++ string. Example: ERRNO=2 for + ENOENT. + + + + BUSERROR=... + +- If a daemon fails, the ++ If a service fails, the + D-Bus error-style error code. Example: +- "BUSERROR=org.freedesktop.DBus.Error.TimedOut" ++ BUSERROR=org.freedesktop.DBus.Error.TimedOut + + + + MAINPID=... + + The main pid of the +- daemon, in case the init system did ++ service, in case the service manager did + not fork off the process + itself. Example: +- "MAINPID=4711" ++ MAINPID=4711 + + + +@@ -183,7 +212,7 @@ + clashes. + + Note that systemd will accept status data sent +- from a daemon only if the ++ from a service only if the + NotifyAccess= option is correctly + set in the service definition file. See + systemd.service5 +@@ -222,7 +251,7 @@ + $NOTIFY_SOCKET is @, the string is + understood as Linux abstract namespace socket. The + datagram is accompanied by the process credentials of +- the sending daemon, using SCM_CREDENTIALS. ++ the sending service, using SCM_CREDENTIALS. + + + +@@ -232,7 +261,7 @@ + + $NOTIFY_SOCKET + +- Set by the init system ++ Set by the service manager + for supervised processes for status + and start-up completion + notification. This environment variable +@@ -249,9 +278,9 @@ + + Start-up Notification + +- When a daemon finished starting up, it ++ When a service finished starting up, it + might issue the following call to notify +- the init system: ++ the service manager: + + sd_notify(0, "READY=1"); + +@@ -259,7 +288,7 @@ + + Extended Start-up Notification + +- A daemon could send the following after ++ A service could send the following after + completing initialization: + + sd_notifyf(0, "READY=1\n" +@@ -271,7 +300,7 @@ + + Error Cause Notification + +- A daemon could send the following shortly before exiting, on failure ++ A service could send the following shortly before exiting, on failure + + sd_notifyf(0, "STATUS=Failed to start up: %s\n" + "ERRNO=%i", +diff --git a/src/core/service.c b/src/core/service.c +index 262a40cc8b..3221938793 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -92,6 +92,7 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us + static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata); + + static void service_enter_signal(Service *s, ServiceState state, ServiceResult f); ++static void service_enter_reload_by_notify(Service *s); + + static void service_init(Unit *u) { + Service *s = SERVICE(u); +@@ -473,7 +474,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { + "%sGuessMainPID: %s\n" + "%sType: %s\n" + "%sRestart: %s\n" +- "%sNotifyAccess: %s\n", ++ "%sNotifyAccess: %s\n" ++ "%sNotifyState: %s\n", + prefix, service_state_to_string(s->state), + prefix, service_result_to_string(s->result), + prefix, service_result_to_string(s->reload_result), +@@ -483,7 +485,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { + prefix, yes_no(s->guess_main_pid), + prefix, service_type_to_string(s->type), + prefix, service_restart_to_string(s->restart), +- prefix, notify_access_to_string(s->notify_access)); ++ prefix, notify_access_to_string(s->notify_access), ++ prefix, notify_state_to_string(s->notify_state)); + + if (s->control_pid > 0) + fprintf(f, +@@ -1176,6 +1179,17 @@ fail: + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true); + } + ++static void service_enter_stop_by_notify(Service *s) { ++ assert(s); ++ ++ unit_watch_all_pids(UNIT(s)); ++ ++ if (s->timeout_stop_usec > 0) ++ service_arm_timer(s, s->timeout_stop_usec); ++ ++ service_set_state(s, SERVICE_STOP); ++} ++ + static void service_enter_stop(Service *s, ServiceResult f) { + int r; + +@@ -1226,9 +1240,18 @@ static void service_enter_running(Service *s, ServiceResult f) { + cgroup_ok = cgroup_good(s); + + if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) && +- (s->bus_name_good || s->type != SERVICE_DBUS)) +- service_set_state(s, SERVICE_RUNNING); +- else if (s->remain_after_exit) ++ (s->bus_name_good || s->type != SERVICE_DBUS)) { ++ ++ /* If there are any queued up sd_notify() ++ * notifications, process them now */ ++ if (s->notify_state == NOTIFY_RELOADING) ++ service_enter_reload_by_notify(s); ++ else if (s->notify_state == NOTIFY_STOPPING) ++ service_enter_stop_by_notify(s); ++ else ++ service_set_state(s, SERVICE_RUNNING); ++ ++ } else if (s->remain_after_exit) + service_set_state(s, SERVICE_EXITED); + else + service_enter_stop(s, SERVICE_SUCCESS); +@@ -1433,12 +1456,19 @@ static void service_enter_restart(Service *s) { + return; + + fail: +- log_warning_unit(UNIT(s)->id, +- "%s failed to schedule restart job: %s", +- UNIT(s)->id, bus_error_message(&error, -r)); ++ log_warning_unit(UNIT(s)->id, "%s failed to schedule restart job: %s", UNIT(s)->id, bus_error_message(&error, -r)); + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false); + } + ++static void service_enter_reload_by_notify(Service *s) { ++ assert(s); ++ ++ if (s->timeout_start_usec > 0) ++ service_arm_timer(s, s->timeout_start_usec); ++ ++ service_set_state(s, SERVICE_RELOAD); ++} ++ + static void service_enter_reload(Service *s) { + int r; + +@@ -1667,6 +1697,8 @@ static int service_start(Unit *u) { + s->status_text = NULL; + s->status_errno = 0; + ++ s->notify_state = NOTIFY_UNKNOWN; ++ + service_enter_start_pre(s); + return 0; + } +@@ -2504,13 +2536,15 @@ static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void + + static void service_notify_message(Unit *u, pid_t pid, char **tags) { + Service *s = SERVICE(u); +- const char *e; ++ _cleanup_free_ char *cc = NULL; + bool notify_dbus = false; ++ const char *e; + + assert(u); + +- log_debug_unit(u->id, "%s: Got notification message from PID "PID_FMT" (%s...)", +- u->id, pid, tags && *tags ? tags[0] : "(empty)"); ++ cc = strv_join(tags, ", "); ++ log_debug_unit(u->id, "%s: Got notification message from PID "PID_FMT" (%s)", ++ u->id, pid, isempty(cc) ? "n/a" : cc); + + if (s->notify_access == NOTIFY_NONE) { + log_warning_unit(u->id, "%s: Got notification message from PID "PID_FMT", but reception is disabled.", u->id, pid); +@@ -2539,10 +2573,46 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { + } + } + ++ /* Interpret RELOADING= */ ++ if (strv_find(tags, "RELOADING=1")) { ++ ++ log_debug_unit(u->id, "%s: got RELOADING=1", u->id); ++ s->notify_state = NOTIFY_RELOADING; ++ ++ if (s->state == SERVICE_RUNNING) ++ service_enter_reload_by_notify(s); ++ ++ notify_dbus = true; ++ } ++ + /* Interpret READY= */ +- if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START && strv_find(tags, "READY=1")) { ++ if (strv_find(tags, "READY=1")) { ++ + log_debug_unit(u->id, "%s: got READY=1", u->id); +- service_enter_start_post(s); ++ s->notify_state = NOTIFY_READY; ++ ++ /* Type=notify services inform us about completed ++ * initialization with READY=1 */ ++ if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START) ++ service_enter_start_post(s); ++ ++ /* Sending READY=1 while we are reloading informs us ++ * that the reloading is complete */ ++ if (s->state == SERVICE_RELOAD && s->control_pid == 0) ++ service_enter_running(s, SERVICE_SUCCESS); ++ ++ notify_dbus = true; ++ } ++ ++ /* Interpret STOPPING= */ ++ if (strv_find(tags, "STOPPING=1")) { ++ ++ log_debug_unit(u->id, "%s: got STOPPING=1", u->id); ++ s->notify_state = NOTIFY_STOPPING; ++ ++ if (s->state == SERVICE_RUNNING) ++ service_enter_stop_by_notify(s); ++ + notify_dbus = true; + } + +@@ -2798,6 +2868,15 @@ static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); + ++static const char* const notify_state_table[_NOTIFY_STATE_MAX] = { ++ [NOTIFY_UNKNOWN] = "unknown", ++ [NOTIFY_READY] = "ready", ++ [NOTIFY_RELOADING] = "reloading", ++ [NOTIFY_STOPPING] = "stopping", ++}; ++ ++DEFINE_STRING_TABLE_LOOKUP(notify_state, NotifyState); ++ + static const char* const service_result_table[_SERVICE_RESULT_MAX] = { + [SERVICE_SUCCESS] = "success", + [SERVICE_FAILURE_RESOURCES] = "resources", +diff --git a/src/core/service.h b/src/core/service.h +index 686cf4b0bd..0227321d99 100644 +--- a/src/core/service.h ++++ b/src/core/service.h +@@ -91,6 +91,15 @@ typedef enum NotifyAccess { + _NOTIFY_ACCESS_INVALID = -1 + } NotifyAccess; + ++typedef enum NotifyState { ++ NOTIFY_UNKNOWN, ++ NOTIFY_READY, ++ NOTIFY_RELOADING, ++ NOTIFY_STOPPING, ++ _NOTIFY_STATE_MAX, ++ _NOTIFY_STATE_INVALID = -1 ++} NotifyState; ++ + typedef enum ServiceResult { + SERVICE_SUCCESS, + SERVICE_FAILURE_RESOURCES, +@@ -196,6 +205,7 @@ struct Service { + PathSpec *pid_file_pathspec; + + NotifyAccess notify_access; ++ NotifyState notify_state; + }; + + extern const UnitVTable service_vtable; +@@ -219,6 +229,9 @@ ServiceExecCommand service_exec_command_from_string(const char *s) _pure_; + const char* notify_access_to_string(NotifyAccess i) _const_; + NotifyAccess notify_access_from_string(const char *s) _pure_; + ++const char* notify_state_to_string(NotifyState i) _const_; ++NotifyState notify_state_from_string(const char *s) _pure_; ++ + const char* service_result_to_string(ServiceResult i) _const_; + ServiceResult service_result_from_string(const char *s) _pure_; + +diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c +index bcc049b325..7e0ac754d1 100644 +--- a/src/test/test-daemon.c ++++ b/src/test/test-daemon.c +@@ -25,13 +25,29 @@ + + int main(int argc, char*argv[]) { + +- sd_notify(0, "STATUS=Starting up"); ++ sd_notify(0, ++ "STATUS=Starting up"); ++ sleep(5); ++ ++ sd_notify(0, ++ "STATUS=Running\n" ++ "READY=1"); ++ sleep(5); ++ ++ sd_notify(0, ++ "STATUS=Reloading\n" ++ "RELOADING=1"); + sleep(5); ++ + sd_notify(0, + "STATUS=Running\n" + "READY=1"); +- sleep(10); +- sd_notify(0, "STATUS=Quitting"); ++ sleep(5); ++ ++ sd_notify(0, ++ "STATUS=Quitting\n" ++ "STOPPING=1"); ++ sleep(5); + + return 0; + } diff --git a/0024-notify-send-STOPPING-1-from-our-daemons.patch b/0024-notify-send-STOPPING-1-from-our-daemons.patch new file mode 100644 index 0000000..205d8f4 --- /dev/null +++ b/0024-notify-send-STOPPING-1-from-our-daemons.patch @@ -0,0 +1,236 @@ +From af4ec4309e8f82aad87a8d574785c12f8763d5f8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 17:19:28 +0200 +Subject: [PATCH] notify: send STOPPING=1 from our daemons + +--- + src/bus-proxyd/bus-proxyd.c | 6 +++++- + src/core/manager.c | 3 ++- + src/initctl/initctl.c | 1 + + src/journal-remote/journal-remote.c | 6 ++++-- + src/journal-remote/journal-upload.c | 5 ++++- + src/journal/journald.c | 4 +++- + src/login/logind.c | 1 + + src/machine/machined.c | 1 + + src/network/networkd.c | 1 + + src/nspawn/nspawn.c | 8 +++++++- + src/resolve/resolved.c | 4 +++- + src/shutdownd/shutdownd.c | 1 + + src/timesync/timesyncd.c | 8 ++++++-- + 13 files changed, 39 insertions(+), 10 deletions(-) + +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +index d8d989b9b0..d35d7f63b2 100644 +--- a/src/bus-proxyd/bus-proxyd.c ++++ b/src/bus-proxyd/bus-proxyd.c +@@ -239,7 +239,7 @@ static int rename_service(sd_bus *a, sd_bus *b) { + pid, p, + uid, name, + a->unique_name); +- ; ++ + return 0; + } + +@@ -1474,6 +1474,10 @@ int main(int argc, char *argv[]) { + } + + finish: ++ sd_notify(false, ++ "STOPPING=1\n" ++ "STATUS=Shutting down."); ++ + policy_free(&policy); + strv_free(arg_configuration); + free(arg_address); +diff --git a/src/core/manager.c b/src/core/manager.c +index c91ece116f..7401817844 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2551,7 +2551,8 @@ void manager_check_finished(Manager *m) { + bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec); + + sd_notifyf(false, +- "READY=1\nSTATUS=Startup finished in %s.", ++ "READY=1\n" ++ "STATUS=Startup finished in %s.", + format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)); + } + +diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c +index 0954e58afd..f1c2b8dfb4 100644 +--- a/src/initctl/initctl.c ++++ b/src/initctl/initctl.c +@@ -431,6 +431,7 @@ int main(int argc, char *argv[]) { + + fail: + sd_notify(false, ++ "STOPPING=1\n" + "STATUS=Shutting down..."); + + server_done(&server); +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index 7f422bfb37..1cc86aeaf3 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -1530,10 +1530,12 @@ int main(int argc, char **argv) { + } + } + +- server_destroy(&s); ++ sd_notifyf(false, ++ "STOPPING=1\n" ++ "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count); + log_info("Finishing after writing %" PRIu64 " entries", s.event_count); + +- sd_notify(false, "STATUS=Shutting down..."); ++ server_destroy(&s); + + free(arg_key); + free(arg_cert); +diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c +index bdeeff6778..40c380aa9e 100644 +--- a/src/journal-remote/journal-upload.c ++++ b/src/journal-remote/journal-upload.c +@@ -818,7 +818,10 @@ int main(int argc, char **argv) { + } + + cleanup: +- sd_notify(false, "STATUS=Shutting down..."); ++ sd_notify(false, ++ "STOPPING=1\n" ++ "STATUS=Shutting down..."); ++ + destroy_uploader(&u); + + finish: +diff --git a/src/journal/journald.c b/src/journal/journald.c +index b1a0e25d0c..de40827d6a 100644 +--- a/src/journal/journald.c ++++ b/src/journal/journald.c +@@ -116,7 +116,9 @@ int main(int argc, char *argv[]) { + server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped"); + + finish: +- sd_notify(false, "STATUS=Shutting down..."); ++ sd_notify(false, ++ "STOPPING=1\n" ++ "STATUS=Shutting down..."); + + server_done(&server); + +diff --git a/src/login/logind.c b/src/login/logind.c +index 006c56ae51..52e1c43a47 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -1226,6 +1226,7 @@ int main(int argc, char *argv[]) { + + finish: + sd_notify(false, ++ "STOPPING=1\n" + "STATUS=Shutting down..."); + + if (m) +diff --git a/src/machine/machined.c b/src/machine/machined.c +index 6160320127..f9d180d24a 100644 +--- a/src/machine/machined.c ++++ b/src/machine/machined.c +@@ -350,6 +350,7 @@ int main(int argc, char *argv[]) { + + finish: + sd_notify(false, ++ "STOPPING=1\n" + "STATUS=Shutting down..."); + + if (m) +diff --git a/src/network/networkd.c b/src/network/networkd.c +index 665f4c4709..fdb80368d4 100644 +--- a/src/network/networkd.c ++++ b/src/network/networkd.c +@@ -125,6 +125,7 @@ int main(int argc, char *argv[]) { + + out: + sd_notify(false, ++ "STOPPING=1\n" + "STATUS=Shutting down..."); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index d01da45930..2c718557ee 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -3071,7 +3071,9 @@ int main(int argc, char *argv[]) { + goto finish; + } + +- sd_notify(0, "READY=1"); ++ sd_notify(false, ++ "READY=1\n" ++ "STATUS=Container running."); + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigemptyset(&mask_chld) == 0); +@@ -3504,6 +3506,10 @@ int main(int argc, char *argv[]) { + } + + finish: ++ sd_notify(false, ++ "STOPPING=1\n" ++ "STATUS=Terminating..."); ++ + loop_remove(loop_nr, &image_fd); + + if (pid > 0) +diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c +index 8235558585..88c3bcc591 100644 +--- a/src/resolve/resolved.c ++++ b/src/resolve/resolved.c +@@ -100,7 +100,9 @@ int main(int argc, char *argv[]) { + sd_event_get_exit_code(m->event, &r); + + finish: +- sd_notify(false, "STATUS=Shutting down..."); ++ sd_notify(false, ++ "STOPPIN=1\n" ++ "STATUS=Shutting down..."); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + } +diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c +index 92907497ed..99aa4b32b3 100644 +--- a/src/shutdownd/shutdownd.c ++++ b/src/shutdownd/shutdownd.c +@@ -456,6 +456,7 @@ finish: + } + + sd_notify(false, ++ "STOPPING=\n" + "STATUS=Exiting..."); + + return r; +diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c +index 351bfd0236..ee3bc99ae0 100644 +--- a/src/timesync/timesyncd.c ++++ b/src/timesync/timesyncd.c +@@ -132,7 +132,9 @@ int main(int argc, char *argv[]) { + log_warning("Failed to parse configuration file: %s", strerror(-r)); + + log_debug("systemd-timesyncd running as pid %lu", (unsigned long) getpid()); +- sd_notify(false, "READY=1"); ++ sd_notify(false, ++ "READY=1\n" ++ "STATUS=Daemon is running"); + + if (network_is_online()) { + r = manager_connect(m); +@@ -153,7 +155,9 @@ int main(int argc, char *argv[]) { + sd_event_get_exit_code(m->event, &r); + + finish: +- sd_notify(false, "STATUS=Shutting down..."); ++ sd_notify(false, ++ "STOPPING=1\n" ++ "STATUS=Shutting down..."); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + } diff --git a/0025-update-TODO.patch b/0025-update-TODO.patch new file mode 100644 index 0000000..03779e6 --- /dev/null +++ b/0025-update-TODO.patch @@ -0,0 +1,34 @@ +From 55cdcbacf70f05a40a155af24f6d2da6b478cba6 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 17:20:00 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/TODO b/TODO +index cbd8384b4a..868518ab75 100644 +--- a/TODO ++++ b/TODO +@@ -38,9 +38,6 @@ Features: + for "systemctl suspend" to finish to know when the suspending is + complete. + +-* sd_notify("SHUTDOWN=1") to fix a dbus activation race. +- http://lists.freedesktop.org/archives/systemd-devel/2014-July/020983.html +- + * merge ~/.local/share and ~/.local/lib into one similar /usr/lib and /usr/share.... + + * make "systemctl suspend" block until we are back from suspend +@@ -603,9 +600,7 @@ Features: + + * make sure systemd-ask-password-wall does not shutdown systemd-ask-password-console too early + +-* support sd_notify() style notification when reload begins (RELOADING=1), reload is finished (READY=1), and add ReloadSignal= then to use in combination +- +-* support sd_notify() style notification when shutting down, to make auto-exit bus services work (STOPPING=1) ++* add ReloadSignal= for configuring a reload signal to use + + * verify that the AF_UNIX sockets of a service in the fs still exist + when we start a service in order to avoid confusion when a user diff --git a/0026-bus-when-terminating-our-bus-actviated-services-that.patch b/0026-bus-when-terminating-our-bus-actviated-services-that.patch new file mode 100644 index 0000000..d0c16d2 --- /dev/null +++ b/0026-bus-when-terminating-our-bus-actviated-services-that.patch @@ -0,0 +1,49 @@ +From 430e21c2f7e77d600257ead56419f511e48e854a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 17:20:19 +0200 +Subject: [PATCH] bus: when terminating our bus-actviated services that + exit-on-idle send STOPPING=1 via sd_notify() + +This should fix a race where a service thatis idle drops its name, and +is immediately requested by another client, which causes dbus-daemon to +ask systemd to activate it again, but since systemd still assumes it is +running it won't do anything. +--- + src/libsystemd/sd-bus/bus-util.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 475ed34a53..c97bf7d99d 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -22,6 +22,8 @@ + #include + #include + ++#include "systemd/sd-daemon.h" ++ + #include "util.h" + #include "strv.h" + #include "macro.h" +@@ -128,11 +130,17 @@ int bus_event_loop_with_idle( + if (r == -EBUSY) + continue; + ++ /* Fallback for dbus1 connections: we ++ * unregister the name and wait for the ++ * response to come through for it */ + if (r == -ENOTSUP) { +- /* Fallback for dbus1 connections: we +- * unregister the name and wait for +- * the response to come through for +- * it */ ++ ++ /* Inform the service manager that we ++ * are going down, so that it will ++ * queue all further start requests, ++ * instead of assuming we are already ++ * running. */ ++ sd_notify(false, "STOPPING=1"); + + r = bus_async_unregister_and_exit(e, bus, name); + if (r < 0) diff --git a/0027-execute-explain-in-a-comment-why-close_all_fds-is-in.patch b/0027-execute-explain-in-a-comment-why-close_all_fds-is-in.patch new file mode 100644 index 0000000..6d5d070 --- /dev/null +++ b/0027-execute-explain-in-a-comment-why-close_all_fds-is-in.patch @@ -0,0 +1,25 @@ +From f461c8073dee9cd10bfae5ae3586e785ec8a5d07 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 17:35:19 +0200 +Subject: [PATCH] execute: explain in a comment, why close_all_fds() is invoked + the second time differently + +--- + src/core/execute.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 2544a2470c..b5b22472d5 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1635,7 +1635,9 @@ int exec_spawn(ExecCommand *command, + } + + /* We repeat the fd closing here, to make sure that +- * nothing is leaked from the PAM modules */ ++ * nothing is leaked from the PAM modules. Note that ++ * we are more aggressive this time since socket_fd ++ * and the netns fds we don#t need anymore. */ + err = close_all_fds(fds, n_fds); + if (err >= 0) + err = shift_fds(fds, n_fds); diff --git a/0028-service-use-the-right-timeout-for-stop-processes-we-.patch b/0028-service-use-the-right-timeout-for-stop-processes-we-.patch new file mode 100644 index 0000000..02e2a91 --- /dev/null +++ b/0028-service-use-the-right-timeout-for-stop-processes-we-.patch @@ -0,0 +1,106 @@ +From 21b2ce39d4038cd6176394836fdcfb7fba63f424 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 18:01:22 +0200 +Subject: [PATCH] service: use the right timeout for stop processes we fork + +--- + src/core/service.c | 23 +++++++++++------------ + 1 file changed, 11 insertions(+), 12 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 3221938793..7d6ea73e05 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -862,7 +862,7 @@ fail: + static int service_spawn( + Service *s, + ExecCommand *c, +- bool timeout, ++ usec_t timeout, + bool pass_fds, + bool apply_permissions, + bool apply_chroot, +@@ -907,8 +907,8 @@ static int service_spawn( + } + } + +- if (timeout && s->timeout_start_usec > 0) { +- r = service_arm_timer(s, s->timeout_start_usec); ++ if (timeout > 0) { ++ r = service_arm_timer(s, timeout); + if (r < 0) + goto fail; + } else +@@ -1108,7 +1108,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) { + + r = service_spawn(s, + s->control_command, +- true, ++ s->timeout_stop_usec, + false, + !s->permissions_start_only, + !s->root_directory_start_only, +@@ -1207,7 +1207,7 @@ static void service_enter_stop(Service *s, ServiceResult f) { + + r = service_spawn(s, + s->control_command, +- true, ++ s->timeout_stop_usec, + false, + !s->permissions_start_only, + !s->root_directory_start_only, +@@ -1270,7 +1270,7 @@ static void service_enter_start_post(Service *s) { + + r = service_spawn(s, + s->control_command, +- true, ++ s->timeout_start_usec, + false, + !s->permissions_start_only, + !s->root_directory_start_only, +@@ -1334,8 +1334,7 @@ static void service_enter_start(Service *s) { + + r = service_spawn(s, + c, +- s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || +- s->type == SERVICE_NOTIFY || s->type == SERVICE_ONESHOT, ++ IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0, + true, + true, + true, +@@ -1401,7 +1400,7 @@ static void service_enter_start_pre(Service *s) { + + r = service_spawn(s, + s->control_command, +- true, ++ s->timeout_start_usec, + false, + !s->permissions_start_only, + !s->root_directory_start_only, +@@ -1482,7 +1481,7 @@ static void service_enter_reload(Service *s) { + + r = service_spawn(s, + s->control_command, +- true, ++ s->timeout_start_usec, + false, + !s->permissions_start_only, + !s->root_directory_start_only, +@@ -1519,7 +1518,7 @@ static void service_run_next_control(Service *s) { + + r = service_spawn(s, + s->control_command, +- true, ++ IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec, + false, + !s->permissions_start_only, + !s->root_directory_start_only, +@@ -1563,7 +1562,7 @@ static void service_run_next_main(Service *s) { + + r = service_spawn(s, + s->main_command, +- true, ++ s->timeout_start_usec, + true, + true, + true, diff --git a/0029-update-TODO.patch b/0029-update-TODO.patch new file mode 100644 index 0000000..a53b0c8 --- /dev/null +++ b/0029-update-TODO.patch @@ -0,0 +1,22 @@ +From 1954ea346dc28226c0fffde848d49a297165b0a9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 18:01:47 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/TODO b/TODO +index 868518ab75..16b61d045c 100644 +--- a/TODO ++++ b/TODO +@@ -40,8 +40,6 @@ Features: + + * merge ~/.local/share and ~/.local/lib into one similar /usr/lib and /usr/share.... + +-* make "systemctl suspend" block until we are back from suspend +- + * remove readahead in 217 + + * journald: allows specification of UID range for splitting up journal files diff --git a/0030-service-allow-services-of-Type-oneshot-that-specify-.patch b/0030-service-allow-services-of-Type-oneshot-that-specify-.patch new file mode 100644 index 0000000..d946e98 --- /dev/null +++ b/0030-service-allow-services-of-Type-oneshot-that-specify-.patch @@ -0,0 +1,166 @@ +From 96fb8242cc1ef6b0e28f6c86a4f57950095dd7f1 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 18:50:42 +0200 +Subject: [PATCH] service: allow services of Type=oneshot that specify no + ExecStart= commands + +This is useful for services that simply want to run something on +shutdown, but not at bootup. They should only set ExecStop= but leave +ExecStart= unset. +--- + man/systemd.service.xml | 44 +++++++++++++++++++++++++++----------------- + src/core/service.c | 39 +++++++++++++++++++++++++++++---------- + 2 files changed, 56 insertions(+), 27 deletions(-) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index 5c4bd6569f..e584a1f006 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -139,9 +139,10 @@ + + If set to + (the default +- value if neither ++ if neither + Type= nor +- BusName= are ++ BusName=, but ++ ExecStart= are + specified), it is expected that the + process configured with + ExecStart= is the +@@ -177,13 +178,17 @@ + exits. + + Behavior of +- is similar +- to ; however, +- it is expected that the process has to ++ is similar to ++ ; however, it ++ is expected that the process has to + exit before systemd starts follow-up + units. RemainAfterExit= + is particularly useful for this type +- of service. ++ of service. This is the implied ++ default if neither ++ Type= or ++ ExecStart= are ++ specified. + + Behavior of + is similar to +@@ -313,22 +318,27 @@ + + When Type is + not , only one +- command may be given. When ++ command may and must be given. When + Type=oneshot is +- used, more than one command may be +- specified. Multiple command lines may +- be concatenated in a single directive +- by separating them with semicolons +- (these semicolons must be passed as +- separate words). Alternatively, this +- directive may be specified more than +- once with the same effect. +- Lone semicolons may be escaped as ++ used, none or more than one command ++ may be specified. Multiple command ++ lines may be concatenated in a single ++ directive by separating them with ++ semicolons (these semicolons must be ++ passed as separate ++ words). Alternatively, this directive ++ may be specified more than once with ++ the same effect. Lone semicolons may ++ be escaped as + \;. If the empty + string is assigned to this option, the + list of commands to start is reset, + prior assignments of this option will +- have no effect. ++ have no effect. If no ++ ExecStart= is ++ specified, then the service must have ++ RemainAfterExit=yes ++ set. + + Each command line is split on + whitespace, with the first item being +diff --git a/src/core/service.c b/src/core/service.c +index 7d6ea73e05..1b864c4c8c 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -313,14 +313,23 @@ static int service_verify(Service *s) { + if (UNIT(s)->load_state != UNIT_LOADED) + return 0; + +- if (!s->exec_command[SERVICE_EXEC_START]) { +- log_error_unit(UNIT(s)->id, "%s lacks ExecStart setting. Refusing.", UNIT(s)->id); ++ if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP]) { ++ log_error_unit(UNIT(s)->id, "%s lacks both ExecStart= and ExecStop= setting. Refusing.", UNIT(s)->id); + return -EINVAL; + } + +- if (s->type != SERVICE_ONESHOT && +- s->exec_command[SERVICE_EXEC_START]->command_next) { +- log_error_unit(UNIT(s)->id, "%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id); ++ if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) { ++ log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id); ++ return -EINVAL; ++ } ++ ++ if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) { ++ log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.", UNIT(s)->id); ++ return -EINVAL; ++ } ++ ++ if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) { ++ log_error_unit(UNIT(s)->id, "%s has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id); + return -EINVAL; + } + +@@ -410,8 +419,15 @@ static int service_load(Unit *u) { + if (r < 0) + return r; + +- if (s->type == _SERVICE_TYPE_INVALID) +- s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE; ++ if (s->type == _SERVICE_TYPE_INVALID) { ++ /* Figure out a type automatically */ ++ if (s->bus_name) ++ s->type = SERVICE_DBUS; ++ else if (s->exec_command[SERVICE_EXEC_START]) ++ s->type = SERVICE_SIMPLE; ++ else ++ s->type = SERVICE_ONESHOT; ++ } + + /* Oneshot services have disabled start timeout by default */ + if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined) +@@ -1309,9 +1325,6 @@ static void service_enter_start(Service *s) { + + assert(s); + +- assert(s->exec_command[SERVICE_EXEC_START]); +- assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT); +- + service_unwatch_control_pid(s); + service_unwatch_main_pid(s); + +@@ -1332,6 +1345,12 @@ static void service_enter_start(Service *s) { + c = s->main_command = s->exec_command[SERVICE_EXEC_START]; + } + ++ if (!c) { ++ assert(s->type == SERVICE_ONESHOT); ++ service_enter_start_post(s); ++ return; ++ } ++ + r = service_spawn(s, + c, + IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0, diff --git a/0031-install-simplify-usage-of-_cleanup_-macros.patch b/0031-install-simplify-usage-of-_cleanup_-macros.patch new file mode 100644 index 0000000..39a50c2 --- /dev/null +++ b/0031-install-simplify-usage-of-_cleanup_-macros.patch @@ -0,0 +1,126 @@ +From 59ccf93d97f0a37522e5f4fbf5cc0288dbedf495 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 19:08:30 +0200 +Subject: [PATCH] install: simplify usage of _cleanup_ macros + +--- + src/shared/install.c | 27 +++++++++++++-------------- + src/shared/path-lookup.h | 4 ++-- + 2 files changed, 15 insertions(+), 16 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 03c7a9da2e..4b09a69456 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -45,8 +45,6 @@ typedef struct { + Hashmap *have_installed; + } InstallContext; + +-#define _cleanup_install_context_done_ _cleanup_(install_context_done) +- + static int in_search_path(const char *path, char **search) { + _cleanup_free_ char *parent = NULL; + int r; +@@ -1161,7 +1159,7 @@ static int unit_file_can_install( + const char *name, + bool allow_symlink) { + +- _cleanup_install_context_done_ InstallContext c = {}; ++ _cleanup_(install_context_done) InstallContext c = {}; + InstallInfo *i; + int r; + +@@ -1498,7 +1496,7 @@ int unit_file_enable( + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- _cleanup_install_context_done_ InstallContext c = {}; ++ _cleanup_(install_context_done) InstallContext c = {}; + char **i; + _cleanup_free_ char *config_path = NULL; + int r; +@@ -1537,7 +1535,7 @@ int unit_file_disable( + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- _cleanup_install_context_done_ InstallContext c = {}; ++ _cleanup_(install_context_done) InstallContext c = {}; + char **i; + _cleanup_free_ char *config_path = NULL; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +@@ -1597,7 +1595,7 @@ int unit_file_set_default( + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- _cleanup_install_context_done_ InstallContext c = {}; ++ _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_free_ char *config_path = NULL; + char *path; + int r; +@@ -1859,7 +1857,7 @@ int unit_file_preset( + UnitFileChange **changes, + unsigned *n_changes) { + +- _cleanup_install_context_done_ InstallContext plus = {}, minus = {}; ++ _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_free_ char *config_path = NULL; + char **i; +@@ -1927,7 +1925,7 @@ int unit_file_preset_all( + UnitFileChange **changes, + unsigned *n_changes) { + +- _cleanup_install_context_done_ InstallContext plus = {}, minus = {}; ++ _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_free_ char *config_path = NULL; + char **i; +@@ -2019,14 +2017,15 @@ int unit_file_preset_all( + return r; + } + +-static void unitfilelist_free(UnitFileList **f) { +- if (!*f) ++static void unit_file_list_free_one(UnitFileList *f) { ++ if (!f) + return; + +- free((*f)->path); +- free(*f); ++ free(f->path); ++ free(f); + } +-#define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free) ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one); + + int unit_file_get_list( + UnitFileScope scope, +@@ -2071,7 +2070,7 @@ int unit_file_get_list( + } + + for (;;) { +- _cleanup_unitfilelist_free_ UnitFileList *f = NULL; ++ _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL; + struct dirent *de; + + errno = 0; +diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h +index 2fe8173f44..4bbd47ec39 100644 +--- a/src/shared/path-lookup.h ++++ b/src/shared/path-lookup.h +@@ -38,8 +38,6 @@ typedef enum SystemdRunningAs { + _SYSTEMD_RUNNING_AS_INVALID = -1 + } SystemdRunningAs; + +-#define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free) +- + int user_config_home(char **config_home); + + int lookup_paths_init(LookupPaths *p, +@@ -50,3 +48,5 @@ int lookup_paths_init(LookupPaths *p, + const char *generator_early, + const char *generator_late); + void lookup_paths_free(LookupPaths *p); ++ ++#define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free) diff --git a/0032-systemctl-in-list-unit-files-always-show-legend-even.patch b/0032-systemctl-in-list-unit-files-always-show-legend-even.patch new file mode 100644 index 0000000..df3b01a --- /dev/null +++ b/0032-systemctl-in-list-unit-files-always-show-legend-even.patch @@ -0,0 +1,46 @@ +From 4fe1be9ce2e0cca6354a4167f0a1a7e1f943c91c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 19:10:26 +0200 +Subject: [PATCH] systemctl: in list-unit-files, always show legend, even if we + know about no unit files + +--- + src/systemctl/systemctl.c | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 072f615ad5..d9b8bee28d 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1351,11 +1351,8 @@ static int list_unit_files(sd_bus *bus, char **args) { + + n_units = hashmap_size(h); + +- if (n_units == 0) +- return 0; +- + units = new(UnitFileList, n_units); +- if (!units) { ++ if (!units && n_units > 0) { + unit_file_list_free(h); + return log_oom(); + } +@@ -1411,14 +1408,13 @@ static int list_unit_files(sd_bus *bus, char **args) { + return bus_log_parse_error(r); + } + +- if (c > 0) { +- qsort(units, c, sizeof(UnitFileList), compare_unit_file_list); +- output_unit_file_list(units, c); +- } ++ qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list); ++ output_unit_file_list(units, c); + +- if (avoid_bus()) ++ if (avoid_bus()) { + for (unit = units; unit < units + c; unit++) + free(unit->path); ++ } + + return 0; + } diff --git a/0033-update-TODO.patch b/0033-update-TODO.patch new file mode 100644 index 0000000..303bce7 --- /dev/null +++ b/0033-update-TODO.patch @@ -0,0 +1,24 @@ +From 337ce7442a0602116c6253ebf202bd34f675f627 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 21 Aug 2014 19:12:43 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/TODO b/TODO +index 16b61d045c..3073f3a5a2 100644 +--- a/TODO ++++ b/TODO +@@ -521,10 +521,6 @@ Features: + + * properly handle loop back mounts via fstab, especially regards to fsck/passno + +-* allow services with no ExecStart= but with an ExecStop= +- +-* dracut-shutdown needs to be ordered before unmounting /boot +- + * initialize the hostname from the fs label of /, if /etc/hostname does not exist? + + * rename "userspace" to "core-os" diff --git a/0034-dbus1-generator-properly-free-the-FILE.patch b/0034-dbus1-generator-properly-free-the-FILE.patch new file mode 100644 index 0000000..00b2595 --- /dev/null +++ b/0034-dbus1-generator-properly-free-the-FILE.patch @@ -0,0 +1,59 @@ +From 0975b63fb31263e535a2d26ed41e66e23f468bc5 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Aug 2014 12:44:17 +0200 +Subject: [PATCH] dbus1-generator: properly free the FILE* + +Also, rework the code to make use of fflush_and_check(). + +Issue discovered by Simon Danner. +--- + src/dbus1-generator/dbus1-generator.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c +index e1ffc5515f..3c4522b589 100644 +--- a/src/dbus1-generator/dbus1-generator.c ++++ b/src/dbus1-generator/dbus1-generator.c +@@ -40,6 +40,7 @@ static int create_dbus_files( + + _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL; + _cleanup_fclose_ FILE *f = NULL; ++ int r; + + assert(path); + assert(name); +@@ -100,12 +101,15 @@ static int create_dbus_files( + } + } + +- fflush(f); +- if (ferror(f)) { +- log_error("Failed to write %s: %m", a); +- return -errno; ++ r = fflush_and_check(f); ++ if (r < 0) { ++ log_error("Failed to write %s: %s", a, strerror(-r)); ++ return r; + } + ++ fclose(f); ++ f = NULL; ++ + service = s; + } + +@@ -134,10 +138,10 @@ static int create_dbus_files( + name, + service); + +- fflush(f); +- if (ferror(f)) { +- log_error("Failed to write %s: %m", b); +- return -errno; ++ r = fflush_and_check(f); ++ if (r < 0) { ++ log_error("Failed to write %s: %s", b, strerror(-r)); ++ return r; + } + + lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL); diff --git a/0035-shared-add-MAXSIZE-and-use-it-in-resolved.patch b/0035-shared-add-MAXSIZE-and-use-it-in-resolved.patch new file mode 100644 index 0000000..f69df25 --- /dev/null +++ b/0035-shared-add-MAXSIZE-and-use-it-in-resolved.patch @@ -0,0 +1,75 @@ +From 40a1eebde6be7ac3f1885147fc24e06ad1da260c Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 22 Aug 2014 13:55:57 +0200 +Subject: [PATCH] shared: add MAXSIZE() and use it in resolved + +The MAXSIZE() macro takes two types and returns the size of the larger +one. It is much simpler to use than MAX(sizeof(A), sizeof(B)) and also +avoids any compiler-extensions, unlike CONST_MAX() and MAX() (which are +needed to avoid evaluating arguments more than once). This was suggested +by Daniele Nicolodi . + +Also make resolved use this macro instead of CONST_MAX(). This enhances +readability quite a bit. +--- + src/resolve/resolved-dns-stream.c | 2 +- + src/resolve/resolved-manager.c | 2 +- + src/shared/macro.h | 3 +++ + src/test/test-util.c | 4 ++++ + 4 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c +index 8b3a3ced4b..8aad5e4df1 100644 +--- a/src/resolve/resolved-dns-stream.c ++++ b/src/resolve/resolved-dns-stream.c +@@ -64,7 +64,7 @@ static int dns_stream_complete(DnsStream *s, int error) { + static int dns_stream_identify(DnsStream *s) { + union { + struct cmsghdr header; /* For alignment */ +- uint8_t buffer[CMSG_SPACE(CONST_MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo))) ++ uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo)) + + EXTRA_CMSG_SPACE /* kernel appears to require extra space */]; + } control; + struct msghdr mh = {}; +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index 56baf8730d..659b1dacc8 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -841,7 +841,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + union { + struct cmsghdr header; /* For alignment */ +- uint8_t buffer[CMSG_SPACE(CONST_MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo))) ++ uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo)) + + CMSG_SPACE(int) /* ttl/hoplimit */ + + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */]; + } control; +diff --git a/src/shared/macro.h b/src/shared/macro.h +index 179b24c983..43fa3e556f 100644 +--- a/src/shared/macro.h ++++ b/src/shared/macro.h +@@ -149,6 +149,9 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { + ((_A) > (_B)) ? (_A) : (_B), \ + (void)0)) + ++/* takes two types and returns the size of the larger one */ ++#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) ++ + #define MAX3(x,y,z) \ + __extension__ ({ \ + const typeof(x) _c = MAX(x,y); \ +diff --git a/src/test/test-util.c b/src/test/test-util.c +index ac1afce86b..34d5f2ed7d 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -90,6 +90,10 @@ static void test_max(void) { + assert_se(val1.a == 100); + assert_se(MAX(++d, 0) == 1); + assert_se(d == 1); ++ ++ assert_cc(MAXSIZE(char[3], uint16_t) == 3); ++ assert_cc(MAXSIZE(char[3], uint32_t) == 4); ++ assert_cc(MAXSIZE(char, long) == sizeof(long)); + } + + static void test_first_word(void) { diff --git a/0036-missing.h-add-fake-__NR_memfd_create-for-MIPS.patch b/0036-missing.h-add-fake-__NR_memfd_create-for-MIPS.patch new file mode 100644 index 0000000..553d66c --- /dev/null +++ b/0036-missing.h-add-fake-__NR_memfd_create-for-MIPS.patch @@ -0,0 +1,25 @@ +From a7d611f280b3eadafd6b411b659a321b4d6e63f4 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 22 Aug 2014 15:39:36 +0200 +Subject: [PATCH] missing.h: add fake __NR_memfd_create for MIPS + +We don't have the correct __NR_memfd_create syscall number yet, so set it to +0xffffffff for now to prevent compile time errors. +--- + src/shared/missing.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 3ff1a21720..3051cb5640 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -167,6 +167,9 @@ static inline int pivot_root(const char *new_root, const char *put_old) { + # define __NR_fanotify_mark 5296 + # endif + # endif ++# ifndef __NR_memfd_create ++# define __NR_memfd_create 0xffffffff /* FIXME */ ++# endif + #else + # ifndef __NR_fanotify_init + # define __NR_fanotify_init 338 diff --git a/0037-missing.h-add-a-cpp-warning-for-__NR_memfd_create-on.patch b/0037-missing.h-add-a-cpp-warning-for-__NR_memfd_create-on.patch new file mode 100644 index 0000000..f52f355 --- /dev/null +++ b/0037-missing.h-add-a-cpp-warning-for-__NR_memfd_create-on.patch @@ -0,0 +1,23 @@ +From 2de1851fe3611c59abf77127c6b5bc1b91eb7cba Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 22 Aug 2014 16:10:02 +0200 +Subject: [PATCH] missing.h: add a cpp warning for __NR_memfd_create on MIPS + +--- + src/shared/missing.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 3051cb5640..a9dd274274 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -168,7 +168,8 @@ static inline int pivot_root(const char *new_root, const char *put_old) { + # endif + # endif + # ifndef __NR_memfd_create +-# define __NR_memfd_create 0xffffffff /* FIXME */ ++# warning "__NR_memfd_create not yet defined for MIPS" ++# define __NR_memfd_create 0xffffffff + # endif + #else + # ifndef __NR_fanotify_init diff --git a/0038-core-add-support-for-a-configurable-system-wide-star.patch b/0038-core-add-support-for-a-configurable-system-wide-star.patch new file mode 100644 index 0000000..ef368f0 --- /dev/null +++ b/0038-core-add-support-for-a-configurable-system-wide-star.patch @@ -0,0 +1,704 @@ +From 2928b0a863091f8f291fddb168988711afd389ef Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Aug 2014 16:36:38 +0200 +Subject: [PATCH] core: add support for a configurable system-wide start-up + timeout + +When this system-wide start-up timeout is hit we execute one of the +failure actions already implemented for services that fail. + +This should not only be useful on embedded devices, but also on laptops +which have the power-button reachable when the lid is closed. This +devices, when in a backpack might get powered on by accident due to the +easily reachable power button. We want to make sure that the system +turns itself off if it starts up due this after a while. + +When the system manages to fully start-up logind will suspend the +machine by default if the lid is closed. However, in some cases we don't +even get as far as logind, and the boot hangs much earlier, for example +because we ask for a LUKS password that nobody ever enters. + +Yeah, this is a real-life problem on my Yoga 13, which has one of those +easily accessible power buttons, even if the device is closed. +--- + Makefile.am | 4 +- + man/systemd-system.conf.xml | 27 ++++++++++++- + man/systemd.service.xml | 23 +++++------ + src/core/failure-action.c | 94 +++++++++++++++++++++++++++++++++++++++++++++ + src/core/failure-action.h | 40 +++++++++++++++++++ + src/core/main.c | 13 +++++++ + src/core/manager.c | 43 +++++++++++++++++++-- + src/core/manager.h | 10 +++++ + src/core/service.c | 77 ++++--------------------------------- + src/core/service.h | 16 +------- + src/core/system.conf | 3 ++ + src/shared/util.c | 21 ++++++++++ + src/shared/util.h | 2 + + src/test/test-tables.c | 2 +- + 14 files changed, 273 insertions(+), 102 deletions(-) + create mode 100644 src/core/failure-action.c + create mode 100644 src/core/failure-action.h + +diff --git a/Makefile.am b/Makefile.am +index 4028112a62..cbf98bdac3 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1112,7 +1112,9 @@ libsystemd_core_la_SOURCES = \ + src/core/audit-fd.c \ + src/core/audit-fd.h \ + src/core/show-status.c \ +- src/core/show-status.h ++ src/core/show-status.h \ ++ src/core/failure-action.c \ ++ src/core/failure-action.h + + if HAVE_KMOD + libsystemd_core_la_SOURCES += \ +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 6105c5131c..48690024f4 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -254,7 +254,6 @@ + signal. + + +- + + TimerSlackNSec= + +@@ -281,6 +280,32 @@ + + + ++ StartTimeoutSec= ++ StartTimeoutAction= ++ StartTimeoutRebootArgument= ++ ++ Configures an over-all ++ system start-up timeout and controls ++ what to do when the timeout is ++ reached. StartTimeoutSec= ++ specifies the timeout, and defaults to ++ 15min. StartTimeoutAction= ++ configures the action to take when the ++ system did not finish boot-up within ++ the specified time. It takes the same ++ values as the per-service ++ StartLimitAction= ++ setting, see ++ systemd.service5 ++ for details. Defaults to ++ . StartTimeoutRebootArgument= ++ configures an optional reboot string ++ to pass to the ++ reboot2 ++ system call. ++ ++ ++ + DefaultTimerAccuracySec= + + Sets the default +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index e584a1f006..20d2a0d755 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -1155,29 +1155,30 @@ ExecStart=/bin/echo $ONE $TWO ${TWO} + + + ++ FailureAction= ++ Configure the action ++ to take when the service enters a failed ++ state. Takes the same values as ++ StartLimitAction= ++ and executes the same actions. ++ Defaults to . ++ ++ ++ ++ + RebootArgument= + Configure the optional + argument for the + reboot2 + system call if + StartLimitAction= ++ or FailureAction= + is a reboot action. This works just + like the optional argument to + systemctl reboot + command. + + +- +- FailureAction= +- Configure the action +- to take when the service enters a failed +- state. Takes the same values as +- StartLimitAction= +- and executes the same actions. +- Defaults to . +- +- +- + + + Check +diff --git a/src/core/failure-action.c b/src/core/failure-action.c +new file mode 100644 +index 0000000000..ca807b68da +--- /dev/null ++++ b/src/core/failure-action.c +@@ -0,0 +1,94 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2014 Lennart Poettering ++ Copyright 2012 Michael Olbrich ++ ++ 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 "bus-util.h" ++#include "bus-error.h" ++#include "special.h" ++#include "failure-action.h" ++ ++int failure_action( ++ Manager *m, ++ FailureAction action, ++ const char *reboot_arg) { ++ ++ int r; ++ ++ assert(m); ++ assert(action >= 0); ++ assert(action < _FAILURE_ACTION_MAX); ++ ++ switch (action) { ++ ++ case FAILURE_ACTION_NONE: ++ break; ++ ++ case FAILURE_ACTION_REBOOT: { ++ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ ++ log_warning("Rebooting as result of failure."); ++ ++ update_reboot_param_file(reboot_arg); ++ r = manager_add_job_by_name(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL); ++ if (r < 0) ++ log_error("Failed to reboot: %s.", bus_error_message(&error, r)); ++ ++ break; ++ } ++ ++ case FAILURE_ACTION_REBOOT_FORCE: ++ log_warning("Forcibly rebooting as result of failure."); ++ update_reboot_param_file(reboot_arg); ++ m->exit_code = MANAGER_REBOOT; ++ break; ++ ++ case FAILURE_ACTION_REBOOT_IMMEDIATE: ++ log_warning("Rebooting immediately as result of failure."); ++ ++ sync(); ++ ++ if (reboot_arg) { ++ log_info("Rebooting with argument '%s'.", reboot_arg); ++ syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reboot_arg); ++ } ++ ++ log_info("Rebooting."); ++ reboot(RB_AUTOBOOT); ++ break; ++ ++ default: ++ assert_not_reached("Unknown failure 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" ++}; ++DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction); +diff --git a/src/core/failure-action.h b/src/core/failure-action.h +new file mode 100644 +index 0000000000..5353192f31 +--- /dev/null ++++ b/src/core/failure-action.h +@@ -0,0 +1,40 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++#pragma once ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2014 Lennart Poettering ++ Copyright 2012 Michael Olbrich ++ ++ 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 . ++***/ ++ ++typedef enum FailureAction { ++ FAILURE_ACTION_NONE, ++ FAILURE_ACTION_REBOOT, ++ FAILURE_ACTION_REBOOT_FORCE, ++ FAILURE_ACTION_REBOOT_IMMEDIATE, ++ _FAILURE_ACTION_MAX, ++ _FAILURE_ACTION_INVALID = -1 ++} FailureAction; ++ ++#include "macro.h" ++#include "manager.h" ++ ++int failure_action(Manager *m, FailureAction action, const char *reboot_arg); ++ ++const char* failure_action_to_string(FailureAction i) _const_; ++FailureAction failure_action_from_string(const char *s) _pure_; +diff --git a/src/core/main.c b/src/core/main.c +index 792b316c61..ed690162bf 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -116,6 +116,9 @@ 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 usec_t arg_start_timeout_usec = DEFAULT_MANAGER_START_TIMEOUT_USEC; ++static FailureAction arg_start_timeout_action = FAILURE_ACTION_REBOOT_FORCE; ++static char *arg_start_timeout_reboot_arg = NULL; + + static void nop_handler(int sig) {} + +@@ -669,6 +672,9 @@ 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", "StartTimeoutSec", config_parse_sec, 0, &arg_start_timeout_usec }, ++ { "Manager", "StartTimeoutAction", config_parse_failure_action, 0, &arg_start_timeout_action }, ++ { "Manager", "StartTimeoutRebootArgument",config_parse_string, 0, &arg_start_timeout_reboot_arg }, + {} + }; + +@@ -1628,6 +1634,10 @@ int main(int argc, char *argv[]) { + m->default_memory_accounting = arg_default_memory_accounting; + m->runtime_watchdog = arg_runtime_watchdog; + m->shutdown_watchdog = arg_shutdown_watchdog; ++ m->start_timeout_usec = arg_start_timeout_usec; ++ m->start_timeout_action = arg_start_timeout_action; ++ free_and_strdup(&m->start_timeout_reboot_arg, arg_start_timeout_reboot_arg); ++ + m->userspace_timestamp = userspace_timestamp; + m->kernel_timestamp = kernel_timestamp; + m->initrd_timestamp = initrd_timestamp; +@@ -1816,6 +1826,9 @@ finish: + set_free(arg_syscall_archs); + arg_syscall_archs = NULL; + ++ free(arg_start_timeout_reboot_arg); ++ arg_start_timeout_reboot_arg = NULL; ++ + label_finish(); + + if (reexecute) { +diff --git a/src/core/manager.c b/src/core/manager.c +index 7401817844..1bb0c9025f 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -435,6 +435,8 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) { + m->running_as = running_as; + m->exit_code = _MANAGER_EXIT_CODE_INVALID; + m->default_timer_accuracy_usec = USEC_PER_MINUTE; ++ m->start_timeout_usec = DEFAULT_MANAGER_START_TIMEOUT_USEC; ++ m->start_timeout_action = FAILURE_ACTION_REBOOT_FORCE; + + m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; + +@@ -823,6 +825,9 @@ void manager_free(Manager *m) { + + manager_close_idle_pipe(m); + ++ sd_event_source_unref(m->start_timeout_event_source); ++ free(m->start_timeout_reboot_arg); ++ + udev_unref(m->udev); + sd_event_unref(m->event); + +@@ -970,6 +975,20 @@ static int manager_distribute_fds(Manager *m, FDSet *fds) { + return 0; + } + ++static int on_start_timeout(sd_event_source *s, usec_t usec, void *userdata) { ++ Manager *m = userdata; ++ ++ assert(s); ++ assert(m); ++ ++ m->start_timeout_event_source = sd_event_source_unref(m->start_timeout_event_source); ++ ++ log_error("Startup timed out."); ++ ++ failure_action(m, m->start_timeout_action, m->start_timeout_reboot_arg); ++ return 0; ++} ++ + int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + int r, q; + +@@ -1042,6 +1061,22 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + m->send_reloading_done = true; + } + ++ /* Possibly set up a start timeout */ ++ if (!dual_timestamp_is_set(&m->finish_timestamp)) { ++ m->start_timeout_event_source = sd_event_source_unref(m->start_timeout_event_source); ++ ++ if (m->start_timeout_usec) { ++ r = sd_event_add_time( ++ m->event, ++ &m->start_timeout_event_source, ++ CLOCK_MONOTONIC, ++ now(CLOCK_MONOTONIC) + m->start_timeout_usec, 0, ++ on_start_timeout, m); ++ if (r < 0) ++ log_error("Failed to add start timeout event: %s", strerror(-r)); ++ } ++ } ++ + return r; + } + +@@ -2462,10 +2497,8 @@ void manager_check_finished(Manager *m) { + + if (hashmap_size(m->jobs) > 0) { + +- if (m->jobs_in_progress_event_source) { +- sd_event_source_set_time(m->jobs_in_progress_event_source, +- now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC); +- } ++ if (m->jobs_in_progress_event_source) ++ sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC); + + return; + } +@@ -2487,6 +2520,8 @@ void manager_check_finished(Manager *m) { + + dual_timestamp_get(&m->finish_timestamp); + ++ m->start_timeout_event_source = sd_event_source_unref(m->start_timeout_event_source); ++ + if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) { + + /* Note that m->kernel_usec.monotonic is always at 0, +diff --git a/src/core/manager.h b/src/core/manager.h +index 7cb76f7f00..7d26c3adea 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -33,6 +33,8 @@ + /* Enforce upper limit how many names we allow */ + #define MANAGER_MAX_NAMES 131072 /* 128K */ + ++#define DEFAULT_MANAGER_START_TIMEOUT_USEC (15*USEC_PER_MINUTE) ++ + typedef struct Manager Manager; + + typedef enum ManagerState { +@@ -69,6 +71,7 @@ typedef enum ManagerExitCode { + #include "unit-name.h" + #include "exit-status.h" + #include "show-status.h" ++#include "failure-action.h" + + struct Manager { + /* Note that the set of units we know of is allowed to be +@@ -152,6 +155,7 @@ struct Manager { + dual_timestamp initrd_timestamp; + dual_timestamp userspace_timestamp; + dual_timestamp finish_timestamp; ++ + dual_timestamp security_start_timestamp; + dual_timestamp security_finish_timestamp; + dual_timestamp generators_start_timestamp; +@@ -279,6 +283,12 @@ struct Manager { + + /* Used for processing polkit authorization responses */ + Hashmap *polkit_registry; ++ ++ /* System wide startup timeouts */ ++ usec_t start_timeout_usec; ++ sd_event_source *start_timeout_event_source; ++ FailureAction start_timeout_action; ++ char *start_timeout_reboot_arg; + }; + + int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m); +diff --git a/src/core/service.c b/src/core/service.c +index 1b864c4c8c..223e4b3a41 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -23,9 +23,6 @@ + #include + #include + #include +-#include +-#include +-#include + + #include "async.h" + #include "manager.h" +@@ -1052,8 +1049,6 @@ static int cgroup_good(Service *s) { + return !r; + } + +-static int service_execute_action(Service *s, FailureAction action, const char *reason, bool log_action_none); +- + static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) { + int r; + assert(s); +@@ -1063,8 +1058,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) + + service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD); + +- if (s->result != SERVICE_SUCCESS) +- service_execute_action(s, s->failure_action, "failed", false); ++ if (s->result != SERVICE_SUCCESS) { ++ log_warning_unit(UNIT(s)->id, "%s failed.", UNIT(s)->id); ++ failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg); ++ } + + if (allow_restart && + !s->forbid_restart && +@@ -1601,67 +1598,15 @@ fail: + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); + } + +-static int service_execute_action(Service *s, FailureAction action, const char *reason, bool log_action_none) { +- assert(s); +- +- if (action == SERVICE_FAILURE_ACTION_REBOOT || +- action == SERVICE_FAILURE_ACTION_REBOOT_FORCE) +- update_reboot_param_file(s->reboot_arg); +- +- switch (action) { +- +- case SERVICE_FAILURE_ACTION_NONE: +- if (log_action_none) +- log_warning_unit(UNIT(s)->id, "%s %s, refusing to start.", UNIT(s)->id, reason); +- break; +- +- case SERVICE_FAILURE_ACTION_REBOOT: { +- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- int r; +- +- log_warning_unit(UNIT(s)->id, "%s %s, rebooting.", UNIT(s)->id, reason); +- +- r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL); +- if (r < 0) +- log_error_unit(UNIT(s)->id, "Failed to reboot: %s.", bus_error_message(&error, r)); +- +- break; +- } +- +- case SERVICE_FAILURE_ACTION_REBOOT_FORCE: +- log_warning_unit(UNIT(s)->id, "%s %s, forcibly rebooting.", UNIT(s)->id, reason); +- UNIT(s)->manager->exit_code = MANAGER_REBOOT; +- break; +- +- case SERVICE_FAILURE_ACTION_REBOOT_IMMEDIATE: +- log_warning_unit(UNIT(s)->id, "%s %s, rebooting immediately.", UNIT(s)->id, reason); +- +- sync(); +- +- if (s->reboot_arg) { +- log_info("Rebooting with argument '%s'.", s->reboot_arg); +- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, s->reboot_arg); +- } +- +- log_info("Rebooting."); +- reboot(RB_AUTOBOOT); +- break; +- +- default: +- log_error_unit(UNIT(s)->id, "failure action=%i", action); +- assert_not_reached("Unknown FailureAction."); +- } +- +- return -ECANCELED; +-} +- + static int service_start_limit_test(Service *s) { + assert(s); + + if (ratelimit_test(&s->start_limit)) + return 0; + +- return service_execute_action(s, s->start_limit_action, "start request repeated too quickly", true); ++ log_warning_unit(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); + } + + static int service_start(Unit *u) { +@@ -2908,14 +2853,6 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); + +-static const char* const failure_action_table[_SERVICE_FAILURE_ACTION_MAX] = { +- [SERVICE_FAILURE_ACTION_NONE] = "none", +- [SERVICE_FAILURE_ACTION_REBOOT] = "reboot", +- [SERVICE_FAILURE_ACTION_REBOOT_FORCE] = "reboot-force", +- [SERVICE_FAILURE_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate" +-}; +-DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction); +- + const UnitVTable service_vtable = { + .object_size = sizeof(Service), + .exec_context_offset = offsetof(Service, exec_context), +diff --git a/src/core/service.h b/src/core/service.h +index 0227321d99..5bcfd14339 100644 +--- a/src/core/service.h ++++ b/src/core/service.h +@@ -28,6 +28,7 @@ typedef struct Service Service; + #include "ratelimit.h" + #include "kill.h" + #include "exit-status.h" ++#include "failure-action.h" + + typedef enum ServiceState { + SERVICE_DEAD, +@@ -113,15 +114,6 @@ typedef enum ServiceResult { + _SERVICE_RESULT_INVALID = -1 + } ServiceResult; + +-typedef enum FailureAction { +- SERVICE_FAILURE_ACTION_NONE, +- SERVICE_FAILURE_ACTION_REBOOT, +- SERVICE_FAILURE_ACTION_REBOOT_FORCE, +- SERVICE_FAILURE_ACTION_REBOOT_IMMEDIATE, +- _SERVICE_FAILURE_ACTION_MAX, +- _SERVICE_FAILURE_ACTION_INVALID = -1 +-} FailureAction; +- + struct Service { + Unit meta; + +@@ -193,10 +185,9 @@ struct Service { + char *status_text; + int status_errno; + +- FailureAction failure_action; +- + RateLimit start_limit; + FailureAction start_limit_action; ++ FailureAction failure_action; + char *reboot_arg; + + UnitRef accept_socket; +@@ -234,6 +225,3 @@ NotifyState notify_state_from_string(const char *s) _pure_; + + const char* service_result_to_string(ServiceResult i) _const_; + ServiceResult service_result_from_string(const char *s) _pure_; +- +-const char* failure_action_to_string(FailureAction i) _const_; +-FailureAction failure_action_from_string(const char *s) _pure_; +diff --git a/src/core/system.conf b/src/core/system.conf +index 65a35a0689..45448de328 100644 +--- a/src/core/system.conf ++++ b/src/core/system.conf +@@ -23,6 +23,9 @@ + #CapabilityBoundingSet= + #SystemCallArchitectures= + #TimerSlackNSec= ++#StartTimeoutSec=15min ++#StartTimeoutAction=reboot-force ++#StartTimeoutRebootArgument= + #DefaultTimerAccuracySec=1min + #DefaultStandardOutput=journal + #DefaultStandardError=inherit +diff --git a/src/shared/util.c b/src/shared/util.c +index a54e879953..fc6f668726 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -7137,3 +7137,24 @@ int unquote_many_words(const char **p, ...) { + + return c; + } ++ ++int free_and_strdup(char **p, const char *s) { ++ char *t; ++ ++ assert(p); ++ ++ /* Replaces a string pointer with an strdup()ed new string, ++ * possibly freeing the old one. */ ++ ++ if (s) { ++ t = strdup(s); ++ if (!t) ++ return -ENOMEM; ++ } else ++ t = NULL; ++ ++ free(*p); ++ *p = t; ++ ++ return 0; ++} +diff --git a/src/shared/util.h b/src/shared/util.h +index 8cd47b8294..cd947dbbef 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -978,3 +978,5 @@ int is_symlink(const char *path); + + int unquote_first_word(const char **p, char **ret); + int unquote_many_words(const char **p, ...) _sentinel_; ++ ++int free_and_strdup(char **p, const char *s); +diff --git a/src/test/test-tables.c b/src/test/test-tables.c +index 88e7d10c60..58fe4433b7 100644 +--- a/src/test/test-tables.c ++++ b/src/test/test-tables.c +@@ -63,7 +63,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, SERVICE_FAILURE_ACTION); ++ test_table(failure_action, FAILURE_ACTION); + test_table(job_mode, JOB_MODE); + test_table(job_result, JOB_RESULT); + test_table(job_state, JOB_STATE); diff --git a/0039-core-print-startup-finished-messages-even-if-we-log-.patch b/0039-core-print-startup-finished-messages-even-if-we-log-.patch new file mode 100644 index 0000000..a17c2cd --- /dev/null +++ b/0039-core-print-startup-finished-messages-even-if-we-log-.patch @@ -0,0 +1,85 @@ +From e12919e8be5c80efe09a57f642bbd2411b313ced Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Aug 2014 16:41:00 +0200 +Subject: [PATCH] core: print 'startup finished' messages even if we log to + console + +--- + src/core/manager.c | 55 ++++++++++++++++++++++++++---------------------------- + 1 file changed, 26 insertions(+), 29 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 1bb0c9025f..7508fefaef 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2539,44 +2539,41 @@ void manager_check_finished(Manager *m) { + kernel_usec = m->initrd_timestamp.monotonic - m->kernel_timestamp.monotonic; + initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic; + +- if (!log_on_console()) +- log_struct(LOG_INFO, +- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), +- "KERNEL_USEC="USEC_FMT, kernel_usec, +- "INITRD_USEC="USEC_FMT, initrd_usec, +- "USERSPACE_USEC="USEC_FMT, userspace_usec, +- "MESSAGE=Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.", +- format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC), +- format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC), +- format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC), +- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), +- NULL); ++ log_struct(LOG_INFO, ++ MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), ++ "KERNEL_USEC="USEC_FMT, kernel_usec, ++ "INITRD_USEC="USEC_FMT, initrd_usec, ++ "USERSPACE_USEC="USEC_FMT, userspace_usec, ++ "MESSAGE=Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.", ++ format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC), ++ format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC), ++ format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC), ++ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), ++ NULL); + } else { + kernel_usec = m->userspace_timestamp.monotonic - m->kernel_timestamp.monotonic; + initrd_usec = 0; + +- if (!log_on_console()) +- log_struct(LOG_INFO, +- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), +- "KERNEL_USEC="USEC_FMT, kernel_usec, +- "USERSPACE_USEC="USEC_FMT, userspace_usec, +- "MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.", +- format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC), +- format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC), +- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), +- NULL); +- } +- } else { +- firmware_usec = loader_usec = initrd_usec = kernel_usec = 0; +- total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic; +- +- if (!log_on_console()) + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), ++ "KERNEL_USEC="USEC_FMT, kernel_usec, + "USERSPACE_USEC="USEC_FMT, userspace_usec, +- "MESSAGE=Startup finished in %s.", ++ "MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.", ++ format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC), ++ format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC), + format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), + NULL); ++ } ++ } else { ++ firmware_usec = loader_usec = initrd_usec = kernel_usec = 0; ++ total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic; ++ ++ log_struct(LOG_INFO, ++ MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), ++ "USERSPACE_USEC="USEC_FMT, userspace_usec, ++ "MESSAGE=Startup finished in %s.", ++ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), ++ NULL); + } + + SET_FOREACH(u, m->startup_units, i) diff --git a/0040-resolved-fix-typo-in-log-message.patch b/0040-resolved-fix-typo-in-log-message.patch new file mode 100644 index 0000000..41b27e0 --- /dev/null +++ b/0040-resolved-fix-typo-in-log-message.patch @@ -0,0 +1,22 @@ +From c4147df156835513c43260a14fc9f7af177f737f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Aug 2014 16:58:25 +0200 +Subject: [PATCH] resolved: fix typo in log message + +--- + src/resolve/resolved-manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index 659b1dacc8..f97989754d 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -449,7 +449,7 @@ static int manager_llmnr_start(Manager *m) { + return 0; + + eaddrinuse: +- log_warning("There appears to be another LLMNR respondering running. Turning off LLMNR support."); ++ log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support."); + m->llmnr_support = SUPPORT_NO; + manager_llmnr_stop(m); + diff --git a/0041-core-introduce-poweroff-as-new-failure-action-types.patch b/0041-core-introduce-poweroff-as-new-failure-action-types.patch new file mode 100644 index 0000000..bd2b8dc --- /dev/null +++ b/0041-core-introduce-poweroff-as-new-failure-action-types.patch @@ -0,0 +1,219 @@ +From f07756bfe25c64119704c93a634162d6c88b5c89 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Aug 2014 16:59:46 +0200 +Subject: [PATCH] core: introduce "poweroff" as new failure action types + +Also, change the default action on a system start-up timeout to powering off. +--- + man/systemd-system.conf.xml | 2 +- + man/systemd.service.xml | 31 +++++++++++++++++++----------- + src/core/failure-action.c | 46 +++++++++++++++++++++++++++++++++++++++++---- + src/core/failure-action.h | 3 +++ + src/core/main.c | 2 +- + src/core/manager.c | 2 +- + src/core/shutdown.c | 3 +-- + src/core/system.conf | 2 +- + 8 files changed, 70 insertions(+), 21 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 48690024f4..1fad1dba80 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -298,7 +298,7 @@ + setting, see + systemd.service5 + for details. Defaults to +- . StartTimeoutRebootArgument= ++ . StartTimeoutRebootArgument= + configures an optional reboot string + to pass to the + reboot2 +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index 20d2a0d755..8b17f857ce 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -1131,26 +1131,35 @@ ExecStart=/bin/echo $ONE $TWO ${TWO} + hit. Takes one of + , + , +- , or +- . If +- is set, +- hitting the rate limit will trigger no +- action besides that the start will not +- be permitted. ++ , ++ , ++ , ++ or ++ . If ++ is set, hitting ++ the rate limit will trigger no action ++ besides that the start will not be ++ permitted. + causes a reboot following the normal + shutdown procedure (i.e. equivalent to + systemctl reboot). +- causes +- a forced reboot which will terminate +- all processes forcibly but should +- cause no dirty file systems on reboot ++ causes a ++ forced reboot which will terminate all ++ processes forcibly but should cause no ++ dirty file systems on reboot + (i.e. equivalent to systemctl + reboot -f) and + + causes immediate execution of the + reboot2 + system call, which might result in +- data loss. Defaults to ++ data loss. Similar, ++ , ++ , ++ ++ have the effect of powering down the ++ system with similar ++ semantics. Defaults to + . + + +diff --git a/src/core/failure-action.c b/src/core/failure-action.c +index ca807b68da..941747429f 100644 +--- a/src/core/failure-action.c ++++ b/src/core/failure-action.c +@@ -40,10 +40,19 @@ int failure_action( + assert(action >= 0); + assert(action < _FAILURE_ACTION_MAX); + +- switch (action) { ++ if (action == FAILURE_ACTION_NONE) ++ return -ECANCELED; + +- case FAILURE_ACTION_NONE: +- break; ++ 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."); ++ m->exit_code = MANAGER_EXIT; ++ return -ECANCELED; ++ } ++ ++ switch (action) { + + case FAILURE_ACTION_REBOOT: { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +@@ -78,6 +87,32 @@ int failure_action( + reboot(RB_AUTOBOOT); + break; + ++ case FAILURE_ACTION_POWEROFF: { ++ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ ++ log_warning("Powering off as result of failure."); ++ ++ r = manager_add_job_by_name(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, true, &error, NULL); ++ if (r < 0) ++ log_error("Failed to poweroff: %s.", bus_error_message(&error, r)); ++ ++ break; ++ } ++ ++ case FAILURE_ACTION_POWEROFF_FORCE: ++ log_warning("Forcibly powering off as result of failure."); ++ m->exit_code = MANAGER_POWEROFF; ++ break; ++ ++ case FAILURE_ACTION_POWEROFF_IMMEDIATE: ++ log_warning("Powering off immediately as result of failure."); ++ ++ sync(); ++ ++ log_info("Powering off."); ++ reboot(RB_POWER_OFF); ++ break; ++ + default: + assert_not_reached("Unknown failure action"); + } +@@ -89,6 +124,9 @@ 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_REBOOT_IMMEDIATE] = "reboot-immediate", ++ [FAILURE_ACTION_POWEROFF] = "poweroff", ++ [FAILURE_ACTION_POWEROFF_FORCE] = "poweroff-force", ++ [FAILURE_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate" + }; + DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction); +diff --git a/src/core/failure-action.h b/src/core/failure-action.h +index 5353192f31..1af4dd987b 100644 +--- a/src/core/failure-action.h ++++ b/src/core/failure-action.h +@@ -27,6 +27,9 @@ typedef enum FailureAction { + 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; +diff --git a/src/core/main.c b/src/core/main.c +index ed690162bf..bd148b1b33 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -117,7 +117,7 @@ static bool arg_default_cpu_accounting = false; + static bool arg_default_blockio_accounting = false; + static bool arg_default_memory_accounting = false; + static usec_t arg_start_timeout_usec = DEFAULT_MANAGER_START_TIMEOUT_USEC; +-static FailureAction arg_start_timeout_action = FAILURE_ACTION_REBOOT_FORCE; ++static FailureAction arg_start_timeout_action = FAILURE_ACTION_POWEROFF_FORCE; + static char *arg_start_timeout_reboot_arg = NULL; + + static void nop_handler(int sig) {} +diff --git a/src/core/manager.c b/src/core/manager.c +index 7508fefaef..7639aeef19 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -436,7 +436,7 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) { + m->exit_code = _MANAGER_EXIT_CODE_INVALID; + m->default_timer_accuracy_usec = USEC_PER_MINUTE; + m->start_timeout_usec = DEFAULT_MANAGER_START_TIMEOUT_USEC; +- m->start_timeout_action = FAILURE_ACTION_REBOOT_FORCE; ++ m->start_timeout_action = FAILURE_ACTION_POWEROFF_FORCE; + + m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; + +diff --git a/src/core/shutdown.c b/src/core/shutdown.c +index 1abc140e7d..0e2ea5754f 100644 +--- a/src/core/shutdown.c ++++ b/src/core/shutdown.c +@@ -435,8 +435,7 @@ int main(int argc, char *argv[]) { + + if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { + log_info("Rebooting with argument '%s'.", param); +- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, +- LINUX_REBOOT_CMD_RESTART2, param); ++ syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); + } + } + +diff --git a/src/core/system.conf b/src/core/system.conf +index 45448de328..5a723bb20e 100644 +--- a/src/core/system.conf ++++ b/src/core/system.conf +@@ -24,7 +24,7 @@ + #SystemCallArchitectures= + #TimerSlackNSec= + #StartTimeoutSec=15min +-#StartTimeoutAction=reboot-force ++#StartTimeoutAction=poweroff-force + #StartTimeoutRebootArgument= + #DefaultTimerAccuracySec=1min + #DefaultStandardOutput=journal diff --git a/0042-core-split-up-starting-manager-state-into-initializi.patch b/0042-core-split-up-starting-manager-state-into-initializi.patch new file mode 100644 index 0000000..a31ac63 --- /dev/null +++ b/0042-core-split-up-starting-manager-state-into-initializi.patch @@ -0,0 +1,88 @@ +From d81afec1c9bf4b73e3df8996d65ecae95d19b6db Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Aug 2014 18:07:18 +0200 +Subject: [PATCH] core: split up "starting" manager state into "initializing" + and "starting" + +We'll stay in "initializing" until basic.target has reached, at which +point we will enter "starting". + +This is preparation so that we can change the startip timeout to only +apply to the first phase of startup, not the full procedure. +--- + src/core/cgroup.c | 4 ++-- + src/core/manager.c | 11 +++++++++-- + src/core/manager.h | 1 + + 3 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 9248cb523b..6c6e4f5e7b 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -300,7 +300,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha + char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1]; + + sprintf(buf, "%lu\n", +- state == MANAGER_STARTING && c->startup_cpu_shares != (unsigned long) -1 ? c->startup_cpu_shares : ++ 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); + r = cg_set_attribute("cpu", path, "cpu.shares", buf); + if (r < 0) +@@ -328,7 +328,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha + CGroupBlockIODeviceBandwidth *b; + + if (!is_root) { +- sprintf(buf, "%lu\n", state == MANAGER_STARTING && c->startup_blockio_weight != (unsigned long) -1 ? c->startup_blockio_weight : ++ 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); + r = cg_set_attribute("blkio", path, "blkio.weight", buf); + if (r < 0) +diff --git a/src/core/manager.c b/src/core/manager.c +index 7639aeef19..9abdf475cf 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2837,7 +2837,7 @@ static bool manager_get_show_status(Manager *m) { + if (m->no_console_output) + return false; + +- if (!IN_SET(manager_state(m), MANAGER_STARTING, MANAGER_STOPPING)) ++ if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING)) + return false; + + if (m->show_status > 0) +@@ -2928,8 +2928,14 @@ ManagerState manager_state(Manager *m) { + assert(m); + + /* Did we ever finish booting? If not then we are still starting up */ +- if (!dual_timestamp_is_set(&m->finish_timestamp)) ++ if (!dual_timestamp_is_set(&m->finish_timestamp)) { ++ ++ u = manager_get_unit(m, SPECIAL_BASIC_TARGET); ++ if (!u || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) ++ return MANAGER_INITIALIZING; ++ + return MANAGER_STARTING; ++ } + + /* Is the special shutdown target queued? If so, we are in shutdown state */ + u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); +@@ -2955,6 +2961,7 @@ ManagerState manager_state(Manager *m) { + } + + static const char *const manager_state_table[_MANAGER_STATE_MAX] = { ++ [MANAGER_INITIALIZING] = "initializing", + [MANAGER_STARTING] = "starting", + [MANAGER_RUNNING] = "running", + [MANAGER_DEGRADED] = "degraded", +diff --git a/src/core/manager.h b/src/core/manager.h +index 7d26c3adea..8e3c146b42 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -38,6 +38,7 @@ + typedef struct Manager Manager; + + typedef enum ManagerState { ++ MANAGER_INITIALIZING, + MANAGER_STARTING, + MANAGER_RUNNING, + MANAGER_DEGRADED, diff --git a/0043-update-TODO.patch b/0043-update-TODO.patch new file mode 100644 index 0000000..926e5d6 --- /dev/null +++ b/0043-update-TODO.patch @@ -0,0 +1,32 @@ +From d74f9e8e8a3dcddb043ef193e4bb14f58efa095f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Aug 2014 18:10:22 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/TODO b/TODO +index 3073f3a5a2..0fcd3a0b8e 100644 +--- a/TODO ++++ b/TODO +@@ -24,6 +24,9 @@ External: + + Features: + ++* apply start timeout during the "initializing" manager state only, ++ instead of both "initializing" and "starting". ++ + * journald: make use of uid-range.h to managed uid ranges to split + journals in. + +@@ -138,8 +141,6 @@ Features: + * For timer units: add some mechanisms so that timer units that trigger immediately on boot do not have the services + they run added to the initial transaction and thus confuse Type=idle. + +-* Add timeout to early-boot, and shut down the system if it is hit. Solves the laptop-in-bag problem and is useful for embedded cases +- + * Run most system services with cgroupfs read-only and procfs with a more secure mode (doesn't work, since the hidepid= option is per-pid-namespace, not per-mount) + + * sd-event: generate a failure of a default event loop is executed out-of-thread diff --git a/0044-systemctl-fix-broken-list-unit-files-with-root.patch b/0044-systemctl-fix-broken-list-unit-files-with-root.patch new file mode 100644 index 0000000..016822a --- /dev/null +++ b/0044-systemctl-fix-broken-list-unit-files-with-root.patch @@ -0,0 +1,27 @@ +From 41a451cc2901a5deb985aea4cc8de204a22e5612 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 25 Aug 2014 15:29:50 +0200 +Subject: [PATCH] systemctl: fix broken list-unit-files with --root + +This patch modifies unit_file_get_list which will now return +hashmap of structures where f->path is *without* root_dir prefix. + +This change should be ok, because current code either does not use +root_dir at all or calls basename() on the f->path. +--- + 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 4b09a69456..a07d1dd315 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2099,7 +2099,7 @@ int unit_file_get_list( + if (!f) + return -ENOMEM; + +- f->path = path_make_absolute(de->d_name, units_dir); ++ f->path = path_make_absolute(de->d_name, *i); + if (!f->path) + return -ENOMEM; + diff --git a/0045-sd-event-split-run-into-prepare-wait-dispatch.patch b/0045-sd-event-split-run-into-prepare-wait-dispatch.patch new file mode 100644 index 0000000..2c4ca63 --- /dev/null +++ b/0045-sd-event-split-run-into-prepare-wait-dispatch.patch @@ -0,0 +1,244 @@ +From c45a5a74465a39280b855f9d720b2ab4779a47fa Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 15 Aug 2014 18:49:29 +0200 +Subject: [PATCH] sd-event: split run into prepare/wait/dispatch + +This will allow sd-event to be integrated into an external event loop, which +in turn will allow (say) glib-based applications to use our various libraries, +without manually integrating each of them (bus, rtnl, dhcp, ...). + +The external event-loop should integrate sd-event int he following way: + +Every iteration must start with a call to sd_event_prepare(), which will +return 0 if no event sources are ready to be processed, a positive value if +they are and a negative value on error. sd_event_prepare() may only be called +following sd_event_dispatch(); a call to sd_event_wait() indicating that no +sources are ready to be dispatched; or a failed call to sd_event_dispatch() or +sd_event_wait(). + +A successful call to sd_event_prepare() indicating that no event sources are +ready to be dispatched must be followed by a call to sd_event_wait(), +which will return 0 if it timed out without event sources being ready to +be processed, a negative value on error and a positive value otherwise. +sd_event_wait() may only be called following a successful call to +sd_event_prepare() indicating that no event sources are ready to be dispatched. + +If sd_event_wait() indicates that some events sources are ready to be +dispatched, it must be followed by a call to sd_event_dispatch(). This +is the only time sd_event_dispatch() may be called. +--- + src/libsystemd/sd-event/sd-event.c | 122 +++++++++++++++++++++++++++++-------- + src/systemd/sd-event.h | 5 ++ + 2 files changed, 102 insertions(+), 25 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index e062997a80..a71962c24c 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2210,12 +2210,8 @@ static int process_watchdog(sd_event *e) { + return arm_watchdog(e); + } + +-_public_ int sd_event_run(sd_event *e, uint64_t timeout) { +- struct epoll_event *ev_queue; +- unsigned ev_queue_max; +- sd_event_source *p; +- int r, i, m; +- bool timedout; ++_public_ int sd_event_prepare(sd_event *e) { ++ int r; + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); +@@ -2223,38 +2219,60 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY); + + if (e->exit_requested) +- return dispatch_exit(e); ++ goto pending; + +- sd_event_ref(e); + e->iteration++; +- e->state = SD_EVENT_RUNNING; + + r = event_prepare(e); + if (r < 0) +- goto finish; ++ return r; + + r = event_arm_timer(e, &e->realtime); + if (r < 0) +- goto finish; ++ return r; + + r = event_arm_timer(e, &e->boottime); + if (r < 0) +- goto finish; ++ return r; + + r = event_arm_timer(e, &e->monotonic); + if (r < 0) +- goto finish; ++ return r; + + r = event_arm_timer(e, &e->realtime_alarm); + if (r < 0) +- goto finish; ++ return r; + + r = event_arm_timer(e, &e->boottime_alarm); + if (r < 0) +- goto finish; ++ return r; + + if (event_next_pending(e) || e->need_process_child) +- timeout = 0; ++ goto pending; ++ ++ e->state = SD_EVENT_PREPARED; ++ ++ return 0; ++ ++pending: ++ e->state = SD_EVENT_PREPARED; ++ return sd_event_wait(e, 0); ++} ++ ++_public_ int sd_event_wait(sd_event *e, uint64_t timeout) { ++ struct epoll_event *ev_queue; ++ unsigned ev_queue_max; ++ int r, m, i; ++ ++ assert_return(e, -EINVAL); ++ assert_return(!event_pid_changed(e), -ECHILD); ++ assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); ++ assert_return(e->state == SD_EVENT_PREPARED, -EBUSY); ++ ++ if (e->exit_requested) { ++ e->state = SD_EVENT_PENDING; ++ return 1; ++ } + + ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX); + ev_queue = newa(struct epoll_event, ev_queue_max); +@@ -2262,12 +2280,16 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max, + timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC)); + if (m < 0) { +- r = errno == EAGAIN || errno == EINTR ? 1 : -errno; ++ if (errno == EINTR) { ++ e->state = SD_EVENT_PENDING; ++ return 1; ++ } ++ ++ r = -errno; ++ + goto finish; + } + +- timedout = m == 0; +- + dual_timestamp_get(&e->timestamp); + e->timestamp_boottime = now(CLOCK_BOOTTIME); + +@@ -2324,21 +2346,71 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + goto finish; + } + +- p = event_next_pending(e); +- if (!p) { +- r = !timedout; +- goto finish; ++ if (event_next_pending(e)) { ++ e->state = SD_EVENT_PENDING; ++ ++ return 1; + } + +- r = source_dispatch(p); ++ r = 0; + + finish: + e->state = SD_EVENT_PASSIVE; +- sd_event_unref(e); + + return r; + } + ++_public_ int sd_event_dispatch(sd_event *e) { ++ sd_event_source *p; ++ int r; ++ ++ assert_return(e, -EINVAL); ++ assert_return(!event_pid_changed(e), -ECHILD); ++ assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); ++ assert_return(e->state == SD_EVENT_PENDING, -EBUSY); ++ ++ if (e->exit_requested) ++ return dispatch_exit(e); ++ ++ p = event_next_pending(e); ++ if (p) { ++ sd_event_ref(e); ++ ++ e->state = SD_EVENT_RUNNING; ++ r = source_dispatch(p); ++ e->state = SD_EVENT_PASSIVE; ++ ++ sd_event_unref(e); ++ ++ return r; ++ } ++ ++ e->state = SD_EVENT_PASSIVE; ++ ++ return 1; ++} ++ ++_public_ int sd_event_run(sd_event *e, uint64_t timeout) { ++ int r; ++ ++ assert_return(e, -EINVAL); ++ assert_return(!event_pid_changed(e), -ECHILD); ++ assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); ++ assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY); ++ ++ r = sd_event_prepare(e); ++ if (r > 0) ++ return sd_event_dispatch(e); ++ else if (r < 0) ++ return r; ++ ++ r = sd_event_wait(e, timeout); ++ if (r > 0) ++ return sd_event_dispatch(e); ++ else ++ return r; ++} ++ + _public_ int sd_event_loop(sd_event *e) { + int r; + +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index d96852a763..8e013b33f6 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -52,6 +52,8 @@ enum { + + enum { + SD_EVENT_PASSIVE, ++ SD_EVENT_PREPARED, ++ SD_EVENT_PENDING, + SD_EVENT_RUNNING, + SD_EVENT_EXITING, + SD_EVENT_FINISHED +@@ -84,6 +86,9 @@ int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t call + int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); + int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); + ++int sd_event_prepare(sd_event *e); ++int sd_event_wait(sd_event *e, uint64_t timeout); ++int sd_event_dispatch(sd_event *e); + int sd_event_run(sd_event *e, uint64_t timeout); + int sd_event_loop(sd_event *e); + int sd_event_exit(sd_event *e, int code); diff --git a/0046-sd-event-sd_event_prepare-stay-in-PREPARED-if-sd_eve.patch b/0046-sd-event-sd_event_prepare-stay-in-PREPARED-if-sd_eve.patch new file mode 100644 index 0000000..c5cc91f --- /dev/null +++ b/0046-sd-event-sd_event_prepare-stay-in-PREPARED-if-sd_eve.patch @@ -0,0 +1,27 @@ +From 6d148a842ebb04a9a9bc2853e167a9d8eddf8cd8 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 26 Aug 2014 00:22:06 +0200 +Subject: [PATCH] sd-event: sd_event_prepare - stay in PREPARED if + sd_event_wait() indicates that no sources are pending + +--- + src/libsystemd/sd-event/sd-event.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index a71962c24c..32777e386b 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2256,7 +2256,11 @@ _public_ int sd_event_prepare(sd_event *e) { + + pending: + e->state = SD_EVENT_PREPARED; +- return sd_event_wait(e, 0); ++ r = sd_event_wait(e, 0); ++ if (r == 0) ++ e->state = SD_EVENT_PREPARED; ++ ++ return r; + } + + _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { diff --git a/0047-update-TODO.patch b/0047-update-TODO.patch new file mode 100644 index 0000000..ab86dd4 --- /dev/null +++ b/0047-update-TODO.patch @@ -0,0 +1,30 @@ +From 42aeb14a4a0fa7d43da96a8ed0fb0e180a2dd5c8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 03:59:05 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/TODO b/TODO +index 0fcd3a0b8e..471d3b29bc 100644 +--- a/TODO ++++ b/TODO +@@ -24,8 +24,15 @@ External: + + Features: + ++* remove multi-seat-x now ++ ++* refcounting in sd-resolve is borked ++ ++* exponential backoff in timesyncd and resolved when we cannot reach a server ++ + * apply start timeout during the "initializing" manager state only, +- instead of both "initializing" and "starting". ++ instead of both "initializing" and "starting". maybe rename the ++ timeout to "initialization-timeout" then or so? + + * journald: make use of uid-range.h to managed uid ranges to split + journals in. diff --git a/0048-Revert-systemctl-fix-broken-list-unit-files-with-roo.patch b/0048-Revert-systemctl-fix-broken-list-unit-files-with-roo.patch new file mode 100644 index 0000000..a82cbb6 --- /dev/null +++ b/0048-Revert-systemctl-fix-broken-list-unit-files-with-roo.patch @@ -0,0 +1,26 @@ +From 4fc13f521ab44eb55c599b07c18860c1aeca35a7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 04:03:24 +0200 +Subject: [PATCH] Revert "systemctl: fix broken list-unit-files with --root" + +This reverts commit 41a451cc2901a5deb985aea4cc8de204a22e5612. + +This breaks checks for masking of units file, since we invoke +null_or_empty_path() on the resulting path. +--- + 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 a07d1dd315..4b09a69456 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2099,7 +2099,7 @@ int unit_file_get_list( + if (!f) + return -ENOMEM; + +- f->path = path_make_absolute(de->d_name, *i); ++ f->path = path_make_absolute(de->d_name, units_dir); + if (!f->path) + return -ENOMEM; + diff --git a/0049-udev-hwdb-do-not-look-at-usb_device-parents.patch b/0049-udev-hwdb-do-not-look-at-usb_device-parents.patch new file mode 100644 index 0000000..1c6962d --- /dev/null +++ b/0049-udev-hwdb-do-not-look-at-usb_device-parents.patch @@ -0,0 +1,60 @@ +From 77cf759ea05bea476cdcb8d0dcd04c4e6fb3b2ff Mon Sep 17 00:00:00 2001 +From: Kay Sievers +Date: Tue, 26 Aug 2014 18:27:36 +0200 +Subject: [PATCH] udev: hwdb - do not look at "usb_device" parents + +Based on a patch from Simon McVittie . + +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=758050 +--- + src/udev/udev-builtin-hwdb.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c +index cac97e756b..695a31a12f 100644 +--- a/src/udev/udev-builtin-hwdb.c ++++ b/src/udev/udev-builtin-hwdb.c +@@ -88,9 +88,10 @@ static int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device + const char *filter, bool test) { + struct udev_device *d; + char s[16]; +- int n = 0; ++ bool last = false; ++ int r = 0; + +- for (d = srcdev; d; d = udev_device_get_parent(d)) { ++ for (d = srcdev; d && !last; d = udev_device_get_parent(d)) { + const char *dsubsys; + const char *modalias = NULL; + +@@ -104,19 +105,24 @@ static int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device + + modalias = udev_device_get_property_value(d, "MODALIAS"); + +- /* the usb_device does not have a modalias, compose one */ +- if (!modalias && streq(dsubsys, "usb")) +- modalias = modalias_usb(d, s, sizeof(s)); ++ if (streq(dsubsys, "usb") && streq_ptr(udev_device_get_devtype(d), "usb_device")) { ++ /* if the usb_device does not have a modalias, compose one */ ++ if (!modalias) ++ modalias = modalias_usb(d, s, sizeof(s)); ++ ++ /* avoid looking at any parent device, they are usually just a USB hub */ ++ last = true; ++ } + + if (!modalias) + continue; + +- n = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test); +- if (n > 0) ++ r = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test); ++ if (r > 0) + break; + } + +- return n; ++ return r; + } + + static int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) { diff --git a/0050-update-TODO.patch b/0050-update-TODO.patch new file mode 100644 index 0000000..c099f42 --- /dev/null +++ b/0050-update-TODO.patch @@ -0,0 +1,24 @@ +From 8dac15b6e9792c2b0f503ddf78ac499817904a6f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 20:23:49 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/TODO b/TODO +index 471d3b29bc..09f82d3c37 100644 +--- a/TODO ++++ b/TODO +@@ -24,6 +24,10 @@ External: + + Features: + ++* dbus: add new message hdr field for allowing interactive auth, write spec for it. update dbus spec to mandate that unknown flags *must* be ignored... ++ ++* maybe introduce AssertXYZ= similar to ConditionXYZ= that causes a unit to fail (instead of skipping it) if some condition is not true... ++ + * remove multi-seat-x now + + * refcounting in sd-resolve is borked diff --git a/0051-NEWS-Fix-typos.patch b/0051-NEWS-Fix-typos.patch new file mode 100644 index 0000000..2e3e7fd --- /dev/null +++ b/0051-NEWS-Fix-typos.patch @@ -0,0 +1,33 @@ +From daa05349dfefb12638c96e034c11be613bdc39b7 Mon Sep 17 00:00:00 2001 +From: Ansgar Burchardt +Date: Tue, 26 Aug 2014 00:19:54 +0200 +Subject: [PATCH] NEWS: Fix typos. + +--- + NEWS | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/NEWS b/NEWS +index 7dad765a33..2fca2cdc93 100644 +--- a/NEWS ++++ b/NEWS +@@ -42,8 +42,8 @@ CHANGES WITH 216: + + * systemd-resolved now includes a caching DNS stub resolver + and a complete LLMNR name resolution implementation. A new +- NSS module "nss-resolve" has been added which make be used +- of glibc's own "nss-dns" to resolve hostnames via ++ NSS module "nss-resolve" has been added which can be used ++ instead of glibc's own "nss-dns" to resolve hostnames via + systemd-resolved. Hostnames, addresses and arbitrary RRs may + be resolved via systemd-resolved D-Bus APIs. In contrast to + the glibc internal resolver systemd-resolved is aware of +@@ -606,7 +606,7 @@ CHANGES WITH 214: + + * Access modes specified in tmpfiles snippets may now be + prefixed with "~", which indicates that they shall be masked +- by whether the existing file or directly is currently ++ by whether the existing file or directory is currently + writable, readable or executable at all. Also, if specified, + the sgid/suid/sticky bits will be masked for all + non-directories. diff --git a/0052-missing-add-BPF_XOR.patch b/0052-missing-add-BPF_XOR.patch new file mode 100644 index 0000000..774508b --- /dev/null +++ b/0052-missing-add-BPF_XOR.patch @@ -0,0 +1,22 @@ +From 7965435e588c8d2fb824c5fd4b8c2739bc30acdf Mon Sep 17 00:00:00 2001 +From: Michael Olbrich +Date: Thu, 21 Aug 2014 12:38:08 +0200 +Subject: [PATCH] missing: add BPF_XOR + +BPF_XOR was introduced in kernel 3.7 +--- + src/shared/missing.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index a9dd274274..c80ed2ad99 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -593,3 +593,7 @@ static inline int setns(int fd, int nstype) { + #ifndef NET_NAME_RENAMED + # define NET_NAME_RENAMED 4 + #endif ++ ++#ifndef BPF_XOR ++# define BPF_XOR 0xa0 ++#endif diff --git a/0053-networkd-wait-online-add-missing-short-option-i-to-o.patch b/0053-networkd-wait-online-add-missing-short-option-i-to-o.patch new file mode 100644 index 0000000..08adf9c --- /dev/null +++ b/0053-networkd-wait-online-add-missing-short-option-i-to-o.patch @@ -0,0 +1,23 @@ +From 32dfe42c66085c55916e5306a9a07d42d3958b6b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= +Date: Tue, 26 Aug 2014 12:28:28 +0200 +Subject: [PATCH] networkd-wait-online: add missing short option 'i' to + optstring + +--- + src/network/networkd-wait-online.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c +index 6c2fdd1b2c..714343656b 100644 +--- a/src/network/networkd-wait-online.c ++++ b/src/network/networkd-wait-online.c +@@ -59,7 +59,7 @@ static int parse_argv(int argc, char *argv[]) { + assert(argc >= 0); + assert(argv); + +- while ((c = getopt_long(argc, argv, "+hq", options, NULL)) >= 0) ++ while ((c = getopt_long(argc, argv, "+hiq", options, NULL)) >= 0) + + switch (c) { + diff --git a/0054-test-compress-make-sure-asserts-with-side-effects-us.patch b/0054-test-compress-make-sure-asserts-with-side-effects-us.patch new file mode 100644 index 0000000..e3a2e7d --- /dev/null +++ b/0054-test-compress-make-sure-asserts-with-side-effects-us.patch @@ -0,0 +1,33 @@ +From 52754725e185f1331f821d85ed2ef78fb92af1fe Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Mon, 25 Aug 2014 22:05:02 -0700 +Subject: [PATCH] test-compress: make sure asserts with side effects use + assert_se() + +Otherwise the test fails when built with CPPFLAGS='-DNDEBUG' which disables +assertions. + +Tested: +- make check TESTS='test-compress' CPPFLAGS='-DNDEBUG' +--- + src/journal/test-compress.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c +index f5f5f8df39..026d630ac2 100644 +--- a/src/journal/test-compress.c ++++ b/src/journal/test-compress.c +@@ -145,11 +145,11 @@ static void test_compress_stream(int compression, + + assert_se((dst = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC)) >= 0); + +- assert(compress(src, dst, -1) == 0); ++ assert_se(compress(src, dst, -1) == 0); + + if (cat) { + assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0); +- assert(system(cmd) == 0); ++ assert_se(system(cmd) == 0); + } + + log_debug("/* test decompression */"); diff --git a/0055-test-path-util-use-assert_se-in-all-assertions.patch b/0055-test-path-util-use-assert_se-in-all-assertions.patch new file mode 100644 index 0000000..f98092a --- /dev/null +++ b/0055-test-path-util-use-assert_se-in-all-assertions.patch @@ -0,0 +1,78 @@ +From 8d95631ea6c039a60bb7ac456f687a8fdf0c4381 Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Mon, 25 Aug 2014 22:05:03 -0700 +Subject: [PATCH] test-path-util: use assert_se in all assertions + +Otherwise they get optimized out when CPPFLAGS='-DNDEBUG' is used, and that +causes the tests to fail. + +Tested: +- make check TESTS='test-path-util' CPPFLAGS='-DNDEBUG' +--- + src/test/test-path-util.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index c8dcd85397..01afb3e6fe 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -79,35 +79,35 @@ static void test_path(void) { + char p2[] = "//aaa/.////ccc"; + char p3[] = "/./"; + +- assert(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc")); +- assert(path_equal(path_kill_slashes(p2), "/aaa/./ccc")); +- assert(path_equal(path_kill_slashes(p3), "/./")); ++ assert_se(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc")); ++ assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc")); ++ assert_se(path_equal(path_kill_slashes(p3), "/./")); + } + } + + static void test_find_binary(const char *self) { + char *p; + +- assert(find_binary("/bin/sh", &p) == 0); ++ assert_se(find_binary("/bin/sh", &p) == 0); + puts(p); +- assert(streq(p, "/bin/sh")); ++ assert_se(streq(p, "/bin/sh")); + free(p); + +- assert(find_binary(self, &p) == 0); ++ assert_se(find_binary(self, &p) == 0); + puts(p); +- assert(endswith(p, "/test-path-util")); +- assert(path_is_absolute(p)); ++ assert_se(endswith(p, "/test-path-util")); ++ assert_se(path_is_absolute(p)); + free(p); + +- assert(find_binary("sh", &p) == 0); ++ assert_se(find_binary("sh", &p) == 0); + puts(p); +- assert(endswith(p, "/sh")); +- assert(path_is_absolute(p)); ++ assert_se(endswith(p, "/sh")); ++ assert_se(path_is_absolute(p)); + free(p); + +- assert(find_binary("xxxx-xxxx", &p) == -ENOENT); ++ assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT); + +- assert(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT); ++ assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT); + } + + static void test_prefixes(void) { +@@ -156,8 +156,8 @@ static void test_prefixes(void) { + + b = false; + PATH_FOREACH_PREFIX_MORE(s, "") { +- assert(!b); +- assert(streq(s, "")); ++ assert_se(!b); ++ assert_se(streq(s, "")); + b = true; + } + } diff --git a/0056-test-util-use-assert_se-for-call-to-safe_mkdir-with-.patch b/0056-test-util-use-assert_se-for-call-to-safe_mkdir-with-.patch new file mode 100644 index 0000000..7774489 --- /dev/null +++ b/0056-test-util-use-assert_se-for-call-to-safe_mkdir-with-.patch @@ -0,0 +1,27 @@ +From 684fc8927e0f83496d4384ac434e265f7cd7a87b Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Mon, 25 Aug 2014 22:05:04 -0700 +Subject: [PATCH] test-util: use assert_se() for call to safe_mkdir with side + effect + +Otherwise it gets optimized out when CPPFLAGS='-DNDEBUG' is used. + +Tested: +- make check TESTS='test-util' CPPFLAGS='-DNDEBUG' +--- + src/test/test-util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 34d5f2ed7d..4d9b28f9c8 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -863,7 +863,7 @@ static void test_readlink_and_make_absolute(void) { + char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; + char *r = NULL; + +- assert(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); ++ assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); + assert_se(touch(name) >= 0); + + assert_se(symlink(name, name_alias) >= 0); diff --git a/0057-sd-bus-remove-unused-call-bus_kernel_create_monitor.patch b/0057-sd-bus-remove-unused-call-bus_kernel_create_monitor.patch new file mode 100644 index 0000000..29cc849 --- /dev/null +++ b/0057-sd-bus-remove-unused-call-bus_kernel_create_monitor.patch @@ -0,0 +1,65 @@ +From bb19cb17076bbec942ad08f94d41ba36b28a5a13 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 20:35:31 +0200 +Subject: [PATCH] sd-bus: remove unused call bus_kernel_create_monitor() + +Noticed by Djalal Harouni +--- + src/libsystemd/sd-bus/bus-kernel.c | 31 ------------------------------- + src/libsystemd/sd-bus/bus-kernel.h | 1 - + 2 files changed, 32 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 3ca271c704..03c4165095 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -1535,37 +1535,6 @@ int bus_kernel_create_domain(const char *name, char **s) { + return fd; + } + +-int bus_kernel_create_monitor(const char *bus) { +- struct kdbus_cmd_hello *hello; +- int fd; +- +- assert(bus); +- +- fd = bus_kernel_open_bus_fd(bus, NULL); +- if (fd < 0) +- return fd; +- +- hello = alloca0(sizeof(struct kdbus_cmd_hello)); +- hello->size = sizeof(struct kdbus_cmd_hello); +- hello->conn_flags = KDBUS_HELLO_ACTIVATOR; +- hello->pool_size = KDBUS_POOL_SIZE; +- +- if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) { +- safe_close(fd); +- return -errno; +- } +- +- /* The higher 32bit of both flags fields are considered +- * 'incompatible flags'. Refuse them all for now. */ +- if (hello->bus_flags > 0xFFFFFFFFULL || +- hello->conn_flags > 0xFFFFFFFFULL) { +- safe_close(fd); +- return -ENOTSUP; +- } +- +- return fd; +-} +- + int bus_kernel_try_close(sd_bus *bus) { + assert(bus); + assert(bus->is_kernel); +diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h +index 87f98c58bf..448dd3a797 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.h ++++ b/src/libsystemd/sd-bus/bus-kernel.h +@@ -70,7 +70,6 @@ int bus_kernel_make_starter(int fd, const char *name, bool activating, bool acce + + int bus_kernel_create_bus(const char *name, bool world, char **s); + int bus_kernel_create_domain(const char *name, char **s); +-int bus_kernel_create_monitor(const char *bus); + + int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated); + void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated); diff --git a/0058-systemctl-Correct-error-message-printed-when-bus_pro.patch b/0058-systemctl-Correct-error-message-printed-when-bus_pro.patch new file mode 100644 index 0000000..deba562 --- /dev/null +++ b/0058-systemctl-Correct-error-message-printed-when-bus_pro.patch @@ -0,0 +1,25 @@ +From 498cfc230af8f83675be2e92057956f1792969e4 Mon Sep 17 00:00:00 2001 +From: Sjoerd Simons +Date: Sat, 23 Aug 2014 21:11:44 +0200 +Subject: [PATCH] systemctl: Correct error message printed when + bus_process_wait fails + +Actually use the variable containing the return code of bus_process_wait when +printing the error message as a result of it failing. +--- + 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 d9b8bee28d..65348193b7 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -2382,7 +2382,7 @@ static int wait_for_jobs(sd_bus *bus, Set *s) { + while (!set_isempty(s)) { + q = bus_process_wait(bus); + if (q < 0) { +- log_error("Failed to wait for response: %s", strerror(-r)); ++ log_error("Failed to wait for response: %s", strerror(-q)); + return q; + } + diff --git a/0059-sd-bus-don-t-include-internal-header-memfd.h-in-publ.patch b/0059-sd-bus-don-t-include-internal-header-memfd.h-in-publ.patch new file mode 100644 index 0000000..a336fd9 --- /dev/null +++ b/0059-sd-bus-don-t-include-internal-header-memfd.h-in-publ.patch @@ -0,0 +1,36 @@ +From f2322f0b64107b2eee1fadb6c59857381277a9f8 Mon Sep 17 00:00:00 2001 +From: Hristo Venev +Date: Tue, 26 Aug 2014 20:40:35 +0200 +Subject: [PATCH] sd-bus: don't include internal header memfd.h in public + header sd-bus.h + +https://bugs.freedesktop.org/show_bug.cgi?id=83097 +--- + src/libsystemd/sd-bus/bus-message.c | 1 + + src/systemd/sd-bus.h | 1 - + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index c058b06f41..d00455a112 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -28,6 +28,7 @@ + #include "strv.h" + #include "time-util.h" + #include "cgroup-util.h" ++#include "memfd.h" + + #include "sd-bus.h" + #include "bus-message.h" +diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h +index 1e23a93a60..036ab556c1 100644 +--- a/src/systemd/sd-bus.h ++++ b/src/systemd/sd-bus.h +@@ -28,7 +28,6 @@ + + #include "sd-id128.h" + #include "sd-event.h" +-#include "memfd.h" + #include "_sd-common.h" + + _SD_BEGIN_DECLARATIONS; diff --git a/0060-util-make-sure-reset_all_signal_handlers-continues-w.patch b/0060-util-make-sure-reset_all_signal_handlers-continues-w.patch new file mode 100644 index 0000000..a185edd --- /dev/null +++ b/0060-util-make-sure-reset_all_signal_handlers-continues-w.patch @@ -0,0 +1,47 @@ +From 24a5d6b04e17d447cf122f02a8a2dedd843cce45 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 21:03:20 +0200 +Subject: [PATCH] util: make sure reset_all_signal_handlers() continues with + all other signal handlers when one sigaction() fails + +After all, we usually don't check for failures here, and it is better to +do as much as we can... +--- + src/shared/util.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index fc6f668726..4af2d3ceba 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -937,7 +937,7 @@ int readlink_and_canonicalize(const char *p, char **r) { + } + + int reset_all_signal_handlers(void) { +- int sig; ++ int sig, r = 0; + + for (sig = 1; sig < _NSIG; sig++) { + struct sigaction sa = { +@@ -945,17 +945,18 @@ int reset_all_signal_handlers(void) { + .sa_flags = SA_RESTART, + }; + ++ /* These two cannot be caught... */ + if (sig == SIGKILL || sig == SIGSTOP) + continue; + + /* On Linux the first two RT signals are reserved by + * glibc, and sigaction() will return EINVAL for them. */ + if ((sigaction(sig, &sa, NULL) < 0)) +- if (errno != EINVAL) +- return -errno; ++ if (errno != EINVAL && r == 0) ++ r = -errno; + } + +- return 0; ++ return r; + } + + char *strstrip(char *s) { diff --git a/0061-util-reset-signals-when-we-fork-off-agents.patch b/0061-util-reset-signals-when-we-fork-off-agents.patch new file mode 100644 index 0000000..8dfe2e2 --- /dev/null +++ b/0061-util-reset-signals-when-we-fork-off-agents.patch @@ -0,0 +1,66 @@ +From 1dedb74a2e1d840b531b76b01a76979f3b57456b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 21:04:21 +0200 +Subject: [PATCH] util: reset signals when we fork off agents + +If we invoke agents, we should make sure we actually can kill them +again. I mean, it's probably not our job to cleanup the signals if our +tools are invoked in weird contexts, but at least we should make sure, +that the subprocesses we invoke and intend to control work as intended. + +Also see: + +http://lists.freedesktop.org/archives/systemd-devel/2014-August/022460.html +--- + src/shared/util.c | 18 ++++++++++++++++++ + src/shared/util.h | 1 + + 2 files changed, 19 insertions(+) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 4af2d3ceba..98c07163da 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -959,6 +959,18 @@ int reset_all_signal_handlers(void) { + return r; + } + ++int reset_signal_mask(void) { ++ sigset_t ss; ++ ++ if (sigemptyset(&ss) < 0) ++ return -errno; ++ ++ if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) ++ return -errno; ++ ++ return 0; ++} ++ + char *strstrip(char *s) { + char *e; + +@@ -5131,6 +5143,12 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa + /* Don't leak fds to the agent */ + close_all_fds(except, n_except); + ++ /* Make sure we actually can kill the agent, if we need to, in ++ * case somebody invoked us from a shell script that trapped ++ * SIGTERM or so... */ ++ reset_all_signal_handlers(); ++ reset_signal_mask(); ++ + stdout_is_tty = isatty(STDOUT_FILENO); + stderr_is_tty = isatty(STDERR_FILENO); + +diff --git a/src/shared/util.h b/src/shared/util.h +index cd947dbbef..ea87c96956 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -274,6 +274,7 @@ int readlink_and_make_absolute(const char *p, char **r); + int readlink_and_canonicalize(const char *p, char **r); + + int reset_all_signal_handlers(void); ++int reset_signal_mask(void); + + char *strstrip(char *s); + char *delete_chars(char *s, const char *bad); diff --git a/0062-util-make-use-of-newly-added-reset_signal_mask-call-.patch b/0062-util-make-use-of-newly-added-reset_signal_mask-call-.patch new file mode 100644 index 0000000..df4bb59 --- /dev/null +++ b/0062-util-make-use-of-newly-added-reset_signal_mask-call-.patch @@ -0,0 +1,101 @@ +From 1b6d7fa742e303611dff8d7ebfa86ee5fb8b7dc7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 21:11:35 +0200 +Subject: [PATCH] util: make use of newly added reset_signal_mask() call + wherever appropriate + +--- + src/core/execute.c | 6 ++---- + src/core/main.c | 7 ++----- + src/nspawn/nspawn.c | 4 +--- + src/shared/util.c | 5 +---- + 4 files changed, 6 insertions(+), 16 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index b5b22472d5..066efd6fdf 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1301,7 +1301,6 @@ int exec_spawn(ExecCommand *command, + int dont_close[n_fds + 3]; + uid_t uid = (uid_t) -1; + gid_t gid = (gid_t) -1; +- sigset_t ss; + int i, err; + + /* child */ +@@ -1319,9 +1318,8 @@ int exec_spawn(ExecCommand *command, + if (context->ignore_sigpipe) + ignore_signals(SIGPIPE, -1); + +- assert_se(sigemptyset(&ss) == 0); +- if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) { +- err = -errno; ++ err = reset_signal_mask(); ++ if (err < 0) { + r = EXIT_SIGNAL_MASK; + goto fail_child; + } +diff --git a/src/core/main.c b/src/core/main.c +index bd148b1b33..95ab40fffc 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1834,7 +1834,6 @@ finish: + if (reexecute) { + const char **args; + unsigned i, args_size; +- sigset_t ss; + + /* Close and disarm the watchdog, so that the new + * instance can reinitialize it, but doesn't get +@@ -1918,12 +1917,10 @@ finish: + args[i++] = NULL; + assert(i <= args_size); + +- /* reenable any blocked signals, especially important ++ /* Reenable any blocked signals, especially important + * if we switch from initial ramdisk to init=... */ + reset_all_signal_handlers(); +- +- assert_se(sigemptyset(&ss) == 0); +- assert_se(sigprocmask(SIG_SETMASK, &ss, NULL) == 0); ++ reset_signal_mask(); + + if (switch_root_init) { + args[0] = switch_root_init; +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 2c718557ee..56d9cc68c6 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -3156,9 +3156,7 @@ int main(int argc, char *argv[]) { + kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); + + reset_all_signal_handlers(); +- +- assert_se(sigemptyset(&mask) == 0); +- assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); ++ reset_signal_mask(); + + k = open_terminal(console, O_RDWR); + if (k != STDIN_FILENO) { +diff --git a/src/shared/util.c b/src/shared/util.c +index 98c07163da..fdcf5719fa 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3890,16 +3890,13 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv + _cleanup_hashmap_free_free_ Hashmap *pids = NULL; + _cleanup_closedir_ DIR *_d = NULL; + struct dirent *de; +- sigset_t ss; + + /* We fork this all off from a child process so that + * we can somewhat cleanly make use of SIGALRM to set + * a time limit */ + + reset_all_signal_handlers(); +- +- assert_se(sigemptyset(&ss) == 0); +- assert_se(sigprocmask(SIG_SETMASK, &ss, NULL) == 0); ++ reset_signal_mask(); + + assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); + diff --git a/0063-sd-journal-never-log-anything-by-default-from-a-libr.patch b/0063-sd-journal-never-log-anything-by-default-from-a-libr.patch new file mode 100644 index 0000000..5fa5aad --- /dev/null +++ b/0063-sd-journal-never-log-anything-by-default-from-a-libr.patch @@ -0,0 +1,22 @@ +From 36202fd2bc252616966166c98ccb0e0e5ece1fc9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 26 Aug 2014 21:47:46 +0200 +Subject: [PATCH] sd-journal: never log anything by default from a library + +--- + 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 b9ec90230d..80ff8fef57 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -2557,7 +2557,7 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ + + /* Let's do the type check by hand, since we used 0 context above. */ + if (o->object.type != OBJECT_DATA) { +- log_error("%s:offset " OFSfmt ": object has type %d, expected %d", ++ log_debug("%s:offset " OFSfmt ": object has type %d, expected %d", + j->unique_file->path, j->unique_offset, + o->object.type, OBJECT_DATA); + return -EBADMSG; diff --git a/0064-logind-add-HandleLidSwitchDocked-option-to-logind.co.patch b/0064-logind-add-HandleLidSwitchDocked-option-to-logind.co.patch new file mode 100644 index 0000000..c8eb27b --- /dev/null +++ b/0064-logind-add-HandleLidSwitchDocked-option-to-logind.co.patch @@ -0,0 +1,244 @@ +From 3c56cab44150ad47323970cfadfb0257c6305a74 Mon Sep 17 00:00:00 2001 +From: Ben Wolsieffer +Date: Tue, 26 Aug 2014 22:08:02 +0200 +Subject: [PATCH] logind: add HandleLidSwitchDocked= option to logind.conf + + documentation + +https://bugs.freedesktop.org/show_bug.cgi?id=82485 +--- + man/logind.conf.xml | 16 +++++++++++----- + src/login/logind-action.c | 18 ------------------ + src/login/logind-button.c | 18 ++++++++++++++++-- + src/login/logind-core.c | 22 ++++++++++++++++++++++ + src/login/logind-dbus.c | 1 + + src/login/logind-gperf.gperf | 1 + + src/login/logind.c | 7 +++++-- + src/login/logind.conf | 1 + + src/login/logind.h | 2 ++ + 9 files changed, 59 insertions(+), 27 deletions(-) + +diff --git a/man/logind.conf.xml b/man/logind.conf.xml +index f037da259b..8ba95230be 100644 +--- a/man/logind.conf.xml ++++ b/man/logind.conf.xml +@@ -224,6 +224,7 @@ + HandleSuspendKey= + HandleHibernateKey= + HandleLidSwitch= ++ HandleLidSwitchDocked= + + Controls whether + logind shall handle the system power +@@ -255,13 +256,18 @@ + and + HandleLidSwitch= + default to suspend. ++ HandleLidSwitchDocked= ++ defaults to ignore. + HandleHibernateKey= + defaults to +- hibernate. Note +- that the lid switch is ignored if the +- system is inserted in a docking +- station, or if more than one display +- is connected. ++ hibernate. If the ++ system is inserted in a docking station, ++ or if more than one display is connected, ++ the action specified by ++ HandleLidSwitchDocked= ++ occurs; otherwise the ++ HandleLidSwitch= ++ action occurs. + + + +diff --git a/src/login/logind-action.c b/src/login/logind-action.c +index 36ee4418b8..0844df20a9 100644 +--- a/src/login/logind-action.c ++++ b/src/login/logind-action.c +@@ -71,24 +71,6 @@ int manager_handle_action( + } + + if (inhibit_key == INHIBIT_HANDLE_LID_SWITCH) { +- int n; +- +- /* If we are docked don't react to lid closing */ +- if (manager_is_docked(m)) { +- log_debug("Ignoring lid switch request, system is docked."); +- return 0; +- } +- +- /* If we have more than one display connected, +- * don't react to lid closing. */ +- n = manager_count_displays(m); +- if (n < 0) +- log_warning("Display counting failed: %s", strerror(-n)); +- else if (n > 1) { +- log_debug("Ignoring lid switch request, %i displays connected.", n); +- return 0; +- } +- + /* If the last system suspend or startup is too close, + * let's not suspend for now, to give USB docking + * stations some time to settle so that we can +diff --git a/src/login/logind-button.c b/src/login/logind-button.c +index 2561d13c67..57e619efe6 100644 +--- a/src/login/logind-button.c ++++ b/src/login/logind-button.c +@@ -97,13 +97,27 @@ int button_set_seat(Button *b, const char *sn) { + return 0; + } + ++static void button_lid_switch_handle_action(Manager *manager, bool is_edge) { ++ HandleAction handle_action; ++ ++ assert(manager); ++ ++ /* If we are docked, handle the lid switch differently */ ++ if (manager_is_docked_or_multiple_displays(manager)) ++ handle_action = manager->handle_lid_switch_docked; ++ else ++ handle_action = manager->handle_lid_switch; ++ ++ manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge); ++} ++ + static int button_recheck(sd_event_source *e, void *userdata) { + Button *b = userdata; + + assert(b); + assert(b->lid_closed); + +- manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false); ++ button_lid_switch_handle_action(b->manager, false); + return 1; + } + +@@ -186,7 +200,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u + NULL); + + b->lid_closed = true; +- manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true); ++ button_lid_switch_handle_action(b->manager, true); + button_install_check_event_source(b); + + } else if (ev.code == SW_DOCK) { +diff --git a/src/login/logind-core.c b/src/login/logind-core.c +index 053d2ed63e..ed7ea5da31 100644 +--- a/src/login/logind-core.c ++++ b/src/login/logind-core.c +@@ -537,3 +537,25 @@ int manager_count_displays(Manager *m) { + + return n; + } ++ ++bool manager_is_docked_or_multiple_displays(Manager *m) { ++ int n; ++ ++ /* If we are docked don't react to lid closing */ ++ if (manager_is_docked(m)) { ++ log_debug("System is docked."); ++ return true; ++ } ++ ++ /* If we have more than one display connected, ++ * assume that we are docked. */ ++ n = manager_count_displays(m); ++ if (n < 0) ++ log_warning("Display counting failed: %s", strerror(-n)); ++ else if (n > 1) { ++ log_debug("Multiple (%i) displays connected.", n); ++ return true; ++ } ++ ++ return false; ++} +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index acef5119b1..0b2b7b5afe 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -1919,6 +1919,7 @@ const sd_bus_vtable manager_vtable[] = { + SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0), +diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf +index 006f7286c5..62460673b9 100644 +--- a/src/login/logind-gperf.gperf ++++ b/src/login/logind-gperf.gperf +@@ -24,6 +24,7 @@ Login.HandlePowerKey, config_parse_handle_action, 0, offsetof(Manag + Login.HandleSuspendKey, config_parse_handle_action, 0, offsetof(Manager, handle_suspend_key) + Login.HandleHibernateKey, config_parse_handle_action, 0, offsetof(Manager, handle_hibernate_key) + Login.HandleLidSwitch, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch) ++Login.HandleLidSwitchDocked, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch_docked) + Login.PowerKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, power_key_ignore_inhibited) + Login.SuspendKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, suspend_key_ignore_inhibited) + Login.HibernateKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, hibernate_key_ignore_inhibited) +diff --git a/src/login/logind.c b/src/login/logind.c +index 52e1c43a47..1f94a97bd0 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -55,6 +55,7 @@ Manager *manager_new(void) { + m->handle_suspend_key = HANDLE_SUSPEND; + m->handle_hibernate_key = HANDLE_HIBERNATE; + m->handle_lid_switch = HANDLE_SUSPEND; ++ m->handle_lid_switch_docked = HANDLE_IGNORE; + m->lid_switch_ignore_inhibited = true; + + m->idle_action_usec = 30 * USEC_PER_MINUTE; +@@ -232,7 +233,8 @@ static int manager_enumerate_buttons(Manager *m) { + if (m->handle_power_key == HANDLE_IGNORE && + m->handle_suspend_key == HANDLE_IGNORE && + m->handle_hibernate_key == HANDLE_IGNORE && +- m->handle_lid_switch == HANDLE_IGNORE) ++ m->handle_lid_switch == HANDLE_IGNORE && ++ m->handle_lid_switch_docked == HANDLE_IGNORE) + return 0; + + e = udev_enumerate_new(m->udev); +@@ -875,7 +877,8 @@ static int manager_connect_udev(Manager *m) { + if (m->handle_power_key != HANDLE_IGNORE || + m->handle_suspend_key != HANDLE_IGNORE || + m->handle_hibernate_key != HANDLE_IGNORE || +- m->handle_lid_switch != HANDLE_IGNORE) { ++ m->handle_lid_switch != HANDLE_IGNORE || ++ m->handle_lid_switch_docked != HANDLE_IGNORE) { + + m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_button_monitor) +diff --git a/src/login/logind.conf b/src/login/logind.conf +index 79f96ec05b..4608a2c0e2 100644 +--- a/src/login/logind.conf ++++ b/src/login/logind.conf +@@ -18,6 +18,7 @@ + #HandleSuspendKey=suspend + #HandleHibernateKey=hibernate + #HandleLidSwitch=suspend ++#HandleLidSwitchDocked=ignore + #PowerKeyIgnoreInhibited=no + #SuspendKeyIgnoreInhibited=no + #HibernateKeyIgnoreInhibited=no +diff --git a/src/login/logind.h b/src/login/logind.h +index 31353eff02..2f76572580 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -114,6 +114,7 @@ struct Manager { + HandleAction handle_suspend_key; + HandleAction handle_hibernate_key; + HandleAction handle_lid_switch; ++ HandleAction handle_lid_switch_docked; + + bool power_key_ignore_inhibited; + bool suspend_key_ignore_inhibited; +@@ -159,6 +160,7 @@ int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session); + + bool manager_is_docked(Manager *m); + int manager_count_displays(Manager *m); ++bool manager_is_docked_or_multiple_displays(Manager *m); + + extern const sd_bus_vtable manager_vtable[]; + diff --git a/0065-units-order-systemd-fsck-.service-after-local-fs-pre.patch b/0065-units-order-systemd-fsck-.service-after-local-fs-pre.patch new file mode 100644 index 0000000..9125b00 --- /dev/null +++ b/0065-units-order-systemd-fsck-.service-after-local-fs-pre.patch @@ -0,0 +1,25 @@ +From 66f311206e908a5b6f21e66fad73e1e5ea3e31d6 Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Wed, 27 Aug 2014 00:17:43 +0400 +Subject: [PATCH] units: order systemd-fsck@.service after local-fs-pre.target. + +With this change, it becomes possible to order a unit to activate before any +modifications to the file systems. This is especially useful for supporting +resume from hibernation. +--- + units/systemd-fsck@.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in +index c12efa8e76..d2cda6a466 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=systemd-readahead-collect.service systemd-readahead-replay.service %i.device systemd-fsck-root.service ++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/0066-hibernate-resume-add-a-tool-to-write-a-device-node-s.patch b/0066-hibernate-resume-add-a-tool-to-write-a-device-node-s.patch new file mode 100644 index 0000000..eb85996 --- /dev/null +++ b/0066-hibernate-resume-add-a-tool-to-write-a-device-node-s.patch @@ -0,0 +1,353 @@ +From 42483a747489ff46aed3588b78bf4b9480dbeaf7 Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Wed, 27 Aug 2014 00:17:44 +0400 +Subject: [PATCH] hibernate-resume: add a tool to write a device node's + major:minor to /sys/power/resume. + +This can be used to initiate a resume from hibernation by path to a swap +device containing the hibernation image. + +The respective templated unit is also added. It is instantiated using +path to the desired resume device. +--- + .gitignore | 1 + + Makefile-man.am | 7 +++ + Makefile.am | 17 +++++-- + man/systemd-hibernate-resume@.service.xml | 81 ++++++++++++++++++++++++++++++ + src/hibernate-resume/Makefile | 1 + + src/hibernate-resume/hibernate-resume.c | 81 ++++++++++++++++++++++++++++++ + units/.gitignore | 1 + + units/systemd-hibernate-resume@.service.in | 20 ++++++++ + 8 files changed, 206 insertions(+), 3 deletions(-) + create mode 100644 man/systemd-hibernate-resume@.service.xml + create mode 120000 src/hibernate-resume/Makefile + create mode 100644 src/hibernate-resume/hibernate-resume.c + create mode 100644 units/systemd-hibernate-resume@.service.in + +diff --git a/.gitignore b/.gitignore +index 8189da71f0..0b5608ccf9 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -75,6 +75,7 @@ + /systemd-getty-generator + /systemd-gnome-ask-password-agent + /systemd-gpt-auto-generator ++/systemd-hibernate-resume + /systemd-hostnamed + /systemd-inhibit + /systemd-initctl +diff --git a/Makefile-man.am b/Makefile-man.am +index 562ecba435..09a10383a9 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -70,6 +70,7 @@ MANPAGES += \ + man/systemd-getty-generator.8 \ + man/systemd-gpt-auto-generator.8 \ + man/systemd-halt.service.8 \ ++ man/systemd-hibernate-resume@.service.8 \ + man/systemd-inhibit.1 \ + man/systemd-initctl.service.8 \ + man/systemd-journald.service.8 \ +@@ -199,6 +200,7 @@ MANPAGES_ALIAS += \ + man/systemd-firstboot.service.1 \ + man/systemd-fsck-root.service.8 \ + man/systemd-fsck.8 \ ++ man/systemd-hibernate-resume.8 \ + man/systemd-hibernate.service.8 \ + man/systemd-hybrid-sleep.service.8 \ + man/systemd-initctl.8 \ +@@ -305,6 +307,7 @@ man/systemd-ask-password-wall.service.8: man/systemd-ask-password-console.servic + man/systemd-firstboot.service.1: man/systemd-firstboot.1 + man/systemd-fsck-root.service.8: man/systemd-fsck@.service.8 + man/systemd-fsck.8: man/systemd-fsck@.service.8 ++man/systemd-hibernate-resume.8: man/systemd-hibernate-resume@.service.8 + 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 +@@ -567,6 +570,9 @@ man/systemd-fsck-root.service.html: man/systemd-fsck@.service.html + man/systemd-fsck.html: man/systemd-fsck@.service.html + $(html-alias) + ++man/systemd-hibernate-resume.html: man/systemd-hibernate-resume@.service.html ++ $(html-alias) ++ + man/systemd-hibernate.service.html: man/systemd-suspend.service.html + $(html-alias) + +@@ -1619,6 +1625,7 @@ EXTRA_DIST += \ + man/systemd-getty-generator.xml \ + man/systemd-gpt-auto-generator.xml \ + man/systemd-halt.service.xml \ ++ man/systemd-hibernate-resume@.service.xml \ + man/systemd-hostnamed.service.xml \ + man/systemd-inhibit.xml \ + man/systemd-initctl.service.xml \ +diff --git a/Makefile.am b/Makefile.am +index cbf98bdac3..a487caa7bc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -378,7 +378,8 @@ rootlibexec_PROGRAMS = \ + systemd-sleep \ + systemd-bus-proxyd \ + systemd-socket-proxyd \ +- systemd-update-done ++ systemd-update-done \ ++ systemd-hibernate-resume + + systemgenerator_PROGRAMS = \ + systemd-getty-generator \ +@@ -528,7 +529,8 @@ nodist_systemunit_DATA = \ + units/initrd-udevadm-cleanup-db.service \ + units/initrd-switch-root.service \ + units/systemd-nspawn@.service \ +- units/systemd-update-done.service ++ units/systemd-update-done.service \ ++ units/systemd-hibernate-resume@.service + + dist_userunit_DATA = \ + units/user/basic.target \ +@@ -575,7 +577,8 @@ EXTRA_DIST += \ + units/initrd-udevadm-cleanup-db.service.in \ + units/initrd-switch-root.service.in \ + units/systemd-nspawn@.service.in \ +- units/systemd-update-done.service.in ++ units/systemd-update-done.service.in \ ++ units/systemd-hibernate-resume@.service.in + + CLEANFILES += \ + units/console-shell.service.m4 \ +@@ -2103,6 +2106,14 @@ systemd_delta_LDADD = \ + libsystemd-shared.la + + # ------------------------------------------------------------------------------ ++systemd_hibernate_resume_SOURCES = \ ++ src/hibernate-resume/hibernate-resume.c ++ ++systemd_hibernate_resume_LDADD = \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la ++ ++# ------------------------------------------------------------------------------ + systemd_getty_generator_SOURCES = \ + src/getty-generator/getty-generator.c + +diff --git a/man/systemd-hibernate-resume@.service.xml b/man/systemd-hibernate-resume@.service.xml +new file mode 100644 +index 0000000000..9b188b0d96 +--- /dev/null ++++ b/man/systemd-hibernate-resume@.service.xml +@@ -0,0 +1,81 @@ ++ ++ ++ ++ ++ ++ ++ ++ systemd-hibernate-resume@.service ++ systemd ++ ++ ++ ++ Developer ++ Ivan ++ Shapovalov ++ intelfx100@gmail.com ++ ++ ++ ++ ++ ++ systemd-hibernate-resume@.service ++ 8 ++ ++ ++ ++ systemd-hibernate-resume@.service ++ systemd-hibernate-resume ++ Resume from hibernation ++ ++ ++ ++ systemd-hibernate-resume@.service ++ /usr/lib/systemd/systemd-hibernate-resume ++ ++ ++ ++ Description ++ ++ systemd-hibernate-resume@.service is a ++ service that initiates hibernation resume from a device ++ containing the resume image. It is instantiated for each ++ device that is configured for resuming from. ++ ++ systemd-hibernate-resume only supports ++ the in-kernel hibernation implementation, known as swsusp. ++ Internally, it works by writing the major:minor of specified ++ device node to /sys/power/resume. ++ ++ Failing to initiate a resume is not an error condition. ++ It may mean that there was no resume image (e. g. if the ++ system has been simply powered off and not hibernated). In ++ such case, the boot is ordinarily continued. ++ ++ ++ ++ See Also ++ ++ systemd1, ++ systemd-hibernate-resume-generator8 ++ ++ ++ ++ +diff --git a/src/hibernate-resume/Makefile b/src/hibernate-resume/Makefile +new file mode 120000 +index 0000000000..d0b0e8e008 +--- /dev/null ++++ b/src/hibernate-resume/Makefile +@@ -0,0 +1 @@ ++../Makefile +\ No newline at end of file +diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c +new file mode 100644 +index 0000000000..8f68f81f9e +--- /dev/null ++++ b/src/hibernate-resume/hibernate-resume.c +@@ -0,0 +1,81 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2014 Ivan Shapovalov ++ ++ 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 "fileio.h" ++ ++int main(int argc, char *argv[]) { ++ struct stat st; ++ const char *device; ++ _cleanup_free_ char *major_minor = NULL; ++ int r; ++ ++ if (argc != 2) { ++ log_error("This program expects one argument."); ++ return EXIT_FAILURE; ++ } ++ ++ log_set_target(LOG_TARGET_AUTO); ++ log_parse_environment(); ++ log_open(); ++ ++ umask(0022); ++ ++ device = argv[1]; ++ ++ if (stat(device, &st) < 0) { ++ log_error("Failed to stat '%s': %m", device); ++ return EXIT_FAILURE; ++ } ++ ++ if (!S_ISBLK(st.st_mode)) { ++ log_error("Resume device '%s' is not a block device.", device); ++ return EXIT_FAILURE; ++ } ++ ++ if (asprintf(&major_minor, "%d:%d", major(st.st_rdev), minor(st.st_rdev)) < 0) { ++ log_oom(); ++ return EXIT_FAILURE; ++ } ++ ++ r = write_string_file("/sys/power/resume", major_minor); ++ if (r < 0) { ++ log_error("Failed to write '%s' to /sys/power/resume: %s", major_minor, strerror(-r)); ++ return EXIT_FAILURE; ++ } ++ ++ /* ++ * The write above shall not return. ++ * ++ * However, failed resume is a normal condition (may mean that there is ++ * no hibernation image). ++ */ ++ ++ log_info("Could not resume from '%s' (%s).", device, major_minor); ++ return EXIT_SUCCESS; ++} +diff --git a/units/.gitignore b/units/.gitignore +index d9b60ac0fc..c60f357416 100644 +--- a/units/.gitignore ++++ b/units/.gitignore +@@ -54,6 +54,7 @@ + /systemd-reboot.service + /systemd-remount-fs.service + /systemd-resolved.service ++/systemd-hibernate-resume@.service + /systemd-rfkill@.service + /systemd-shutdownd.service + /systemd-suspend.service +diff --git a/units/systemd-hibernate-resume@.service.in b/units/systemd-hibernate-resume@.service.in +new file mode 100644 +index 0000000000..6db584dc4d +--- /dev/null ++++ b/units/systemd-hibernate-resume@.service.in +@@ -0,0 +1,20 @@ ++# 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=Resume from hibernation using device %f ++Documentation=man:systemd-hibernate-resume@.service(8) ++DefaultDependencies=no ++BindsTo=%i.device ++Wants=local-fs-pre.target ++After=%i.device ++Before=local-fs-pre.target systemd-remount-fs.service systemd-fsck-root.service ++ConditionPathExists=/etc/initrd-release ++ ++[Service] ++Type=oneshot ++ExecStart=@rootlibexecdir@/systemd-hibernate-resume %f diff --git a/0067-hibernate-resume-generator-add-a-generator-for-insta.patch b/0067-hibernate-resume-generator-add-a-generator-for-insta.patch new file mode 100644 index 0000000..ffb9be1 --- /dev/null +++ b/0067-hibernate-resume-generator-add-a-generator-for-insta.patch @@ -0,0 +1,330 @@ +From d2c68822c47e37b582820f45b496b2e7d1f9e642 Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Wed, 27 Aug 2014 00:17:45 +0400 +Subject: [PATCH] hibernate-resume-generator: add a generator for instantiating + the resume unit. + +hibernate-resume-generator understands resume= kernel command line parameter +and instantiates the systemd-resume@.service accordingly if it is passed. + +This enables resume from hibernation using device specified on the kernel +command line, and it may be specified either as "/dev/disk/by-foo/bar" +or "FOO=bar", not only "/dev/sdXY" which is understood by the in-kernel +implementation. + +So now resume= is brought on par with root= in terms of possible ways to +specify a device. +--- + .gitignore | 1 + + Makefile-man.am | 2 + + Makefile.am | 11 +++- + man/kernel-command-line.xml | 14 ++++- + man/systemd-hibernate-resume-generator.xml | 93 +++++++++++++++++++++++++++++ + src/resume-generator/Makefile | 1 + + src/resume-generator/resume-generator.c | 95 ++++++++++++++++++++++++++++++ + 7 files changed, 215 insertions(+), 2 deletions(-) + create mode 100644 man/systemd-hibernate-resume-generator.xml + create mode 120000 src/resume-generator/Makefile + create mode 100644 src/resume-generator/resume-generator.c + +diff --git a/.gitignore b/.gitignore +index 0b5608ccf9..8aed0b9ba6 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -76,6 +76,7 @@ + /systemd-gnome-ask-password-agent + /systemd-gpt-auto-generator + /systemd-hibernate-resume ++/systemd-hibernate-resume-generator + /systemd-hostnamed + /systemd-inhibit + /systemd-initctl +diff --git a/Makefile-man.am b/Makefile-man.am +index 09a10383a9..5c27937152 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -70,6 +70,7 @@ MANPAGES += \ + man/systemd-getty-generator.8 \ + man/systemd-gpt-auto-generator.8 \ + man/systemd-halt.service.8 \ ++ man/systemd-hibernate-resume-generator.8 \ + man/systemd-hibernate-resume@.service.8 \ + man/systemd-inhibit.1 \ + man/systemd-initctl.service.8 \ +@@ -1625,6 +1626,7 @@ EXTRA_DIST += \ + man/systemd-getty-generator.xml \ + man/systemd-gpt-auto-generator.xml \ + man/systemd-halt.service.xml \ ++ man/systemd-hibernate-resume-generator.xml \ + man/systemd-hibernate-resume@.service.xml \ + man/systemd-hostnamed.service.xml \ + man/systemd-inhibit.xml \ +diff --git a/Makefile.am b/Makefile.am +index a487caa7bc..cbdf551fa8 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -385,7 +385,8 @@ systemgenerator_PROGRAMS = \ + systemd-getty-generator \ + systemd-fstab-generator \ + systemd-system-update-generator \ +- systemd-debug-generator ++ systemd-debug-generator \ ++ systemd-hibernate-resume-generator + + dist_bashcompletion_DATA = \ + shell-completion/bash/busctl \ +@@ -2146,6 +2147,14 @@ systemd_system_update_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + ++# ------------------------------------------------------------------------------ ++systemd_hibernate_resume_generator_SOURCES = \ ++ src/resume-generator/resume-generator.c ++ ++systemd_hibernate_resume_generator_LDADD = \ ++ libsystemd-label.la \ ++ libsystemd-shared.la ++ + if ENABLE_EFI + # ------------------------------------------------------------------------------ + systemgenerator_PROGRAMS += \ +diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml +index 36428aaa94..d872e6d5b9 100644 +--- a/man/kernel-command-line.xml ++++ b/man/kernel-command-line.xml +@@ -351,6 +351,17 @@ + + + ++ ++ resume= ++ ++ ++ Enables resume from hibernation ++ using the specified device. ++ All fstab5-like ++ pathes are supported. For details, see ++ systemd-hibernate-resume-generator8. ++ ++ + + + +@@ -373,7 +384,8 @@ + systemd-gpt-auto-generator8, + systemd-modules-load.service8, + systemd-backlight@.service8, +- systemd-rfkill@.service8 ++ systemd-rfkill@.service8, ++ systemd-hibernate-resume-generator8 + + + +diff --git a/man/systemd-hibernate-resume-generator.xml b/man/systemd-hibernate-resume-generator.xml +new file mode 100644 +index 0000000000..1a4b99ced4 +--- /dev/null ++++ b/man/systemd-hibernate-resume-generator.xml +@@ -0,0 +1,93 @@ ++ ++ ++ ++ ++ ++ ++ ++ systemd-hibernate-resume-generator ++ systemd ++ ++ ++ ++ Developer ++ Ivan ++ Shapovalov ++ intelfx100@gmail.com ++ ++ ++ ++ ++ ++ systemd-hibernate-resume-generator ++ 8 ++ ++ ++ ++ systemd-hibernate-resume-generator ++ Unit generator for resume= kernel parameter ++ ++ ++ ++ /usr/lib/systemd/system-generators/systemd-hibernate-resume-generator ++ ++ ++ ++ Description ++ ++ systemd-hibernate-resume-generator is ++ a generator that instantiates ++ systemd-hibernate-resume@.service8 ++ unit according to the value of ++ parameter specified on the kernel command line. ++ ++ ++ ++ Kernel Command Line ++ ++ systemd-hibernate-resume-generator understands ++ the following kernel command line parameters: ++ ++ ++ ++ ++ resume= ++ ++ Takes a path to the resume ++ device. Both persistent block device pathes like ++ /dev/disk/by-foo/bar and ++ fstab5-style ++ specifiers like FOO=bar ++ are supported. ++ ++ ++ ++ ++ ++ ++ See Also ++ ++ systemd1, ++ systemd-hibernate-resume@.service8, ++ kernel-command-line7 ++ ++ ++ ++ +diff --git a/src/resume-generator/Makefile b/src/resume-generator/Makefile +new file mode 120000 +index 0000000000..d0b0e8e008 +--- /dev/null ++++ b/src/resume-generator/Makefile +@@ -0,0 +1 @@ ++../Makefile +\ No newline at end of file +diff --git a/src/resume-generator/resume-generator.c b/src/resume-generator/resume-generator.c +new file mode 100644 +index 0000000000..f40721662e +--- /dev/null ++++ b/src/resume-generator/resume-generator.c +@@ -0,0 +1,95 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2014 Ivan Shapovalov ++ ++ 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 "log.h" ++#include "util.h" ++#include "special.h" ++#include "mkdir.h" ++#include "unit-name.h" ++ ++static const char *arg_dest = "/tmp"; ++static char *arg_resume_dev = NULL; ++ ++static int parse_proc_cmdline_item(const char *key, const char *value) { ++ if (streq(key, "resume") && value) { ++ free(arg_resume_dev); ++ arg_resume_dev = fstab_node_to_udev_node(value); ++ if (!arg_resume_dev) ++ return log_oom(); ++ } ++ ++ return 0; ++} ++ ++static int process_resume(void) { ++ _cleanup_free_ char *name = NULL, *lnk = NULL; ++ ++ name = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service"); ++ if (!name) ++ return log_oom(); ++ ++ lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", name, NULL); ++ if (!lnk) ++ return log_oom(); ++ ++ mkdir_parents_label(lnk, 0755); ++ if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-hibernate-resume@.service", lnk) < 0) { ++ log_error("Failed to create symlink %s: %m", lnk); ++ return -errno; ++ } ++ ++ return 0; ++} ++ ++int main(int argc, char *argv[]) { ++ int r = 0; ++ ++ if (argc > 1 && argc != 4) { ++ log_error("This program takes three or no arguments."); ++ return EXIT_FAILURE; ++ } ++ ++ if (argc > 1) ++ arg_dest = argv[1]; ++ ++ log_set_target(LOG_TARGET_SAFE); ++ log_parse_environment(); ++ log_open(); ++ ++ umask(0022); ++ ++ /* Don't even consider resuming outside of initramfs. */ ++ if (!in_initrd()) ++ return EXIT_SUCCESS; ++ ++ if (parse_proc_cmdline(parse_proc_cmdline_item) < 0) ++ return EXIT_FAILURE; ++ ++ if (arg_resume_dev != NULL) ++ r = process_resume(); ++ ++ free(arg_resume_dev); ++ ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} diff --git a/0068-man-reword-sd-hibernate-resume-description-and-add-l.patch b/0068-man-reword-sd-hibernate-resume-description-and-add-l.patch new file mode 100644 index 0000000..6d7d9c1 --- /dev/null +++ b/0068-man-reword-sd-hibernate-resume-description-and-add-l.patch @@ -0,0 +1,35 @@ +From 36f5ace2db7fc43796107b2da9874e4c4bbc623e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 26 Aug 2014 21:14:11 -0400 +Subject: [PATCH] man: reword sd-hibernate-resume description and add link + +"each device" was suggesting that this service might be instantiated +multiple times. "hibernation resume" was too jargon-y. +--- + man/systemd-hibernate-resume@.service.xml | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/man/systemd-hibernate-resume@.service.xml b/man/systemd-hibernate-resume@.service.xml +index 9b188b0d96..30bfd88101 100644 +--- a/man/systemd-hibernate-resume@.service.xml ++++ b/man/systemd-hibernate-resume@.service.xml +@@ -54,13 +54,14 @@ + + Description + +- systemd-hibernate-resume@.service is a +- service that initiates hibernation resume from a device +- containing the resume image. It is instantiated for each +- device that is configured for resuming from. ++ systemd-hibernate-resume@.service ++ initiates the resume from hibernation. It is ++ instantiated with the device to resume from as the ++ template argument. + + systemd-hibernate-resume only supports +- the in-kernel hibernation implementation, known as swsusp. ++ the in-kernel hibernation implementation, known as ++ swsusp. + Internally, it works by writing the major:minor of specified + device node to /sys/power/resume. + diff --git a/0069-Document-.-.-udev-match-syntax.patch b/0069-Document-.-.-udev-match-syntax.patch new file mode 100644 index 0000000..c426cf0 --- /dev/null +++ b/0069-Document-.-.-udev-match-syntax.patch @@ -0,0 +1,39 @@ +From bf2e0ece853b888eb37055849975ddeab3f5f051 Mon Sep 17 00:00:00 2001 +From: Andrei Borzenkov +Date: Sun, 24 Aug 2014 11:11:33 +0400 +Subject: [PATCH] Document "...|..." udev match syntax + +--- + man/udev.xml | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/man/udev.xml b/man/udev.xml +index db729378c5..2948b9ce2b 100644 +--- a/man/udev.xml ++++ b/man/udev.xml +@@ -272,8 +272,8 @@ + + + +- Most of the fields support shell glob pattern matching. The following +- pattern characters are supported: ++ Most of the fields support shell glob pattern matching and ++ alternate patterns. The following special characters are supported: + + + * +@@ -300,6 +300,14 @@ + any characters not enclosed are matched. + + ++ ++ | ++ ++ Separates alternative patterns. For example, the pattern string ++ abc|x* would match either abc ++ or x*. ++ ++ + + + The following keys can get values assigned: diff --git a/0070-po-update-Polish-translation.patch b/0070-po-update-Polish-translation.patch new file mode 100644 index 0000000..d6fc8fb --- /dev/null +++ b/0070-po-update-Polish-translation.patch @@ -0,0 +1,63 @@ +From 1977376274fc81f13e4220d224237e7cc71f0c63 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Piotr=20Dr=C4=85g?= +Date: Sun, 24 Aug 2014 18:18:35 +0200 +Subject: [PATCH] po: update Polish translation + +https://bugs.freedesktop.org/show_bug.cgi?id=83015 +--- + po/pl.po | 34 +++++++++++++++++++++++++++++++--- + 1 file changed, 31 insertions(+), 3 deletions(-) + +diff --git a/po/pl.po b/po/pl.po +index 6a95d2fd74..0407fe0861 100644 +--- a/po/pl.po ++++ b/po/pl.po +@@ -1,13 +1,13 @@ + # translation of pl.po to Polish +-# Piotr Drąg , 2011, 2013. ++# Piotr Drąg , 2011, 2013, 2014. + # Zbigniew Jędrzejewski-Szmek , 2011. + # + msgid "" + msgstr "" + "Project-Id-Version: systemd\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2013-01-12 19:29+0100\n" +-"PO-Revision-Date: 2013-01-12 19:30+0100\n" ++"POT-Creation-Date: 2014-08-24 18:10+0200\n" ++"PO-Revision-Date: 2014-08-24 18:15+0200\n" + "Last-Translator: Piotr Drąg \n" + "Language-Team: Polish \n" + "Language: pl\n" +@@ -389,3 +389,31 @@ msgid "Authentication is required to access the system and service manager." + msgstr "" + "Wymagane jest uwierzytelnienie, aby uzyskać dostęp do menedżera systemu i " + "usług." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5 ++msgid "Manage system services or units" ++msgstr "Zarządzanie usługami lub jednostkami systemu" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6 ++msgid "Authentication is required to manage system services or units." ++msgstr "" ++"Wymagane jest uwierzytelnienie, aby zarządzać usługami lub jednostkami " ++"systemu." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7 ++msgid "Manage system service or unit files" ++msgstr "Zarządzanie plikami usług lub jednostek systemu" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8 ++msgid "Authentication is required to manage system service or unit files." ++msgstr "" ++"Wymagane jest uwierzytelnienie, aby zarządzać plikami usług lub jednostek " ++"systemu." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9 ++msgid "Reload the systemd state" ++msgstr "Ponowne wczytanie stanu systemd" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10 ++msgid "Authentication is required to reload the systemd state." ++msgstr "Wymagane jest uwierzytelnienie, aby ponownie wczytać stan systemd." diff --git a/0071-keymap-Adjust-for-more-Samsung-900X4-series.patch b/0071-keymap-Adjust-for-more-Samsung-900X4-series.patch new file mode 100644 index 0000000..51e9132 --- /dev/null +++ b/0071-keymap-Adjust-for-more-Samsung-900X4-series.patch @@ -0,0 +1,26 @@ +From e512e8a255ef29d5a8eb605f8849202ea3d3e4cb Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Wed, 27 Aug 2014 08:41:10 +0200 +Subject: [PATCH] keymap: Adjust for more Samsung 900X4 series + +Reportedly also applies to NP900X4B, so relax the match to apply to all models +of this series. + +https://launchpad.net/bugs/902332 +--- + 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 ef0ebc5187..0ffcb83277 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -939,7 +939,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*550P*:pvr* + # Series 7 / 9 + keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700Z*:pvr* + keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700G*:pvr* +-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][CDEFG]*:pvr* ++keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34]*:pvr* + keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:pvr* + KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings + KEYBOARD_KEY_a0=!mute # Fn+F6 mute diff --git a/0072-systemctl-fix-broken-list-unit-files-with-root.patch b/0072-systemctl-fix-broken-list-unit-files-with-root.patch new file mode 100644 index 0000000..0c79972 --- /dev/null +++ b/0072-systemctl-fix-broken-list-unit-files-with-root.patch @@ -0,0 +1,34 @@ +From 81fc054dc7c365545bca86d78bf36a12658cedb3 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 26 Aug 2014 13:33:08 +0200 +Subject: [PATCH] systemctl: fix broken list-unit-files with --root + +--- + src/shared/install.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 4b09a69456..3ef995a928 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2072,6 +2072,7 @@ 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); +@@ -2121,7 +2122,11 @@ int unit_file_get_list( + goto found; + } + +- r = unit_file_can_install(&paths, root_dir, f->path, true); ++ path = path_make_absolute(de->d_name, *i); ++ if (!path) ++ return -ENOMEM; ++ ++ r = unit_file_can_install(&paths, root_dir, path, true); + if (r == -EINVAL || /* Invalid setting? */ + r == -EBADMSG || /* Invalid format? */ + r == -ENOENT /* Included file not found? */) diff --git a/0073-tmpfiles-make-resolv.conf-entry-conditional-on-resol.patch b/0073-tmpfiles-make-resolv.conf-entry-conditional-on-resol.patch new file mode 100644 index 0000000..1c78d6b --- /dev/null +++ b/0073-tmpfiles-make-resolv.conf-entry-conditional-on-resol.patch @@ -0,0 +1,114 @@ +From aeb50ff0bd4bbbca74c4695072232348351d512d Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 27 Aug 2014 17:45:41 +0200 +Subject: [PATCH] tmpfiles: make resolv.conf entry conditional on resolved + support + +--- + Makefile.am | 15 +++++++++++++-- + TODO | 2 -- + configure.ac | 1 + + tmpfiles.d/.gitignore | 1 + + tmpfiles.d/{etc.conf => etc.conf.m4} | 2 ++ + 5 files changed, 17 insertions(+), 4 deletions(-) + create mode 100644 tmpfiles.d/.gitignore + rename tmpfiles.d/{etc.conf => etc.conf.m4} (95%) + +diff --git a/Makefile.am b/Makefile.am +index cbdf551fa8..70faed4acb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1940,14 +1940,16 @@ nodist_systemunit_DATA += \ + units/systemd-tmpfiles-setup.service \ + units/systemd-tmpfiles-clean.service + ++nodist_tmpfiles_DATA = \ ++ tmpfiles.d/etc.conf ++ + dist_tmpfiles_DATA = \ + tmpfiles.d/systemd.conf \ + tmpfiles.d/systemd-nologin.conf \ + tmpfiles.d/systemd-remote.conf \ + tmpfiles.d/tmp.conf \ + tmpfiles.d/x11.conf \ +- tmpfiles.d/var.conf \ +- tmpfiles.d/etc.conf ++ tmpfiles.d/var.conf + + if HAVE_SYSV_COMPAT + dist_tmpfiles_DATA += \ +@@ -1970,10 +1972,14 @@ INSTALL_DIRS += \ + endif + + EXTRA_DIST += \ ++ tmpfiles.d/etc.conf.m4 \ + units/systemd-tmpfiles-setup-dev.service.in \ + units/systemd-tmpfiles-setup.service.in \ + units/systemd-tmpfiles-clean.service.in + ++CLEANFILES += \ ++ tmpfiles.d/etc.conf ++ + # ------------------------------------------------------------------------------ + if ENABLE_SYSUSERS + systemd_sysusers_SOURCES = \ +@@ -5708,6 +5714,11 @@ src/%: src/%.m4 + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_M4)$(M4) -P $(M4_DEFINES) < $< > $@ + ++tmpfiles.d/%: tmpfiles.d/%.m4 ++ $(AM_V_at)$(MKDIR_P) $(dir $@) ++ $(AM_V_M4)$(M4) -P $(M4_DEFINES) < $< > $@ ++ ++ + units/%: units/%.m4 + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_M4)$(M4) -P $(M4_DEFINES) -DFOR_SYSTEM=1 < $< > $@ +diff --git a/TODO b/TODO +index 09f82d3c37..372825e8bd 100644 +--- a/TODO ++++ b/TODO +@@ -120,8 +120,6 @@ Features: + + * Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely + +-* the resolv.conf tmpfiles line should be covered by ENABLE_NETWORKD... +- + * Add a new verb "systemctl top" + + * logind: allow users to kill or lock their own sessions +diff --git a/configure.ac b/configure.ac +index 18b719856b..08a8a105f8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1023,6 +1023,7 @@ have_resolved=no + AC_ARG_ENABLE(resolved, AS_HELP_STRING([--disable-resolved], [disable resolve daemon])) + if test "x$enable_resolved" != "xno"; then + have_resolved=yes ++ M4_DEFINES="$M4_DEFINES -DENABLE_RESOLVED" + fi + AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"]) + +diff --git a/tmpfiles.d/.gitignore b/tmpfiles.d/.gitignore +new file mode 100644 +index 0000000000..eb323154ff +--- /dev/null ++++ b/tmpfiles.d/.gitignore +@@ -0,0 +1 @@ ++etc.conf +diff --git a/tmpfiles.d/etc.conf b/tmpfiles.d/etc.conf.m4 +similarity index 95% +rename from tmpfiles.d/etc.conf +rename to tmpfiles.d/etc.conf.m4 +index b23272cb27..f567c8d6ea 100644 +--- a/tmpfiles.d/etc.conf ++++ b/tmpfiles.d/etc.conf.m4 +@@ -10,6 +10,8 @@ + 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 ++) + C /etc/nsswitch.conf - - - - + C /etc/pam.d - - - - diff --git a/0074-TODO.patch b/0074-TODO.patch new file mode 100644 index 0000000..4133a9e --- /dev/null +++ b/0074-TODO.patch @@ -0,0 +1,44 @@ +From 285e8c126b1607188249c42e74c172cb69cc99a6 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 27 Aug 2014 17:46:00 +0200 +Subject: [PATCH] TODO + +--- + TODO | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/TODO b/TODO +index 372825e8bd..a00c13dab2 100644 +--- a/TODO ++++ b/TODO +@@ -61,11 +61,6 @@ Features: + * systemd.show_status= should probably have a mode where only failed + units are shown. + +-* sd-event: +- - make it possible to embedd our event loop into foreign event loops +- by passing out the epoll fd and providing three functions that fit +- into GSource nicely. +- + * networkd: + - add LLDP client side support + - ipv4ll with multiple interfaces doesn't work when both dhcp and +@@ -74,18 +69,10 @@ Features: + - dhcp and ipv4ll should probably be skipped for "lo" devices, even + if the user has a catchall .network file installed, that might + theoretically match it. +- - we probably should introduce a new operational state that +- indicates that we are trying to acquire some configuration for a +- link but haven't acquired any yet. Just to inform the admin that +- networkd cares about an interface, but is still in progress.. + - the DHCP lease data (such as NTP/DNS) is still made available when + a carrier is lost on a link. It should be removed instantly. + - .network setting that allows overriding of the hostname to send to the dhcp server + http://lists.freedesktop.org/archives/systemd-devel/2014-July/021550.html +- - add per-network Domains= settings, with a special syntax Domains=* +- for routing all non-otherwise routed traffic to this link +- - add UseDomains= setting to [DHCP] to add dhcp supplied domains to +- per-interface Domains= list. + - expose in the API the following bits: + - option 15, domain name and/or option 119, search list + - option 12, host name and/or option 81, fqdn diff --git a/0075-shared-drop-UNIQUE.patch b/0075-shared-drop-UNIQUE.patch new file mode 100644 index 0000000..9191e4e --- /dev/null +++ b/0075-shared-drop-UNIQUE.patch @@ -0,0 +1,41 @@ +From 418bcb0ce3b704ea26ee1b4a68706abca536f65a Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 22 Aug 2014 14:38:28 +0200 +Subject: [PATCH] shared: drop UNIQUE() + +The UNIQUE() macro works fine if used in un-stacked macros. However, once +you stack them like: + MAX(MIN(a, b), + CLAMP(MAX(c, d), e, f)) +you will get warnings due to shadowing other variables. gcc uses the last +line of a macro expansion as value for __LINE__, therefore, we cannot even +avoid this by splitting the expressions across lines. + +Remove the only user of UNIQUE() so we introduce a new helper in +follow-ups. +--- + src/shared/macro.h | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/shared/macro.h b/src/shared/macro.h +index 43fa3e556f..2807bc74e8 100644 +--- a/src/shared/macro.h ++++ b/src/shared/macro.h +@@ -79,8 +79,6 @@ + #define XCONCATENATE(x, y) x ## y + #define CONCATENATE(x, y) XCONCATENATE(x, y) + +-#define UNIQUE(prefix) CONCATENATE(prefix, __LINE__) +- + /* Rounds up */ + + #define ALIGN4(l) (((l) + 3) & ~3) +@@ -219,7 +217,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { + #else + #define assert_cc(expr) \ + DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ +- struct UNIQUE(_assert_struct_) { \ ++ struct CONCATENATE(_assert_struct_, __LINE__) { \ + char x[(expr) ? 0 : -1]; \ + }; \ + REENABLE_WARNING diff --git a/0076-shared-make-container_of-use-unique-variable-names.patch b/0076-shared-make-container_of-use-unique-variable-names.patch new file mode 100644 index 0000000..449f202 --- /dev/null +++ b/0076-shared-make-container_of-use-unique-variable-names.patch @@ -0,0 +1,119 @@ +From fb835651aff79a1e7fc5795086c9b26e59a8e6ca Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 22 Aug 2014 14:41:37 +0200 +Subject: [PATCH] shared: make container_of() use unique variable names + +If you stack container_of() macros, you will get warnings due to shadowing +variables of the parent context. To avoid this, use unique names for +variables. + +Two new helpers are added: + UNIQ: This evaluates to a truly unique value never returned by any + evaluation of this macro. It's a shortcut for __COUNTER__. + UNIQ_T: Takes two arguments and concatenates them. It is a shortcut for + CONCATENATE, but meant to defined typed local variables. + +As you usually want to use variables that you just defined, you need to +reference the same unique value at least two times. However, UNIQ returns +a new value on each evaluation, therefore, you have to pass the unique +values into the macro like this: + + #define my_macro(a, b) __max_macro(UNIQ, UNIQ, (a), (b)) + #define __my_macro(uniqa, uniqb, a, b) ({ + typeof(a) UNIQ_T(A, uniqa) = (a); + typeof(b) UNIQ_T(B, uniqb) = (b); + MY_UNSAFE_MACRO(UNIQ_T(A, uniqa), UNIQ_T(B, uniqb)); + }) + +This way, MY_UNSAFE_MACRO() can safely evaluate it's arguments multiple +times as they are local variables. But you can also stack invocations to +the macro my_macro() without clashing names. + +This is the same as if you did: + + #define my_macro(a, b) __max_macro(__COUNTER__, __COUNTER__, (a), (b)) + #define __my_macro(prefixa, prefixb, a, b) ({ + typeof(a) CONCATENATE(A, prefixa) = (a); + typeof(b) CONCATENATE(B, prefixb) = (b); + MY_UNSAFE_MACRO(CONCATENATE(A, prefixa), CONCATENATE(B, prefixb)); + }) + +...but in my opinion, the first macro is easier to write and read. + +This patch starts by converting container_of() to use this new helper. +Other macros may follow (like MIN, MAX, CLAMP, ...). +--- + src/shared/macro.h | 13 ++++++++----- + src/test/test-util.c | 19 +++++++++++++++++++ + 2 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/src/shared/macro.h b/src/shared/macro.h +index 2807bc74e8..e6734804bd 100644 +--- a/src/shared/macro.h ++++ b/src/shared/macro.h +@@ -79,6 +79,9 @@ + #define XCONCATENATE(x, y) x ## y + #define CONCATENATE(x, y) XCONCATENATE(x, y) + ++#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) ++#define UNIQ __COUNTER__ ++ + /* Rounds up */ + + #define ALIGN4(l) (((l) + 3) & ~3) +@@ -122,13 +125,13 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. +- * + */ +-#define container_of(ptr, type, member) \ ++#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member) ++#define __container_of(uniq, ptr, type, member) \ + __extension__ ({ \ +- const typeof( ((type *)0)->member ) *__mptr = (ptr); \ +- (type *)( (char *)__mptr - offsetof(type,member) ); \ +- }) ++ const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \ ++ (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \ ++ }) + + #undef MAX + #define MAX(a,b) \ +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 4d9b28f9c8..795f3a1b3d 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -96,6 +96,24 @@ static void test_max(void) { + assert_cc(MAXSIZE(char, long) == sizeof(long)); + } + ++static void test_container_of(void) { ++ struct mytype { ++ uint8_t pad1[3]; ++ uint64_t v1; ++ uint8_t pad2[2]; ++ uint32_t v2; ++ } _packed_ myval = { }; ++ ++ assert_cc(sizeof(myval) == 17); ++ assert_se(container_of(&myval.v1, struct mytype, v1) == &myval); ++ assert_se(container_of(&myval.v2, struct mytype, v2) == &myval); ++ assert_se(container_of(&container_of(&myval.v2, ++ struct mytype, ++ v2)->v1, ++ struct mytype, ++ v1) == &myval); ++} ++ + static void test_first_word(void) { + assert_se(first_word("Hello", "")); + assert_se(first_word("Hello", "Hello")); +@@ -1218,6 +1236,7 @@ int main(int argc, char *argv[]) { + test_streq_ptr(); + test_align_power2(); + test_max(); ++ test_container_of(); + test_first_word(); + test_close_many(); + test_parse_boolean(); diff --git a/0077-login-fix-memory-leak-on-DropController.patch b/0077-login-fix-memory-leak-on-DropController.patch new file mode 100644 index 0000000..7972eb0 --- /dev/null +++ b/0077-login-fix-memory-leak-on-DropController.patch @@ -0,0 +1,33 @@ +From 60240797a4ce464ec7a0537ccbec4c83f599251c Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 22 Aug 2014 14:57:11 +0200 +Subject: [PATCH] login: fix memory-leak on DropController() + +Our bus-name watch helpers only remove a bus-name if it's not a +controller, anymore. If we call manager_drop_busname() before +unregistering the controller, the busname will not be dropped. Therefore, +first drop the controller, then drop the bus-name. +--- + src/login/logind-session.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 136bbce78e..0c6e425603 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -1061,11 +1061,13 @@ bool session_is_controller(Session *s, const char *sender) { + + static void session_swap_controller(Session *s, char *name) { + SessionDevice *sd; ++ char *c; + + if (s->controller) { +- manager_drop_busname(s->manager, s->controller); +- free(s->controller); ++ c = s->controller; + s->controller = NULL; ++ manager_drop_busname(s->manager, c); ++ free(c); + + /* Drop all devices as they're now unused. Do that after the + * controller is released to avoid sending out useles diff --git a/0078-udev-add-missing-new-line-in-udevadm-error.patch b/0078-udev-add-missing-new-line-in-udevadm-error.patch new file mode 100644 index 0000000..386e2ec --- /dev/null +++ b/0078-udev-add-missing-new-line-in-udevadm-error.patch @@ -0,0 +1,26 @@ +From 92e63a51052e9ba2fbe6e47a173b6264ae292a58 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 27 Aug 2014 18:02:17 +0200 +Subject: [PATCH] udev: add missing new-line in udevadm error + +fprintf() does not add new-lines automatically like log_*() does. Add the +missing \n specified so "udevadm" invoked without arguments adds a newline +to: + udevadm: missing or unknown command +--- + src/udev/udevadm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c +index 2c11550467..df546dd823 100644 +--- a/src/udev/udevadm.c ++++ b/src/udev/udevadm.c +@@ -134,7 +134,7 @@ int main(int argc, char *argv[]) { + goto out; + } + +- fprintf(stderr, "%s: missing or unknown command", program_invocation_short_name); ++ fprintf(stderr, "%s: missing or unknown command\n", program_invocation_short_name); + rc = 2; + out: + label_finish(); diff --git a/0079-util-make-lookup_uid-global.patch b/0079-util-make-lookup_uid-global.patch new file mode 100644 index 0000000..85055d6 --- /dev/null +++ b/0079-util-make-lookup_uid-global.patch @@ -0,0 +1,37 @@ +From f1566e63da92cee5cbc0074df9cd9a8dc078a62e Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 27 Aug 2014 18:03:29 +0200 +Subject: [PATCH] util: make lookup_uid() global + +This is a useful helper, make it global. It will be required for +libsystemd-terminal, at minimum. +--- + src/shared/util.c | 2 +- + src/shared/util.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index fdcf5719fa..9e4ff85ffb 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -2604,7 +2604,7 @@ bool hostname_is_set(void) { + return !isempty(u.nodename) && !streq(u.nodename, "(none)"); + } + +-static char *lookup_uid(uid_t uid) { ++char *lookup_uid(uid_t uid) { + long bufsize; + char *name; + _cleanup_free_ char *buf = NULL; +diff --git a/src/shared/util.h b/src/shared/util.h +index ea87c96956..3401280d09 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -432,6 +432,7 @@ int sigprocmask_many(int how, ...); + + bool hostname_is_set(void); + ++char* lookup_uid(uid_t uid); + char* gethostname_malloc(void); + char* getlogname_malloc(void); + char* getusername_malloc(void); diff --git a/0080-bus-split-bus_map_all_properties-into-multiple-helpe.patch b/0080-bus-split-bus_map_all_properties-into-multiple-helpe.patch new file mode 100644 index 0000000..38acaf6 --- /dev/null +++ b/0080-bus-split-bus_map_all_properties-into-multiple-helpe.patch @@ -0,0 +1,172 @@ +From aae2b488d084cf2af9a552a55e1d9cc614f2a12a Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sun, 24 Aug 2014 18:55:58 +0200 +Subject: [PATCH] bus: split bus_map_all_properties into multiple helpers + +The bus_map_all_properties() helper calls +org.freedesktop.DBus.Properties.GetAll() on a given target and parses the +result according to a given property-table. This simplifies dealing with +DBus.Properties significantly. However, the function is blocking and thus +not really useful in many situations. + +This patch extracts the core of this function and adds two new helpers +which directly take dbus-messages as arguments. This way, you can issue +asynchronous requests and parse the result via these helpers: + + bus_message_map_all_properties(): + This is the same as bus_map_all_properties() but takes the result + message from a GetAll() request as argument. You can thus issue an + asynchronous GetAll() request and then use this helper once you got + the result. + + bus_message_map_properties_changed(): + This function takes a signal-message that was retrieved via a + PropertiesChanged signal and then parses it like if you retrieved + it via GetAll(). Furthermore, this function returns the number of + matched properties that got invalidated by the PropertiesChanged + signal, but didn't carry the new value. This way, the caller can + issue a new GetAll() request and then parse the result. + +The old function bus_map_all_properties() is functionally unchanged, but +now uses bus_message_map_all_properties() internally. +--- + src/libsystemd/sd-bus/bus-util.c | 93 +++++++++++++++++++++++++++++++--------- + src/libsystemd/sd-bus/bus-util.h | 8 ++++ + 2 files changed, 80 insertions(+), 21 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index c97bf7d99d..aed3889b12 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -974,32 +974,17 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_ + return r; + } + +-int bus_map_all_properties(sd_bus *bus, +- const char *destination, +- const char *path, +- const struct bus_properties_map *map, +- void *userdata) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++int bus_message_map_all_properties(sd_bus *bus, ++ sd_bus_message *m, ++ const struct bus_properties_map *map, ++ void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); +- assert(destination); +- assert(path); ++ assert(m); + assert(map); + +- r = sd_bus_call_method( +- bus, +- destination, +- path, +- "org.freedesktop.DBus.Properties", +- "GetAll", +- &error, +- &m, +- "s", ""); +- if (r < 0) +- return r; +- + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return r; +@@ -1052,7 +1037,73 @@ int bus_map_all_properties(sd_bus *bus, + return r; + } + +- return r; ++ return sd_bus_message_exit_container(m); ++} ++ ++int bus_message_map_properties_changed(sd_bus *bus, ++ sd_bus_message *m, ++ const struct bus_properties_map *map, ++ void *userdata) { ++ const char *member; ++ int r, invalidated, i; ++ ++ assert(bus); ++ assert(m); ++ assert(map); ++ ++ /* skip interface, but allow callers to do that themselves */ ++ sd_bus_message_skip(m, "s"); ++ ++ r = bus_message_map_all_properties(bus, m, map, userdata); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s"); ++ if (r < 0) ++ return r; ++ ++ invalidated = 0; ++ while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member)) > 0) ++ for (i = 0; map[i].member; i++) ++ if (streq(map[i].member, member)) { ++ ++invalidated; ++ break; ++ } ++ ++ r = sd_bus_message_exit_container(m); ++ if (r < 0) ++ return r; ++ ++ return invalidated; ++} ++ ++int bus_map_all_properties(sd_bus *bus, ++ const char *destination, ++ const char *path, ++ const struct bus_properties_map *map, ++ void *userdata) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ int r; ++ ++ assert(bus); ++ assert(destination); ++ assert(path); ++ assert(map); ++ ++ r = sd_bus_call_method( ++ bus, ++ destination, ++ path, ++ "org.freedesktop.DBus.Properties", ++ "GetAll", ++ &error, ++ &m, ++ "s", ""); ++ if (r < 0) ++ return r; ++ ++ return bus_message_map_all_properties(bus, m, map, userdata); + } + + int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) { +diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h +index faf1775809..696daa1f03 100644 +--- a/src/libsystemd/sd-bus/bus-util.h ++++ b/src/libsystemd/sd-bus/bus-util.h +@@ -46,6 +46,14 @@ struct bus_properties_map { + + int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata); + ++int bus_message_map_all_properties(sd_bus *bus, ++ sd_bus_message *m, ++ const struct bus_properties_map *map, ++ void *userdata); ++int bus_message_map_properties_changed(sd_bus *bus, ++ sd_bus_message *m, ++ const struct bus_properties_map *map, ++ void *userdata); + int bus_map_all_properties(sd_bus *bus, + const char *destination, + const char *path, diff --git a/0081-terminal-add-system-view-interface.patch b/0081-terminal-add-system-view-interface.patch new file mode 100644 index 0000000..9cbf1e5 --- /dev/null +++ b/0081-terminal-add-system-view-interface.patch @@ -0,0 +1,1828 @@ +From 7ed3a638b2e4ffb5e76a0cf1a008e1c7233edb75 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 26 Aug 2014 15:03:41 +0200 +Subject: [PATCH] terminal: add system view interface + +We're going to need multiple binaries that provide session-services via +logind device management. To avoid re-writing the seat/session/device +scan/monitor interface for each of them, this commit adds a generic helper +to libsystemd-terminal: + +The sysview interface scans and tracks seats, sessions and devices on a +system. It basically mirrors the state of logind on the application side. +Now, each session-service can listen for matching sessions and +attach to them. On each session, managed device access is provided. This +way, it is pretty simple to write session-services that attach to multiple +sessions (even split across seats). +--- + Makefile.am | 4 + + src/libsystemd-terminal/sysview-internal.h | 140 +++ + src/libsystemd-terminal/sysview.c | 1471 ++++++++++++++++++++++++++++ + src/libsystemd-terminal/sysview.h | 151 +++ + 4 files changed, 1766 insertions(+) + create mode 100644 src/libsystemd-terminal/sysview-internal.h + create mode 100644 src/libsystemd-terminal/sysview.c + create mode 100644 src/libsystemd-terminal/sysview.h + +diff --git a/Makefile.am b/Makefile.am +index 70faed4acb..3a263f8c17 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2971,6 +2971,9 @@ libsystemd_terminal_la_CFLAGS = \ + $(AM_CFLAGS) + + libsystemd_terminal_la_SOURCES = \ ++ src/libsystemd-terminal/sysview.h \ ++ src/libsystemd-terminal/sysview-internal.h \ ++ src/libsystemd-terminal/sysview.c \ + src/libsystemd-terminal/term-internal.h \ + src/libsystemd-terminal/term-charset.c \ + src/libsystemd-terminal/term-page.c \ +@@ -2981,6 +2984,7 @@ libsystemd_terminal_la_SOURCES = \ + src/libsystemd-terminal/unifont.c + + libsystemd_terminal_la_LIBADD = \ ++ libudev-internal.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +diff --git a/src/libsystemd-terminal/sysview-internal.h b/src/libsystemd-terminal/sysview-internal.h +new file mode 100644 +index 0000000000..5aee9f67d8 +--- /dev/null ++++ b/src/libsystemd-terminal/sysview-internal.h +@@ -0,0 +1,140 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "hashmap.h" ++#include "list.h" ++#include "macro.h" ++#include "sysview.h" ++#include "util.h" ++ ++/* ++ * Devices ++ */ ++ ++struct sysview_device { ++ sysview_seat *seat; ++ const char *name; ++ unsigned int type; ++ ++ union { ++ struct { ++ struct udev_device *ud; ++ } evdev, drm; ++ }; ++}; ++ ++sysview_device *sysview_find_device(sysview_context *c, const char *name); ++ ++int sysview_device_new(sysview_device **out, sysview_seat *seat, const char *name); ++sysview_device *sysview_device_free(sysview_device *device); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(sysview_device*, sysview_device_free); ++ ++/* ++ * Sessions ++ */ ++ ++struct sysview_session { ++ sysview_seat *seat; ++ char *name; ++ char *path; ++ ++ sd_bus_slot *slot_take_control; ++ ++ bool custom : 1; ++ bool public : 1; ++ bool wants_control : 1; ++ bool has_control : 1; ++}; ++ ++sysview_session *sysview_find_session(sysview_context *c, const char *name); ++ ++int sysview_session_new(sysview_session **out, sysview_seat *seat, const char *name); ++sysview_session *sysview_session_free(sysview_session *session); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(sysview_session*, sysview_session_free); ++ ++/* ++ * Seats ++ */ ++ ++struct sysview_seat { ++ sysview_context *context; ++ char *name; ++ ++ Hashmap *session_map; ++ Hashmap *device_map; ++ ++ bool scanned : 1; ++ bool public : 1; ++}; ++ ++sysview_seat *sysview_find_seat(sysview_context *c, const char *name); ++ ++int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *name); ++sysview_seat *sysview_seat_free(sysview_seat *seat); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(sysview_seat*, sysview_seat_free); ++ ++/* ++ * Contexts ++ */ ++ ++struct sysview_context { ++ sd_event *event; ++ sd_bus *sysbus; ++ struct udev *ud; ++ uint64_t custom_sid; ++ ++ Hashmap *seat_map; ++ Hashmap *session_map; ++ Hashmap *device_map; ++ ++ sd_event_source *scan_src; ++ sysview_event_fn event_fn; ++ void *userdata; ++ ++ /* udev scanner */ ++ struct udev_monitor *ud_monitor; ++ sd_event_source *ud_monitor_src; ++ ++ /* logind scanner */ ++ sd_bus_slot *ld_slot_manager_signal; ++ sd_bus_slot *ld_slot_list_seats; ++ sd_bus_slot *ld_slot_list_sessions; ++ ++ bool scan_logind : 1; ++ bool scan_evdev : 1; ++ bool scan_drm : 1; ++ bool running : 1; ++ bool scanned : 1; ++ bool rescan : 1; ++}; ++ ++int sysview_context_rescan(sysview_context *c); +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +new file mode 100644 +index 0000000000..d885cb4d4a +--- /dev/null ++++ b/src/libsystemd-terminal/sysview.c +@@ -0,0 +1,1471 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 "bus-util.h" ++#include "event-util.h" ++#include "macro.h" ++#include "set.h" ++#include "sysview.h" ++#include "sysview-internal.h" ++#include "udev-util.h" ++#include "util.h" ++ ++static int context_raise_session_control(sysview_context *c, sysview_session *session, int error); ++ ++/* ++ * Devices ++ */ ++ ++sysview_device *sysview_find_device(sysview_context *c, const char *name) { ++ assert_return(c, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(c->device_map, name); ++} ++ ++int sysview_device_new(sysview_device **out, sysview_seat *seat, const char *name) { ++ _cleanup_(sysview_device_freep) sysview_device *device = NULL; ++ int r; ++ ++ assert_return(seat, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ device = new0(sysview_device, 1); ++ if (!device) ++ return -ENOMEM; ++ ++ device->seat = seat; ++ device->type = (unsigned)-1; ++ ++ device->name = strdup(name); ++ if (!device->name) ++ return -ENOMEM; ++ ++ r = hashmap_put(seat->context->device_map, device->name, device); ++ if (r < 0) ++ return r; ++ ++ r = hashmap_put(seat->device_map, device->name, device); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = device; ++ device = NULL; ++ return 0; ++} ++ ++sysview_device *sysview_device_free(sysview_device *device) { ++ if (!device) ++ return NULL; ++ ++ if (device->name) { ++ hashmap_remove_value(device->seat->device_map, device->name, device); ++ hashmap_remove_value(device->seat->context->device_map, device->name, device); ++ } ++ ++ switch (device->type) { ++ case SYSVIEW_DEVICE_EVDEV: ++ device->evdev.ud = udev_device_unref(device->evdev.ud); ++ break; ++ case SYSVIEW_DEVICE_DRM: ++ device->drm.ud = udev_device_unref(device->drm.ud); ++ break; ++ } ++ ++ free(device); ++ ++ return NULL; ++} ++ ++unsigned int sysview_device_get_type(sysview_device *device) { ++ assert_return(device, (unsigned)-1); ++ ++ return device->type; ++} ++ ++struct udev_device *sysview_device_get_ud(sysview_device *device) { ++ assert_return(device, NULL); ++ ++ switch (device->type) { ++ case SYSVIEW_DEVICE_EVDEV: ++ return device->evdev.ud; ++ case SYSVIEW_DEVICE_DRM: ++ return device->drm.ud; ++ default: ++ assert_return(0, NULL); ++ } ++} ++ ++static int device_new_ud(sysview_device **out, sysview_seat *seat, unsigned int type, struct udev_device *ud) { ++ _cleanup_(sysview_device_freep) sysview_device *device = NULL; ++ int r; ++ ++ assert_return(seat, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ r = sysview_device_new(&device, seat, udev_device_get_syspath(ud)); ++ if (r < 0) ++ return r; ++ ++ device->type = type; ++ ++ switch (type) { ++ case SYSVIEW_DEVICE_EVDEV: ++ device->evdev.ud = udev_device_ref(ud); ++ break; ++ case SYSVIEW_DEVICE_DRM: ++ device->drm.ud = udev_device_ref(ud); ++ break; ++ default: ++ assert_not_reached("sysview: invalid udev-device type"); ++ } ++ ++ if (out) ++ *out = device; ++ device = NULL; ++ return 0; ++} ++ ++/* ++ * Sessions ++ */ ++ ++sysview_session *sysview_find_session(sysview_context *c, const char *name) { ++ assert_return(c, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(c->session_map, name); ++} ++ ++int sysview_session_new(sysview_session **out, sysview_seat *seat, const char *name) { ++ _cleanup_(sysview_session_freep) sysview_session *session = NULL; ++ int r; ++ ++ assert_return(seat, -EINVAL); ++ ++ session = new0(sysview_session, 1); ++ if (!session) ++ return -ENOMEM; ++ ++ session->seat = seat; ++ ++ if (name) { ++ /* ++ * If a name is given, we require it to be a logind session ++ * name. The session will be put in managed mode and we use ++ * logind to request controller access. ++ */ ++ ++ session->name = strdup(name); ++ if (!session->name) ++ return -ENOMEM; ++ ++ r = sd_bus_path_encode("/org/freedesktop/login1/session", ++ session->name, &session->path); ++ if (r < 0) ++ return r; ++ ++ session->custom = false;; ++ } else { ++ /* ++ * No session name was given. We assume this is an unmanaged ++ * session controlled by the application. We don't use logind ++ * at all and leave session management to the application. The ++ * name of the session-object is set to a unique random string ++ * that does not clash with the logind namespace. ++ */ ++ ++ r = asprintf(&session->name, "@custom%" PRIu64, ++ ++seat->context->custom_sid); ++ if (r < 0) ++ return -ENOMEM; ++ ++ session->custom = true; ++ } ++ ++ r = hashmap_put(seat->context->session_map, session->name, session); ++ if (r < 0) ++ return r; ++ ++ r = hashmap_put(seat->session_map, session->name, session); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = session; ++ session = NULL; ++ return 0; ++} ++ ++sysview_session *sysview_session_free(sysview_session *session) { ++ if (!session) ++ return NULL; ++ ++ assert(!session->public); ++ assert(!session->wants_control); ++ ++ if (session->name) { ++ hashmap_remove_value(session->seat->session_map, session->name, session); ++ hashmap_remove_value(session->seat->context->session_map, session->name, session); ++ } ++ ++ free(session->path); ++ free(session->name); ++ free(session); ++ ++ return NULL; ++} ++ ++const char *sysview_session_get_name(sysview_session *session) { ++ assert_return(session, NULL); ++ ++ return session->name; ++} ++ ++static int session_take_control_fn(sd_bus *bus, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ sysview_session *session = userdata; ++ int error; ++ ++ session->slot_take_control = sd_bus_slot_unref(session->slot_take_control); ++ ++ if (sd_bus_message_is_method_error(reply, NULL)) { ++ const sd_bus_error *e = sd_bus_message_get_error(reply); ++ ++ log_debug("sysview: %s: TakeControl failed: %s: %s", ++ session->name, e->name, e->message); ++ error = sd_bus_error_get_errno(e); ++ } else { ++ session->has_control = true; ++ error = 0; ++ } ++ ++ return context_raise_session_control(session->seat->context, session, error); ++} ++ ++int sysview_session_take_control(sysview_session *session) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ int r; ++ ++ assert_return(session, -EINVAL); ++ assert_return(!session->custom, -EINVAL); ++ ++ if (session->wants_control) ++ return 0; ++ ++ r = sd_bus_message_new_method_call(session->seat->context->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ session->path, ++ "org.freedesktop.login1.Session", ++ "TakeControl"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append(m, "b", 0); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_call_async(session->seat->context->sysbus, ++ &session->slot_take_control, ++ m, ++ session_take_control_fn, ++ session, ++ 0); ++ if (r < 0) ++ return r; ++ ++ session->wants_control = true; ++ return 0; ++} ++ ++void sysview_session_release_control(sysview_session *session) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ int r; ++ ++ assert(session); ++ assert(!session->custom); ++ ++ if (!session->wants_control) ++ return; ++ ++ session->wants_control = false; ++ ++ if (!session->has_control && !session->slot_take_control) ++ return; ++ ++ session->has_control = false; ++ session->slot_take_control = sd_bus_slot_unref(session->slot_take_control); ++ ++ r = sd_bus_message_new_method_call(session->seat->context->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ session->path, ++ "org.freedesktop.login1.Session", ++ "ReleaseControl"); ++ if (r >= 0) ++ r = sd_bus_send(session->seat->context->sysbus, m, NULL); ++ ++ if (r < 0 && r != -ENOTCONN) ++ log_debug("sysview: %s: cannot send ReleaseControl: %s", ++ session->name, strerror(-r)); ++} ++ ++/* ++ * Seats ++ */ ++ ++sysview_seat *sysview_find_seat(sysview_context *c, const char *name) { ++ assert_return(c, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(c->seat_map, name); ++} ++ ++int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *name) { ++ _cleanup_(sysview_seat_freep) sysview_seat *seat = NULL; ++ int r; ++ ++ assert_return(c, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ seat = new0(sysview_seat, 1); ++ if (!seat) ++ return -ENOMEM; ++ ++ seat->context = c; ++ ++ seat->name = strdup(name); ++ if (!seat->name) ++ return -ENOMEM; ++ ++ seat->session_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!seat->session_map) ++ return -ENOMEM; ++ ++ seat->device_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!seat->device_map) ++ return -ENOMEM; ++ ++ r = hashmap_put(c->seat_map, seat->name, seat); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = seat; ++ seat = NULL; ++ return 0; ++} ++ ++sysview_seat *sysview_seat_free(sysview_seat *seat) { ++ if (!seat) ++ return NULL; ++ ++ assert(!seat->public); ++ assert(hashmap_size(seat->device_map) == 0); ++ assert(hashmap_size(seat->session_map) == 0); ++ ++ if (seat->name) ++ hashmap_remove_value(seat->context->seat_map, seat->name, seat); ++ ++ hashmap_free(seat->device_map); ++ hashmap_free(seat->session_map); ++ free(seat->name); ++ free(seat); ++ ++ return NULL; ++} ++ ++const char *sysview_seat_get_name(sysview_seat *seat) { ++ assert_return(seat, NULL); ++ ++ return seat->name; ++} ++ ++/* ++ * Contexts ++ */ ++ ++static int context_raise(sysview_context *c, sysview_event *event, int def) { ++ return c->running ? c->event_fn(c, c->userdata, event) : def; ++} ++ ++static int context_raise_seat_add(sysview_context *c, sysview_seat *seat) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SEAT_ADD, ++ .seat_add = { ++ .seat = seat, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ ++static int context_raise_seat_remove(sysview_context *c, sysview_seat *seat) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SEAT_REMOVE, ++ .seat_remove = { ++ .seat = seat, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ ++static int context_raise_session_filter(sysview_context *c, ++ const char *id, ++ const char *seatid, ++ const char *username, ++ unsigned int uid) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SESSION_FILTER, ++ .session_filter = { ++ .id = id, ++ .seatid = seatid, ++ .username = username, ++ .uid = uid, ++ } ++ }; ++ ++ return context_raise(c, &event, 1); ++} ++ ++static int context_raise_session_add(sysview_context *c, sysview_session *session) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SESSION_ADD, ++ .session_add = { ++ .session = session, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ ++static int context_raise_session_remove(sysview_context *c, sysview_session *session) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SESSION_REMOVE, ++ .session_remove = { ++ .session = session, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ ++static int context_raise_session_control(sysview_context *c, sysview_session *session, int error) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SESSION_CONTROL, ++ .session_control = { ++ .session = session, ++ .error = error, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ ++static int context_raise_session_attach(sysview_context *c, sysview_session *session, sysview_device *device) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SESSION_ATTACH, ++ .session_attach = { ++ .session = session, ++ .device = device, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ ++static int context_raise_session_detach(sysview_context *c, sysview_session *session, sysview_device *device) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_SESSION_DETACH, ++ .session_detach = { ++ .session = session, ++ .device = device, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ ++static int context_add_device(sysview_context *c, sysview_device *device) { ++ sysview_session *session; ++ int r, error = 0; ++ Iterator i; ++ ++ assert(c); ++ assert(device); ++ ++ log_debug("sysview: add device '%s' on seat '%s'", ++ device->name, device->seat->name); ++ ++ HASHMAP_FOREACH(session, device->seat->session_map, i) { ++ if (!session->public) ++ continue; ++ ++ r = context_raise_session_attach(c, session, device); ++ if (r != 0) ++ error = r; ++ } ++ ++ if (error < 0) ++ log_debug("sysview: error while adding device '%s': %s", ++ device->name, strerror(-r)); ++ return error; ++} ++ ++static int context_remove_device(sysview_context *c, sysview_device *device) { ++ sysview_session *session; ++ int r, error = 0; ++ Iterator i; ++ ++ assert(c); ++ assert(device); ++ ++ log_debug("sysview: remove device '%s'", device->name); ++ ++ HASHMAP_FOREACH(session, device->seat->session_map, i) { ++ if (!session->public) ++ continue; ++ ++ r = context_raise_session_detach(c, session, device); ++ if (r != 0) ++ error = r; ++ } ++ ++ if (error < 0) ++ log_debug("sysview: error while removing device '%s': %s", ++ device->name, strerror(-r)); ++ sysview_device_free(device); ++ return error; ++} ++ ++static int context_add_session(sysview_context *c, sysview_seat *seat, const char *id) { ++ sysview_session *session; ++ sysview_device *device; ++ int r, error = 0; ++ Iterator i; ++ ++ assert(c); ++ assert(seat); ++ assert(id); ++ ++ session = sysview_find_session(c, id); ++ if (session) ++ return 0; ++ ++ log_debug("sysview: add session '%s' on seat '%s'", id, seat->name); ++ ++ r = sysview_session_new(&session, seat, id); ++ if (r < 0) ++ goto error; ++ ++ if (!seat->scanned) { ++ r = sysview_context_rescan(c); ++ if (r < 0) ++ goto error; ++ } ++ ++ if (seat->public) { ++ session->public = true; ++ r = context_raise_session_add(c, session); ++ if (r != 0) { ++ session->public = false; ++ goto error; ++ } ++ ++ HASHMAP_FOREACH(device, seat->device_map, i) { ++ r = context_raise_session_attach(c, session, device); ++ if (r != 0) ++ error = r; ++ } ++ ++ r = error; ++ if (r != 0) ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ if (r < 0) ++ log_debug("sysview: error while adding session '%s': %s", ++ id, strerror(-r)); ++ return r; ++} ++ ++static int context_remove_session(sysview_context *c, sysview_session *session) { ++ sysview_device *device; ++ int r, error = 0; ++ Iterator i; ++ ++ assert(c); ++ assert(session); ++ ++ log_debug("sysview: remove session '%s'", session->name); ++ ++ if (session->public) { ++ HASHMAP_FOREACH(device, session->seat->device_map, i) { ++ r = context_raise_session_detach(c, session, device); ++ if (r != 0) ++ error = r; ++ } ++ ++ session->public = false; ++ r = context_raise_session_remove(c, session); ++ if (r != 0) ++ error = r; ++ } ++ ++ if (!session->custom) ++ sysview_session_release_control(session); ++ ++ if (error < 0) ++ log_debug("sysview: error while removing session '%s': %s", ++ session->name, strerror(-error)); ++ sysview_session_free(session); ++ return error; ++} ++ ++static int context_add_seat(sysview_context *c, const char *id) { ++ sysview_seat *seat; ++ int r; ++ ++ assert(c); ++ assert(id); ++ ++ seat = sysview_find_seat(c, id); ++ if (seat) ++ return 0; ++ ++ log_debug("sysview: add seat '%s'", id); ++ ++ r = sysview_seat_new(&seat, c, id); ++ if (r < 0) ++ goto error; ++ ++ seat->public = true; ++ r = context_raise_seat_add(c, seat); ++ if (r != 0) { ++ seat->public = false; ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ if (r < 0) ++ log_debug("sysview: error while adding seat '%s': %s", ++ id, strerror(-r)); ++ return r; ++} ++ ++static int context_remove_seat(sysview_context *c, sysview_seat *seat) { ++ sysview_session *session; ++ sysview_device *device; ++ int r, error = 0; ++ ++ assert(c); ++ assert(seat); ++ ++ log_debug("sysview: remove seat '%s'", seat->name); ++ ++ while ((device = hashmap_first(seat->device_map))) { ++ r = context_remove_device(c, device); ++ if (r != 0) ++ error = r; ++ } ++ ++ while ((session = hashmap_first(seat->session_map))) { ++ r = context_remove_session(c, session); ++ if (r != 0) ++ error = r; ++ } ++ ++ if (seat->public) { ++ seat->public = false; ++ r = context_raise_seat_remove(c, seat); ++ if (r != 0) ++ error = r; ++ } ++ ++ if (error < 0) ++ log_debug("sysview: error while removing seat '%s': %s", ++ seat->name, strerror(-error)); ++ sysview_seat_free(seat); ++ return error; ++} ++ ++int sysview_context_new(sysview_context **out, ++ unsigned int flags, ++ sd_event *event, ++ sd_bus *sysbus, ++ struct udev *ud) { ++ _cleanup_(sysview_context_freep) sysview_context *c = NULL; ++ int r; ++ ++ assert_return(out, -EINVAL); ++ assert_return(event, -EINVAL); ++ ++ log_debug("sysview: new"); ++ ++ c = new0(sysview_context, 1); ++ if (!c) ++ return -ENOMEM; ++ ++ c->event = sd_event_ref(event); ++ if (flags & SYSVIEW_CONTEXT_SCAN_LOGIND) ++ c->scan_logind = true; ++ if (flags & SYSVIEW_CONTEXT_SCAN_EVDEV) ++ c->scan_evdev = true; ++ if (flags & SYSVIEW_CONTEXT_SCAN_DRM) ++ c->scan_drm = true; ++ ++ if (sysbus) { ++ c->sysbus = sd_bus_ref(sysbus); ++ } else if (c->scan_logind) { ++ r = sd_bus_open_system(&c->sysbus); ++ if (r < 0) ++ return r; ++ } ++ ++ if (ud) { ++ c->ud = udev_ref(ud); ++ } else if (c->scan_evdev || c->scan_drm) { ++ errno = 0; ++ c->ud = udev_new(); ++ if (!c->ud) ++ return errno > 0 ? -errno : -EFAULT; ++ } ++ ++ c->seat_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!c->seat_map) ++ return -ENOMEM; ++ ++ c->session_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!c->session_map) ++ return -ENOMEM; ++ ++ c->device_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!c->device_map) ++ return -ENOMEM; ++ ++ *out = c; ++ c = NULL; ++ return 0; ++} ++ ++sysview_context *sysview_context_free(sysview_context *c) { ++ if (!c) ++ return NULL; ++ ++ log_debug("sysview: free"); ++ ++ sysview_context_stop(c); ++ ++ assert(hashmap_size(c->device_map) == 0); ++ assert(hashmap_size(c->session_map) == 0); ++ assert(hashmap_size(c->seat_map) == 0); ++ ++ hashmap_free(c->device_map); ++ hashmap_free(c->session_map); ++ hashmap_free(c->seat_map); ++ c->ud = udev_unref(c->ud); ++ c->sysbus = sd_bus_unref(c->sysbus); ++ c->event = sd_event_unref(c->event); ++ free(c); ++ ++ return NULL; ++} ++ ++static int context_ud_prepare_monitor(sysview_context *c, struct udev_monitor *m) { ++ int r; ++ ++ if (c->scan_evdev) { ++ r = udev_monitor_filter_add_match_subsystem_devtype(m, "input", NULL); ++ if (r < 0) ++ return r; ++ } ++ ++ if (c->scan_drm) { ++ r = udev_monitor_filter_add_match_subsystem_devtype(m, "drm", NULL); ++ if (r < 0) ++ return r; ++ } ++ ++ return r; ++} ++ ++static int context_ud_prepare_scan(sysview_context *c, struct udev_enumerate *e) { ++ int r; ++ ++ if (c->scan_evdev) { ++ r = udev_enumerate_add_match_subsystem(e, "input"); ++ if (r < 0) ++ return r; ++ } ++ ++ if (c->scan_drm) { ++ r = udev_enumerate_add_match_subsystem(e, "drm"); ++ if (r < 0) ++ return r; ++ } ++ ++ r = udev_enumerate_add_match_is_initialized(e); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { ++ const char *syspath, *sysname, *subsystem, *action, *seatname; ++ sysview_device *device; ++ int r; ++ ++ syspath = udev_device_get_syspath(d); ++ sysname = udev_device_get_sysname(d); ++ subsystem = udev_device_get_subsystem(d); ++ action = udev_device_get_action(d); ++ ++ /* not interested in custom devices without syspath/etc */ ++ if (!syspath || !sysname || !subsystem) ++ return 0; ++ ++ device = sysview_find_device(c, syspath); ++ ++ if (streq_ptr(action, "remove")) { ++ if (!device) ++ return 0; ++ ++ return context_remove_device(c, device); ++ } else if (streq_ptr(action, "change")) { ++ if (!device) ++ return 0; ++ ++ /* TODO: send REFRESH event */ ++ } else if (!action || streq_ptr(action, "add")) { ++ struct udev_device *p; ++ unsigned int type, t; ++ sysview_seat *seat; ++ ++ if (device) ++ return 0; ++ ++ if (streq(subsystem, "input") && startswith(sysname, "event") && safe_atou(sysname + 5, &t) >= 0) ++ type = SYSVIEW_DEVICE_EVDEV; ++ else if (streq(subsystem, "drm") && startswith(sysname, "card") && safe_atou(sysname + 4, &t) >= 0) ++ type = SYSVIEW_DEVICE_DRM; ++ else ++ type = (unsigned)-1; ++ ++ if (type >= SYSVIEW_DEVICE_CNT) ++ return 0; ++ ++ p = d; ++ seatname = NULL; ++ while ((p = udev_device_get_parent(p))) { ++ seatname = udev_device_get_property_value(p, "ID_SEAT"); ++ if (seatname) ++ break; ++ } ++ ++ seat = sysview_find_seat(c, seatname ? : "seat0"); ++ if (!seat) ++ return 0; ++ ++ r = device_new_ud(&device, seat, type, d); ++ if (r < 0) { ++ log_debug("sysview: cannot create device for udev-device '%s': %s", ++ syspath, strerror(-r)); ++ return r; ++ } ++ ++ return context_add_device(c, device); ++ } ++ ++ return 0; ++} ++ ++static int context_ud_monitor_fn(sd_event_source *s, ++ int fd, ++ uint32_t revents, ++ void *userdata) { ++ sysview_context *c = userdata; ++ struct udev_device *d; ++ int r; ++ ++ if (revents & EPOLLIN) { ++ while ((d = udev_monitor_receive_device(c->ud_monitor))) { ++ r = context_ud_hotplug(c, d); ++ udev_device_unref(d); ++ if (r != 0) ++ return r; ++ } ++ ++ /* as long as EPOLLIN is signalled, read pending data */ ++ return 0; ++ } ++ ++ if (revents & (EPOLLHUP | EPOLLERR)) { ++ log_debug("sysview: HUP on udev-monitor"); ++ c->ud_monitor_src = sd_event_source_unref(c->ud_monitor_src); ++ } ++ ++ return 0; ++} ++ ++static int context_ud_start(sysview_context *c) { ++ int r, fd; ++ ++ if (!c->ud) ++ return 0; ++ ++ errno = 0; ++ c->ud_monitor = udev_monitor_new_from_netlink(c->ud, "udev"); ++ if (!c->ud_monitor) ++ return errno > 0 ? -errno : -EFAULT; ++ ++ r = context_ud_prepare_monitor(c, c->ud_monitor); ++ if (r < 0) ++ return r; ++ ++ r = udev_monitor_enable_receiving(c->ud_monitor); ++ if (r < 0) ++ return r; ++ ++ fd = udev_monitor_get_fd(c->ud_monitor); ++ r = sd_event_add_io(c->event, ++ &c->ud_monitor_src, ++ fd, ++ EPOLLHUP | EPOLLERR | EPOLLIN, ++ context_ud_monitor_fn, ++ c); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++static void context_ud_stop(sysview_context *c) { ++ c->ud_monitor_src = sd_event_source_unref(c->ud_monitor_src); ++ c->ud_monitor = udev_monitor_unref(c->ud_monitor); ++} ++ ++static int context_ud_scan(sysview_context *c) { ++ _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL; ++ struct udev_list_entry *entry; ++ struct udev_device *d; ++ int r; ++ ++ if (!c->ud_monitor) ++ return 0; ++ ++ errno = 0; ++ e = udev_enumerate_new(c->ud); ++ if (!e) ++ return errno > 0 ? -errno : -EFAULT; ++ ++ r = context_ud_prepare_scan(c, e); ++ if (r < 0) ++ return r; ++ ++ r = udev_enumerate_scan_devices(e); ++ if (r < 0) ++ return r; ++ ++ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { ++ const char *name; ++ ++ name = udev_list_entry_get_name(entry); ++ ++ errno = 0; ++ d = udev_device_new_from_syspath(c->ud, name); ++ if (!d) { ++ r = errno > 0 ? -errno : -EFAULT; ++ log_debug("sysview: cannot create udev-device for %s: %s", ++ name, strerror(-r)); ++ continue; ++ } ++ ++ r = context_ud_hotplug(c, d); ++ udev_device_unref(d); ++ if (r != 0) ++ return r; ++ } ++ ++ return 0; ++} ++ ++static int context_ld_seat_new(sysview_context *c, sd_bus_message *signal) { ++ const char *id, *path; ++ int r; ++ ++ r = sd_bus_message_read(signal, "so", &id, &path); ++ if (r < 0) { ++ log_debug("sysview: cannot parse SeatNew from logind: %s", ++ strerror(-r)); ++ return r; ++ } ++ ++ return context_add_seat(c, id); ++} ++ ++static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) { ++ const char *id, *path; ++ sysview_seat *seat; ++ int r; ++ ++ r = sd_bus_message_read(signal, "so", &id, &path); ++ if (r < 0) { ++ log_debug("sysview: cannot parse SeatRemoved from logind: %s", ++ strerror(-r)); ++ return r; ++ } ++ ++ seat = sysview_find_seat(c, id); ++ if (!seat) ++ return 0; ++ ++ return context_remove_seat(c, seat); ++} ++ ++static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) { ++ _cleanup_free_ char *seatid = NULL, *username = NULL; ++ const char *id, *path; ++ sysview_seat *seat; ++ uid_t uid; ++ int r; ++ ++ r = sd_bus_message_read(signal, "so", &id, &path); ++ if (r < 0) { ++ log_debug("sysview: cannot parse SessionNew from logind: %s", ++ strerror(-r)); ++ return r; ++ } ++ ++ /* ++ * As the dbus message didn't contain enough information, we ++ * read missing bits via sd-login. Note that this might race session ++ * destruction, so we handle ENOENT properly. ++ */ ++ ++ /* ENOENT is also returned for sessions without seats */ ++ r = sd_session_get_seat(id, &seatid); ++ if (r == -ENOENT) ++ return 0; ++ else if (r < 0) ++ goto error; ++ ++ seat = sysview_find_seat(c, seatid); ++ if (!seat) ++ return 0; ++ ++ r = sd_session_get_uid(id, &uid); ++ if (r == -ENOENT) ++ return 0; ++ else if (r < 0) ++ goto error; ++ ++ username = lookup_uid(uid); ++ if (!username) { ++ r = -ENOMEM; ++ goto error; ++ } ++ ++ r = context_raise_session_filter(c, id, seatid, username, uid); ++ if (r <= 0) { ++ if (r < 0) ++ log_debug("sysview: cannot filter new session '%s' on seat '%s': %s", ++ id, seatid, strerror(-r)); ++ return r; ++ } ++ ++ return context_add_session(c, seat, id); ++ ++error: ++ log_debug("sysview: failed retrieving information for new session '%s': %s", ++ id, strerror(-r)); ++ return r; ++} ++ ++static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal) { ++ sysview_session *session; ++ const char *id, *path; ++ int r; ++ ++ r = sd_bus_message_read(signal, "so", &id, &path); ++ if (r < 0) { ++ log_debug("sysview: cannot parse SessionRemoved from logind: %s", ++ strerror(-r)); ++ return r; ++ } ++ ++ session = sysview_find_session(c, id); ++ if (!session) ++ return 0; ++ ++ return context_remove_session(c, session); ++} ++ ++static int context_ld_manager_signal_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ sysview_context *c = userdata; ++ ++ if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SeatNew")) ++ return context_ld_seat_new(c, signal); ++ else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SeatRemoved")) ++ return context_ld_seat_removed(c, signal); ++ else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SessionNew")) ++ return context_ld_session_new(c, signal); ++ else if (sd_bus_message_is_signal(signal, "org.freedesktop.login1.Manager", "SessionRemoved")) ++ return context_ld_session_removed(c, signal); ++ else ++ return 0; ++} ++ ++static int context_ld_start(sysview_context *c) { ++ int r; ++ ++ if (!c->scan_logind) ++ return 0; ++ ++ r = sd_bus_add_match(c->sysbus, ++ &c->ld_slot_manager_signal, ++ "type='signal'," ++ "sender='org.freedesktop.login1'," ++ "interface='org.freedesktop.login1.Manager'," ++ "path='/org/freedesktop/login1'", ++ context_ld_manager_signal_fn, ++ c); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++static void context_ld_stop(sysview_context *c) { ++ c->ld_slot_list_sessions = sd_bus_slot_unref(c->ld_slot_list_sessions); ++ c->ld_slot_list_seats = sd_bus_slot_unref(c->ld_slot_list_seats); ++ c->ld_slot_manager_signal = sd_bus_slot_unref(c->ld_slot_manager_signal); ++} ++ ++static int context_ld_list_seats_fn(sd_bus *bus, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ sysview_context *c = userdata; ++ int r; ++ ++ c->ld_slot_list_seats = sd_bus_slot_unref(c->ld_slot_list_seats); ++ ++ if (sd_bus_message_is_method_error(reply, NULL)) { ++ const sd_bus_error *error = sd_bus_message_get_error(reply); ++ ++ log_debug("sysview: ListSeats on logind failed: %s: %s", ++ error->name, error->message); ++ return sd_bus_error_get_errno(error); ++ } ++ ++ r = sd_bus_message_enter_container(reply, 'a', "(so)"); ++ if (r < 0) ++ goto error; ++ ++ while ((r = sd_bus_message_enter_container(reply, 'r', "so")) > 0) { ++ const char *id, *path; ++ ++ r = sd_bus_message_read(reply, "so", &id, &path); ++ if (r < 0) ++ goto error; ++ ++ r = context_add_seat(c, id); ++ if (r != 0) ++ return r; ++ ++ r = sd_bus_message_exit_container(reply); ++ if (r < 0) ++ goto error; ++ } ++ ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_message_exit_container(reply); ++ if (r < 0) ++ return r; ++ ++ return 0; ++ ++error: ++ log_debug("sysview: erroneous ListSeats response from logind: %s", ++ strerror(-r)); ++ return r; ++} ++ ++static int context_ld_list_sessions_fn(sd_bus *bus, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ sysview_context *c = userdata; ++ int r; ++ ++ c->ld_slot_list_sessions = sd_bus_slot_unref(c->ld_slot_list_sessions); ++ ++ if (sd_bus_message_is_method_error(reply, NULL)) { ++ const sd_bus_error *error = sd_bus_message_get_error(reply); ++ ++ log_debug("sysview: ListSessions on logind failed: %s: %s", ++ error->name, error->message); ++ return sd_bus_error_get_errno(error); ++ } ++ ++ r = sd_bus_message_enter_container(reply, 'a', "(susso)"); ++ if (r < 0) ++ goto error; ++ ++ while ((r = sd_bus_message_enter_container(reply, 'r', "susso")) > 0) { ++ const char *id, *username, *seatid, *path; ++ sysview_seat *seat; ++ unsigned int uid; ++ ++ r = sd_bus_message_read(reply, ++ "susso", ++ &id, ++ &uid, ++ &username, ++ &seatid, ++ &path); ++ if (r < 0) ++ goto error; ++ ++ seat = sysview_find_seat(c, seatid); ++ if (seat) { ++ r = context_raise_session_filter(c, id, seatid, username, uid); ++ if (r < 0) { ++ log_debug("sysview: cannot filter listed session '%s' on seat '%s': %s", ++ id, seatid, strerror(-r)); ++ return r; ++ } else if (r > 0) { ++ r = context_add_session(c, seat, id); ++ if (r != 0) ++ return r; ++ } ++ } ++ ++ r = sd_bus_message_exit_container(reply); ++ if (r < 0) ++ goto error; ++ } ++ ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_message_exit_container(reply); ++ if (r < 0) ++ return r; ++ ++ return 0; ++ ++error: ++ log_debug("sysview: erroneous ListSessions response from logind: %s", ++ strerror(-r)); ++ return r; ++} ++ ++static int context_ld_scan(sysview_context *c) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ int r; ++ ++ if (!c->ld_slot_manager_signal) ++ return 0; ++ ++ /* request seat list */ ++ ++ r = sd_bus_message_new_method_call(c->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ "/org/freedesktop/login1", ++ "org.freedesktop.login1.Manager", ++ "ListSeats"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_call_async(c->sysbus, ++ &c->ld_slot_list_seats, ++ m, ++ context_ld_list_seats_fn, ++ c, ++ 0); ++ if (r < 0) ++ return r; ++ ++ /* request session list */ ++ ++ m = sd_bus_message_unref(m); ++ r = sd_bus_message_new_method_call(c->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ "/org/freedesktop/login1", ++ "org.freedesktop.login1.Manager", ++ "ListSessions"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_call_async(c->sysbus, ++ &c->ld_slot_list_sessions, ++ m, ++ context_ld_list_sessions_fn, ++ c, ++ 0); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++bool sysview_context_is_running(sysview_context *c) { ++ return c && c->running; ++} ++ ++int sysview_context_start(sysview_context *c, sysview_event_fn event_fn, void *userdata) { ++ int r; ++ ++ assert_return(c, -EINVAL); ++ assert_return(event_fn, -EINVAL); ++ ++ if (c->running) ++ return -EALREADY; ++ ++ log_debug("sysview: start"); ++ ++ c->running = true; ++ c->event_fn = event_fn; ++ c->userdata = userdata; ++ ++ r = context_ld_start(c); ++ if (r < 0) ++ goto error; ++ ++ r = context_ud_start(c); ++ if (r < 0) ++ goto error; ++ ++ r = sysview_context_rescan(c); ++ if (r < 0) ++ goto error; ++ ++ return 0; ++ ++error: ++ sysview_context_stop(c); ++ return r; ++} ++ ++void sysview_context_stop(sysview_context *c) { ++ sysview_session *session; ++ sysview_device *device; ++ sysview_seat *seat; ++ ++ assert(c); ++ ++ if (!c->running) ++ return; ++ ++ log_debug("sysview: stop"); ++ ++ c->running = false; ++ c->scanned = false; ++ c->event_fn = NULL; ++ c->userdata = NULL; ++ c->scan_src = sd_event_source_unref(c->scan_src); ++ context_ud_stop(c); ++ context_ld_stop(c); ++ ++ /* ++ * Event-callbacks are already cleared, hence we can safely ignore ++ * return codes of the context_remove_*() helpers. They cannot be ++ * originated from user-callbacks, so we already handled them. ++ */ ++ ++ while ((device = hashmap_first(c->device_map))) ++ context_remove_device(c, device); ++ ++ while ((session = hashmap_first(c->session_map))) ++ context_remove_session(c, session); ++ ++ while ((seat = hashmap_first(c->seat_map))) ++ context_remove_seat(c, seat); ++} ++ ++static int context_scan_fn(sd_event_source *s, void *userdata) { ++ sysview_context *c = userdata; ++ sysview_seat *seat; ++ Iterator i; ++ int r; ++ ++ if (!c->scanned) { ++ r = context_ld_scan(c); ++ if (r < 0) { ++ log_debug("sysview: logind scan failed: %s", strerror(-r)); ++ return r; ++ } ++ } ++ ++ /* skip device scans if no sessions are available */ ++ if (hashmap_size(c->session_map) > 0) { ++ r = context_ud_scan(c); ++ if (r < 0) { ++ log_debug("sysview: udev scan failed: %s", strerror(-r)); ++ return r; ++ } ++ ++ HASHMAP_FOREACH(seat, c->seat_map, i) ++ seat->scanned = true; ++ } ++ ++ c->scanned = true; ++ ++ return 0; ++} ++ ++int sysview_context_rescan(sysview_context *c) { ++ assert(c); ++ ++ if (!c->running) ++ return 0; ++ ++ if (c->scan_src) ++ return sd_event_source_set_enabled(c->scan_src, SD_EVENT_ONESHOT); ++ else ++ return sd_event_add_defer(c->event, &c->scan_src, context_scan_fn, c); ++} +diff --git a/src/libsystemd-terminal/sysview.h b/src/libsystemd-terminal/sysview.h +new file mode 100644 +index 0000000000..de6ff371db +--- /dev/null ++++ b/src/libsystemd-terminal/sysview.h +@@ -0,0 +1,151 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++/* ++ * System View ++ * The sysview interface scans and monitors the system for seats, sessions and ++ * devices. It basically mirrors the state of logind on the application side. ++ * It's meant as base for session services that require managed device access. ++ * The logind controller API is employed to allow unprivileged access to all ++ * devices of a user. ++ * Furthermore, the sysview interface can be used for system services that run ++ * in situations where logind is not available, but session-like services are ++ * needed. For instance, the initrd does not run logind but might require ++ * graphics access. It cannot run session services, though. The sysview ++ * interface pretends that a session is available and provides the same ++ * interface as to normal session services. ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "util.h" ++ ++typedef struct sysview_event sysview_event; ++typedef struct sysview_device sysview_device; ++typedef struct sysview_session sysview_session; ++typedef struct sysview_seat sysview_seat; ++typedef struct sysview_context sysview_context; ++ ++/* ++ * Events ++ */ ++ ++enum { ++ SYSVIEW_EVENT_SEAT_ADD, ++ SYSVIEW_EVENT_SEAT_REMOVE, ++ ++ SYSVIEW_EVENT_SESSION_FILTER, ++ SYSVIEW_EVENT_SESSION_ADD, ++ SYSVIEW_EVENT_SESSION_REMOVE, ++ SYSVIEW_EVENT_SESSION_ATTACH, ++ SYSVIEW_EVENT_SESSION_DETACH, ++ SYSVIEW_EVENT_SESSION_CONTROL, ++}; ++ ++struct sysview_event { ++ unsigned int type; ++ ++ union { ++ struct { ++ sysview_seat *seat; ++ } seat_add, seat_remove; ++ ++ struct { ++ const char *id; ++ const char *seatid; ++ const char *username; ++ unsigned int uid; ++ } session_filter; ++ ++ struct { ++ sysview_session *session; ++ } session_add, session_remove; ++ ++ struct { ++ sysview_session *session; ++ sysview_device *device; ++ } session_attach, session_detach; ++ ++ struct { ++ sysview_session *session; ++ int error; ++ } session_control; ++ }; ++}; ++ ++typedef int (*sysview_event_fn) (sysview_context *c, void *userdata, sysview_event *e); ++ ++/* ++ * Devices ++ */ ++ ++enum { ++ SYSVIEW_DEVICE_EVDEV, ++ SYSVIEW_DEVICE_DRM, ++ SYSVIEW_DEVICE_CNT ++}; ++ ++unsigned int sysview_device_get_type(sysview_device *device); ++struct udev_device *sysview_device_get_ud(sysview_device *device); ++ ++/* ++ * Sessions ++ */ ++ ++const char *sysview_session_get_name(sysview_session *session); ++ ++int sysview_session_take_control(sysview_session *session); ++void sysview_session_release_control(sysview_session *session); ++ ++/* ++ * Seats ++ */ ++ ++const char *sysview_seat_get_name(sysview_seat *seat); ++ ++/* ++ * Contexts ++ */ ++ ++enum { ++ SYSVIEW_CONTEXT_SCAN_LOGIND = (1 << 0), ++ SYSVIEW_CONTEXT_SCAN_EVDEV = (1 << 1), ++ SYSVIEW_CONTEXT_SCAN_DRM = (1 << 2), ++}; ++ ++int sysview_context_new(sysview_context **out, ++ unsigned int flags, ++ sd_event *event, ++ sd_bus *sysbus, ++ struct udev *ud); ++sysview_context *sysview_context_free(sysview_context *c); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(sysview_context*, sysview_context_free); ++ ++bool sysview_context_is_running(sysview_context *c); ++int sysview_context_start(sysview_context *c, sysview_event_fn event_fn, void *userdata); ++void sysview_context_stop(sysview_context *c); diff --git a/0082-terminal-add-input-interface.patch b/0082-terminal-add-input-interface.patch new file mode 100644 index 0000000..a59129a --- /dev/null +++ b/0082-terminal-add-input-interface.patch @@ -0,0 +1,975 @@ +From e202fa31fb2d60084e7b2ab7976a81c138184d40 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 27 Aug 2014 18:17:27 +0200 +Subject: [PATCH] terminal: add input interface + +The idev-interface provides input drivers for all libsystemd-terminal +based applications. It is split into 4 main objects: + idev_context: The context object tracks global state of the input + interface. This will include data like system-keymaps, + xkb contexts and more. + idev_session: A session serves as controller for a set of devices. + Each session on an idev-context is independent of each + other. The session is also the main notification object. + All events raised via idev are reported through the + session interface. Apart of that, the session is a + pretty dumb object that just contains devices. + idev_element: Elements provide real hardware in the idev stack. For + each hardware device, one element is added. Elements + have no knowledge of higher-level device types, they + only provide raw input data to the upper levels. For + example, each evdev device is represented by a different + element in an idev session. + idev_device: Devices are objects that the application deals with. An + application is usually not interested in elements (and + those are hidden to applications), instead, they want + high-level input devices like keyboard, touchpads, mice + and more. Device are the high-level interface provided + by idev. Each device might be fed by a set of elements. + Elements drive the device. If elements are removed, + devices are destroyed. If elements are added, suitable + devices are created. + +Applications should monitor the system for sessions and hardware devices. +For each session they want to operate on, they create an idev_session +object and add hardware to that object. The idev interface requires the +application to monitor the system (preferably via sysview_*, but not +required) for hardware devices. Whenever hardware is added to the idev +session, new devices *might* be created. The relationship between hardware +and high-level idev-devices is hidden in the idev-session and not exposed. + +Internally, the idev elements and devices are virtual objects. Each real +hardware and device type inherits those virtual objects and provides real +elements and devices. Those types will be added in follow-up commits. + +Data flow from hardware to the application is done via idev_*_feed() +functions. Data flow from applications to hardware is done via +idev_*_feedback() functions. Feedback is usually used for LEDs, FF and +similar operations. +--- + Makefile.am | 3 + + src/libsystemd-terminal/idev-internal.h | 165 +++++++++ + src/libsystemd-terminal/idev.c | 587 ++++++++++++++++++++++++++++++++ + src/libsystemd-terminal/idev.h | 133 ++++++++ + 4 files changed, 888 insertions(+) + create mode 100644 src/libsystemd-terminal/idev-internal.h + create mode 100644 src/libsystemd-terminal/idev.c + create mode 100644 src/libsystemd-terminal/idev.h + +diff --git a/Makefile.am b/Makefile.am +index 3a263f8c17..82f474e20e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2971,6 +2971,9 @@ libsystemd_terminal_la_CFLAGS = \ + $(AM_CFLAGS) + + libsystemd_terminal_la_SOURCES = \ ++ src/libsystemd-terminal/idev.h \ ++ src/libsystemd-terminal/idev-internal.h \ ++ src/libsystemd-terminal/idev.c \ + src/libsystemd-terminal/sysview.h \ + src/libsystemd-terminal/sysview-internal.h \ + src/libsystemd-terminal/sysview.c \ +diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h +new file mode 100644 +index 0000000000..bffefbb9c1 +--- /dev/null ++++ b/src/libsystemd-terminal/idev-internal.h +@@ -0,0 +1,165 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include "hashmap.h" ++#include "idev.h" ++#include "list.h" ++#include "util.h" ++ ++typedef struct idev_link idev_link; ++typedef struct idev_device_vtable idev_device_vtable; ++typedef struct idev_element idev_element; ++typedef struct idev_element_vtable idev_element_vtable; ++ ++/* ++ * Element Links ++ */ ++ ++struct idev_link { ++ /* element-to-device connection */ ++ LIST_FIELDS(idev_link, links_by_element); ++ idev_element *element; ++ ++ /* device-to-element connection */ ++ LIST_FIELDS(idev_link, links_by_device); ++ idev_device *device; ++}; ++ ++/* ++ * Devices ++ */ ++ ++struct idev_device_vtable { ++ void (*free) (idev_device *d); ++ void (*attach) (idev_device *d, idev_link *l); ++ void (*detach) (idev_device *d, idev_link *l); ++ int (*feed) (idev_device *d, idev_data *data); ++}; ++ ++struct idev_device { ++ const idev_device_vtable *vtable; ++ idev_session *session; ++ char *name; ++ ++ LIST_HEAD(idev_link, links); ++ ++ bool public : 1; ++ bool enabled : 1; ++}; ++ ++#define IDEV_DEVICE_INIT(_vtable, _session) ((idev_device){ \ ++ .vtable = (_vtable), \ ++ .session = (_session), \ ++ }) ++ ++idev_device *idev_find_device(idev_session *s, const char *name); ++ ++int idev_device_add(idev_device *d, const char *name); ++idev_device *idev_device_free(idev_device *d); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(idev_device*, idev_device_free); ++ ++int idev_device_feed(idev_device *d, idev_data *data); ++void idev_device_feedback(idev_device *d, idev_data *data); ++ ++/* ++ * Elements ++ */ ++ ++struct idev_element_vtable { ++ void (*free) (idev_element *e); ++ void (*enable) (idev_element *e); ++ void (*disable) (idev_element *e); ++ void (*open) (idev_element *e); ++ void (*close) (idev_element *e); ++ void (*feedback) (idev_element *e, idev_data *data); ++}; ++ ++struct idev_element { ++ const idev_element_vtable *vtable; ++ idev_session *session; ++ unsigned long n_open; ++ char *name; ++ ++ LIST_HEAD(idev_link, links); ++ ++ bool enabled : 1; ++ bool readable : 1; ++ bool writable : 1; ++}; ++ ++#define IDEV_ELEMENT_INIT(_vtable, _session) ((idev_element){ \ ++ .vtable = (_vtable), \ ++ .session = (_session), \ ++ }) ++ ++idev_element *idev_find_element(idev_session *s, const char *name); ++ ++int idev_element_add(idev_element *e, const char *name); ++idev_element *idev_element_free(idev_element *e); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(idev_element*, idev_element_free); ++ ++int idev_element_feed(idev_element *e, idev_data *data); ++void idev_element_feedback(idev_element *e, idev_data *data); ++ ++/* ++ * Sessions ++ */ ++ ++struct idev_session { ++ idev_context *context; ++ char *name; ++ char *path; ++ ++ Hashmap *element_map; ++ Hashmap *device_map; ++ ++ idev_event_fn event_fn; ++ void *userdata; ++ ++ bool custom : 1; ++ bool managed : 1; ++ bool enabled : 1; ++}; ++ ++idev_session *idev_find_session(idev_context *c, const char *name); ++int idev_session_raise_device_data(idev_session *s, idev_device *d, idev_data *data); ++ ++/* ++ * Contexts ++ */ ++ ++struct idev_context { ++ unsigned long ref; ++ sd_event *event; ++ sd_bus *sysbus; ++ ++ Hashmap *session_map; ++ Hashmap *data_map; ++}; +diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c +new file mode 100644 +index 0000000000..5e3080797a +--- /dev/null ++++ b/src/libsystemd-terminal/idev.c +@@ -0,0 +1,587 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 "hashmap.h" ++#include "idev.h" ++#include "idev-internal.h" ++#include "login-shared.h" ++#include "macro.h" ++#include "set.h" ++#include "util.h" ++ ++static void element_open(idev_element *e); ++static void element_close(idev_element *e); ++ ++/* ++ * Devices ++ */ ++ ++idev_device *idev_find_device(idev_session *s, const char *name) { ++ assert_return(s, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(s->device_map, name); ++} ++ ++int idev_device_add(idev_device *d, const char *name) { ++ int r; ++ ++ assert_return(d, -EINVAL); ++ assert_return(d->vtable, -EINVAL); ++ assert_return(d->session, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ d->name = strdup(name); ++ if (!d->name) ++ return -ENOMEM; ++ ++ r = hashmap_put(d->session->device_map, d->name, d); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++idev_device *idev_device_free(idev_device *d) { ++ idev_device tmp; ++ ++ if (!d) ++ return NULL; ++ ++ assert(!d->enabled); ++ assert(!d->public); ++ assert(!d->links); ++ assert(d->vtable); ++ assert(d->vtable->free); ++ ++ if (d->name) ++ hashmap_remove_value(d->session->device_map, d->name, d); ++ ++ tmp = *d; ++ d->vtable->free(d); ++ ++ free(tmp.name); ++ ++ return NULL; ++} ++ ++int idev_device_feed(idev_device *d, idev_data *data) { ++ assert(d); ++ assert(data); ++ assert(data->type < IDEV_DATA_CNT); ++ ++ if (d->vtable->feed) ++ return d->vtable->feed(d, data); ++ else ++ return 0; ++} ++ ++void idev_device_feedback(idev_device *d, idev_data *data) { ++ idev_link *l; ++ ++ assert(d); ++ assert(data); ++ assert(data->type < IDEV_DATA_CNT); ++ ++ LIST_FOREACH(links_by_device, l, d->links) ++ idev_element_feedback(l->element, data); ++} ++ ++static void device_attach(idev_device *d, idev_link *l) { ++ assert(d); ++ assert(l); ++ ++ if (d->vtable->attach) ++ d->vtable->attach(d, l); ++ ++ if (d->enabled) ++ element_open(l->element); ++} ++ ++static void device_detach(idev_device *d, idev_link *l) { ++ assert(d); ++ assert(l); ++ ++ if (d->enabled) ++ element_close(l->element); ++ ++ if (d->vtable->detach) ++ d->vtable->detach(d, l); ++} ++ ++void idev_device_enable(idev_device *d) { ++ idev_link *l; ++ ++ assert(d); ++ ++ if (!d->enabled) { ++ d->enabled = true; ++ LIST_FOREACH(links_by_device, l, d->links) ++ element_open(l->element); ++ } ++} ++ ++void idev_device_disable(idev_device *d) { ++ idev_link *l; ++ ++ assert(d); ++ ++ if (d->enabled) { ++ d->enabled = false; ++ LIST_FOREACH(links_by_device, l, d->links) ++ element_close(l->element); ++ } ++} ++ ++/* ++ * Elements ++ */ ++ ++idev_element *idev_find_element(idev_session *s, const char *name) { ++ assert_return(s, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(s->element_map, name); ++} ++ ++int idev_element_add(idev_element *e, const char *name) { ++ int r; ++ ++ assert_return(e, -EINVAL); ++ assert_return(e->vtable, -EINVAL); ++ assert_return(e->session, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ e->name = strdup(name); ++ if (!e->name) ++ return -ENOMEM; ++ ++ r = hashmap_put(e->session->element_map, e->name, e); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++idev_element *idev_element_free(idev_element *e) { ++ idev_element tmp; ++ ++ if (!e) ++ return NULL; ++ ++ assert(!e->enabled); ++ assert(!e->links); ++ assert(e->n_open == 0); ++ assert(e->vtable); ++ assert(e->vtable->free); ++ ++ if (e->name) ++ hashmap_remove_value(e->session->element_map, e->name, e); ++ ++ tmp = *e; ++ e->vtable->free(e); ++ ++ free(tmp.name); ++ ++ return NULL; ++} ++ ++int idev_element_feed(idev_element *e, idev_data *data) { ++ int r, error = 0; ++ idev_link *l; ++ ++ assert(e); ++ assert(data); ++ assert(data->type < IDEV_DATA_CNT); ++ ++ LIST_FOREACH(links_by_element, l, e->links) { ++ r = idev_device_feed(l->device, data); ++ if (r != 0) ++ error = r; ++ } ++ ++ return error; ++} ++ ++void idev_element_feedback(idev_element *e, idev_data *data) { ++ assert(e); ++ assert(data); ++ assert(data->type < IDEV_DATA_CNT); ++ ++ if (e->vtable->feedback) ++ e->vtable->feedback(e, data); ++} ++ ++static void element_open(idev_element *e) { ++ assert(e); ++ ++ if (e->n_open++ == 0 && e->vtable->open) ++ e->vtable->open(e); ++} ++ ++static void element_close(idev_element *e) { ++ assert(e); ++ assert(e->n_open > 0); ++ ++ if (--e->n_open == 0 && e->vtable->close) ++ e->vtable->close(e); ++} ++ ++static void element_enable(idev_element *e) { ++ assert(e); ++ ++ if (!e->enabled) { ++ e->enabled = true; ++ if (e->vtable->enable) ++ e->vtable->enable(e); ++ } ++} ++ ++static void element_disable(idev_element *e) { ++ assert(e); ++ ++ if (e->enabled) { ++ e->enabled = false; ++ if (e->vtable->disable) ++ e->vtable->disable(e); ++ } ++} ++ ++/* ++ * Sessions ++ */ ++ ++static int session_raise(idev_session *s, idev_event *ev) { ++ return s->event_fn(s, s->userdata, ev); ++} ++ ++static int session_raise_device_add(idev_session *s, idev_device *d) { ++ idev_event event = { ++ .type = IDEV_EVENT_DEVICE_ADD, ++ .device_add = { ++ .device = d, ++ }, ++ }; ++ ++ return session_raise(s, &event); ++} ++ ++static int session_raise_device_remove(idev_session *s, idev_device *d) { ++ idev_event event = { ++ .type = IDEV_EVENT_DEVICE_REMOVE, ++ .device_remove = { ++ .device = d, ++ }, ++ }; ++ ++ return session_raise(s, &event); ++} ++ ++int idev_session_raise_device_data(idev_session *s, idev_device *d, idev_data *data) { ++ idev_event event = { ++ .type = IDEV_EVENT_DEVICE_DATA, ++ .device_data = { ++ .device = d, ++ .data = *data, ++ }, ++ }; ++ ++ return session_raise(s, &event); ++} ++ ++static int session_add_device(idev_session *s, idev_device *d) { ++ int r; ++ ++ assert(s); ++ assert(d); ++ ++ log_debug("idev: %s: add device '%s'", s->name, d->name); ++ ++ d->public = true; ++ r = session_raise_device_add(s, d); ++ if (r != 0) { ++ d->public = false; ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ if (r < 0) ++ log_debug("idev: %s: error while adding device '%s': %s", ++ s->name, d->name, strerror(-r)); ++ return r; ++} ++ ++static int session_remove_device(idev_session *s, idev_device *d) { ++ int r, error = 0; ++ ++ assert(s); ++ assert(d); ++ ++ log_debug("idev: %s: remove device '%s'", s->name, d->name); ++ ++ d->public = false; ++ r = session_raise_device_remove(s, d); ++ if (r != 0) ++ error = r; ++ ++ idev_device_disable(d); ++ ++ if (error < 0) ++ log_debug("idev: %s: error while removing device '%s': %s", ++ s->name, d->name, strerror(-error)); ++ idev_device_free(d); ++ return error; ++} ++ ++static int session_add_element(idev_session *s, idev_element *e) { ++ assert(s); ++ assert(e); ++ ++ log_debug("idev: %s: add element '%s'", s->name, e->name); ++ ++ if (s->enabled) ++ element_enable(e); ++ ++ return 0; ++} ++ ++static int session_remove_element(idev_session *s, idev_element *e) { ++ int r, error = 0; ++ idev_device *d; ++ idev_link *l; ++ ++ assert(s); ++ assert(e); ++ ++ log_debug("idev: %s: remove element '%s'", s->name, e->name); ++ ++ while ((l = e->links)) { ++ d = l->device; ++ LIST_REMOVE(links_by_device, d->links, l); ++ LIST_REMOVE(links_by_element, e->links, l); ++ device_detach(d, l); ++ ++ if (!d->links) { ++ r = session_remove_device(s, d); ++ if (r != 0) ++ error = r; ++ } ++ ++ l->device = NULL; ++ l->element = NULL; ++ free(l); ++ } ++ ++ element_disable(e); ++ ++ if (error < 0) ++ log_debug("idev: %s: error while removing element '%s': %s", ++ s->name, e->name, strerror(-r)); ++ idev_element_free(e); ++ return error; ++} ++ ++idev_session *idev_find_session(idev_context *c, const char *name) { ++ assert_return(c, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(c->session_map, name); ++} ++ ++int idev_session_new(idev_session **out, ++ idev_context *c, ++ unsigned int flags, ++ const char *name, ++ idev_event_fn event_fn, ++ void *userdata) { ++ _cleanup_(idev_session_freep) idev_session *s = NULL; ++ int r; ++ ++ assert_return(out, -EINVAL); ++ assert_return(c, -EINVAL); ++ assert_return(name, -EINVAL); ++ assert_return(event_fn, -EINVAL); ++ assert_return((flags & IDEV_SESSION_CUSTOM) == !session_id_valid(name), -EINVAL); ++ assert_return(!(flags & IDEV_SESSION_CUSTOM) || !(flags & IDEV_SESSION_MANAGED), -EINVAL); ++ assert_return(!(flags & IDEV_SESSION_MANAGED) || c->sysbus, -EINVAL); ++ ++ s = new0(idev_session, 1); ++ if (!s) ++ return -ENOMEM; ++ ++ s->context = idev_context_ref(c); ++ s->custom = flags & IDEV_SESSION_CUSTOM; ++ s->managed = flags & IDEV_SESSION_MANAGED; ++ s->event_fn = event_fn; ++ s->userdata = userdata; ++ ++ s->name = strdup(name); ++ if (!s->name) ++ return -ENOMEM; ++ ++ if (s->managed) { ++ r = sd_bus_path_encode("/org/freedesktop/login1/session", s->name, &s->path); ++ if (r < 0) ++ return r; ++ } ++ ++ s->element_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!s->element_map) ++ return -ENOMEM; ++ ++ s->device_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!s->device_map) ++ return -ENOMEM; ++ ++ r = hashmap_put(c->session_map, s->name, s); ++ if (r < 0) ++ return r; ++ ++ *out = s; ++ s = NULL; ++ return 0; ++} ++ ++idev_session *idev_session_free(idev_session *s) { ++ idev_element *e; ++ ++ if (!s) ++ return NULL; ++ ++ while ((e = hashmap_first(s->element_map))) ++ session_remove_element(s, e); ++ ++ assert(hashmap_size(s->device_map) == 0); ++ ++ if (s->name) ++ hashmap_remove_value(s->context->session_map, s->name, s); ++ ++ s->context = idev_context_unref(s->context); ++ hashmap_free(s->device_map); ++ hashmap_free(s->element_map); ++ free(s->path); ++ free(s->name); ++ free(s); ++ ++ return NULL; ++} ++ ++bool idev_session_is_enabled(idev_session *s) { ++ return s && s->enabled; ++} ++ ++void idev_session_enable(idev_session *s) { ++ idev_element *e; ++ Iterator i; ++ ++ assert(s); ++ ++ if (!s->enabled) { ++ s->enabled = true; ++ HASHMAP_FOREACH(e, s->element_map, i) ++ element_enable(e); ++ } ++} ++ ++void idev_session_disable(idev_session *s) { ++ idev_element *e; ++ Iterator i; ++ ++ assert(s); ++ ++ if (s->enabled) { ++ s->enabled = false; ++ HASHMAP_FOREACH(e, s->element_map, i) ++ element_disable(e); ++ } ++} ++ ++/* ++ * Contexts ++ */ ++ ++int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus) { ++ _cleanup_(idev_context_unrefp) idev_context *c = NULL; ++ ++ assert_return(out, -EINVAL); ++ assert_return(event, -EINVAL); ++ ++ c = new0(idev_context, 1); ++ if (!c) ++ return -ENOMEM; ++ ++ c->ref = 1; ++ c->event = sd_event_ref(event); ++ ++ if (sysbus) ++ c->sysbus = sd_bus_ref(sysbus); ++ ++ c->session_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!c->session_map) ++ return -ENOMEM; ++ ++ c->data_map = hashmap_new(string_hash_func, string_compare_func); ++ if (!c->data_map) ++ return -ENOMEM; ++ ++ *out = c; ++ c = NULL; ++ return 0; ++} ++ ++static void context_cleanup(idev_context *c) { ++ assert(hashmap_size(c->data_map) == 0); ++ assert(hashmap_size(c->session_map) == 0); ++ ++ hashmap_free(c->data_map); ++ hashmap_free(c->session_map); ++ c->sysbus = sd_bus_unref(c->sysbus); ++ c->event = sd_event_unref(c->event); ++ free(c); ++} ++ ++idev_context *idev_context_ref(idev_context *c) { ++ assert_return(c, NULL); ++ assert_return(c->ref > 0, NULL); ++ ++ ++c->ref; ++ return c; ++} ++ ++idev_context *idev_context_unref(idev_context *c) { ++ if (!c) ++ return NULL; ++ ++ assert_return(c->ref > 0, NULL); ++ ++ if (--c->ref == 0) ++ context_cleanup(c); ++ ++ return NULL; ++} +diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h +new file mode 100644 +index 0000000000..6f618f37af +--- /dev/null ++++ b/src/libsystemd-terminal/idev.h +@@ -0,0 +1,133 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++/* ++ * IDev ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include "util.h" ++ ++typedef struct idev_data idev_data; ++ ++typedef struct idev_event idev_event; ++typedef struct idev_device idev_device; ++typedef struct idev_session idev_session; ++typedef struct idev_context idev_context; ++ ++/* ++ * Types ++ */ ++ ++enum { ++ IDEV_ELEMENT_CNT ++}; ++ ++enum { ++ IDEV_DEVICE_CNT ++}; ++ ++/* ++ * Data Packets ++ */ ++ ++enum { ++ IDEV_DATA_RESYNC, ++ IDEV_DATA_CNT ++}; ++ ++struct idev_data { ++ unsigned int type; ++ bool resync : 1; ++}; ++ ++/* ++ * Events ++ */ ++ ++enum { ++ IDEV_EVENT_DEVICE_ADD, ++ IDEV_EVENT_DEVICE_REMOVE, ++ IDEV_EVENT_DEVICE_DATA, ++ IDEV_EVENT_CNT ++}; ++ ++struct idev_event { ++ unsigned int type; ++ union { ++ struct { ++ idev_device *device; ++ } device_add, device_remove; ++ ++ struct { ++ idev_device *device; ++ idev_data data; ++ } device_data; ++ }; ++}; ++ ++typedef int (*idev_event_fn) (idev_session *s, void *userdata, idev_event *ev); ++ ++/* ++ * Devices ++ */ ++ ++void idev_device_enable(idev_device *d); ++void idev_device_disable(idev_device *d); ++ ++/* ++ * Sessions ++ */ ++ ++enum { ++ IDEV_SESSION_CUSTOM = (1 << 0), ++ IDEV_SESSION_MANAGED = (1 << 1), ++}; ++ ++int idev_session_new(idev_session **out, ++ idev_context *c, ++ unsigned int flags, ++ const char *name, ++ idev_event_fn event_fn, ++ void *userdata); ++idev_session *idev_session_free(idev_session *s); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(idev_session*, idev_session_free); ++ ++bool idev_session_is_enabled(idev_session *s); ++void idev_session_enable(idev_session *s); ++void idev_session_disable(idev_session *s); ++ ++/* ++ * Contexts ++ */ ++ ++int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus); ++idev_context *idev_context_ref(idev_context *c); ++idev_context *idev_context_unref(idev_context *c); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(idev_context*, idev_context_unref); diff --git a/0083-terminal-add-evdev-elements-to-idev.patch b/0083-terminal-add-evdev-elements-to-idev.patch new file mode 100644 index 0000000..c11da59 --- /dev/null +++ b/0083-terminal-add-evdev-elements-to-idev.patch @@ -0,0 +1,1189 @@ +From c93e5a62ff599528c3bf2a8656825403aaebe093 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 27 Aug 2014 18:31:34 +0200 +Subject: [PATCH] terminal: add evdev elements to idev + +The evdev-element provides linux evdev interfaces as idev-elements. This +way, all real input hardware devices on linux can be used with the idev +interface. + +We use libevdev to interface with the kernel. It's a simple wrapper +library around the kernel evdev API that takes care to resync devices +after kernel-queue overflows, which is a rather non-trivial task. +Furthermore, it's a well tested interface used by all other major input +users (Xorg, weston, libinput, ...). +Last but not least, it provides nice keycode to keyname lookup tables (and +vice versa), which is really nice for debugging input problems. +--- + Makefile.am | 7 +- + configure.ac | 7 +- + src/libsystemd-terminal/idev-evdev.c | 938 ++++++++++++++++++++++++++++++++ + src/libsystemd-terminal/idev-internal.h | 10 + + src/libsystemd-terminal/idev.c | 48 ++ + src/libsystemd-terminal/idev.h | 20 + + 6 files changed, 1026 insertions(+), 4 deletions(-) + create mode 100644 src/libsystemd-terminal/idev-evdev.c + +diff --git a/Makefile.am b/Makefile.am +index 82f474e20e..b51c522443 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2968,12 +2968,14 @@ tests += \ + endif + + libsystemd_terminal_la_CFLAGS = \ +- $(AM_CFLAGS) ++ $(AM_CFLAGS) \ ++ $(TERMINAL_CFLAGS) + + libsystemd_terminal_la_SOURCES = \ + src/libsystemd-terminal/idev.h \ + src/libsystemd-terminal/idev-internal.h \ + src/libsystemd-terminal/idev.c \ ++ src/libsystemd-terminal/idev-evdev.c \ + src/libsystemd-terminal/sysview.h \ + src/libsystemd-terminal/sysview-internal.h \ + src/libsystemd-terminal/sysview.c \ +@@ -2989,7 +2991,8 @@ libsystemd_terminal_la_SOURCES = \ + libsystemd_terminal_la_LIBADD = \ + libudev-internal.la \ + libsystemd-internal.la \ +- libsystemd-shared.la ++ libsystemd-shared.la \ ++ $(TERMINAL_LIBS) + + systemd_subterm_SOURCES = \ + src/libsystemd-terminal/subterm.c +diff --git a/configure.ac b/configure.ac +index 08a8a105f8..3900c4065b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1066,8 +1066,11 @@ AM_CONDITIONAL(ENABLE_MULTI_SEAT_X, [test "$have_multi_seat_x" = "yes"]) + have_terminal=no + AC_ARG_ENABLE(terminal, AS_HELP_STRING([--enable-terminal], [enable terminal support])) + if test "x$enable_terminal" = "xyes"; then +- AC_DEFINE(ENABLE_TERMINAL, 1, [Define if terminal support is to be enabled]) +- have_terminal=yes ++ PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 ], [have_terminal=yes]) ++ AS_IF([test "x$have_terminal" != xyes -a "x$enable_terminal" = xyes], ++ [AC_MSG_ERROR([*** terminal support requested but required dependencies not available])], ++ [test "x$have_terminal" = xyes], ++ [AC_DEFINE(ENABLE_TERMINAL, 1, [Define if terminal support is to be enabled])]) + fi + AM_CONDITIONAL(ENABLE_TERMINAL, [test "x$have_terminal" = "xyes"]) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +new file mode 100644 +index 0000000000..c93ede8dc9 +--- /dev/null ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -0,0 +1,938 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 "bus-util.h" ++#include "hashmap.h" ++#include "idev.h" ++#include "idev-internal.h" ++#include "macro.h" ++#include "udev-util.h" ++#include "util.h" ++ ++typedef struct idev_evdev idev_evdev; ++typedef struct unmanaged_evdev unmanaged_evdev; ++typedef struct managed_evdev managed_evdev; ++ ++struct idev_evdev { ++ struct idev_element element; ++ struct libevdev *evdev; ++ int fd; ++ sd_event_source *fd_src; ++ sd_event_source *idle_src; ++ ++ bool unsync : 1; /* not in-sync with kernel */ ++ bool resync : 1; /* re-syncing with kernel */ ++}; ++ ++struct unmanaged_evdev { ++ struct idev_evdev evdev; ++ char *devnode; ++}; ++ ++struct managed_evdev { ++ struct idev_evdev evdev; ++ dev_t devnum; ++ ++ sd_bus_slot *slot_pause_device; ++ sd_bus_slot *slot_resume_device; ++ sd_bus_slot *slot_take_device; ++ ++ bool requested : 1; /* TakeDevice() was sent */ ++ bool acquired : 1; /* TakeDevice() was successful */ ++}; ++ ++#define idev_evdev_from_element(_e) container_of((_e), idev_evdev, element) ++#define unmanaged_evdev_from_element(_e) \ ++ container_of(idev_evdev_from_element(_e), unmanaged_evdev, evdev) ++#define managed_evdev_from_element(_e) \ ++ container_of(idev_evdev_from_element(_e), managed_evdev, evdev) ++ ++#define IDEV_EVDEV_INIT(_vtable, _session) ((idev_evdev){ \ ++ .element = IDEV_ELEMENT_INIT((_vtable), (_session)), \ ++ .fd = -1, \ ++ }) ++ ++#define IDEV_EVDEV_NAME_MAX (8 + DECIMAL_STR_MAX(unsigned) * 2) ++ ++static const idev_element_vtable unmanaged_evdev_vtable; ++static const idev_element_vtable managed_evdev_vtable; ++ ++static int idev_evdev_resume(idev_evdev *evdev, int dev_fd); ++static void idev_evdev_pause(idev_evdev *evdev, bool release); ++ ++/* ++ * Virtual Evdev Element ++ * The virtual evdev element is the base class of all other evdev elements. It ++ * uses libevdev to access the kernel evdev API. It supports asynchronous ++ * access revocation, re-syncing if events got dropped and more. ++ * This element cannot be used by itself. There must be a wrapper around it ++ * which opens a file-descriptor and passes it to the virtual evdev element. ++ */ ++ ++static void idev_evdev_name(char *out, dev_t devnum) { ++ /* @out must be at least of size IDEV_EVDEV_NAME_MAX */ ++ sprintf(out, "evdev/%u:%u", major(devnum), minor(devnum)); ++} ++ ++static int idev_evdev_raise(idev_evdev *evdev, struct input_event *event) { ++ idev_data data = { ++ .type = IDEV_DATA_EVDEV, ++ .resync = evdev->resync, ++ .evdev = { ++ .event = *event, ++ }, ++ }; ++ ++ return idev_element_feed(&evdev->element, &data); ++} ++ ++static void idev_evdev_hup(idev_evdev *evdev) { ++ /* ++ * On HUP, we close the current fd via idev_evdev_pause(). This drops ++ * the event-sources from the main-loop and effectively puts the ++ * element asleep. If the HUP is part of a hotplug-event, a following ++ * udev-notification will destroy the element. Otherwise, the HUP is ++ * either result of access-revokation or a serious error. ++ * For unmanaged devices, we should never receive HUP (except for ++ * unplug-events). But if we do, something went seriously wrong and we ++ * shouldn't try to be clever. ++ * Instead, we simply stay asleep and wait for the device to be ++ * disabled and then re-enabled (or closed and re-opened). This will ++ * re-open the device node and restart the device. ++ * For managed devices, a HUP usually means our device-access was ++ * revoked. In that case, we simply put the device asleep and wait for ++ * logind to notify us once the device is alive again. logind also ++ * passes us a new fd. Hence, we don't have to re-enable the device. ++ * ++ * Long story short: The only thing we have to do here, is close() the ++ * file-descriptor and remove it from the main-loop. Everything else is ++ * handled via additional events we receive. ++ */ ++ ++ idev_evdev_pause(evdev, true); ++} ++ ++static int idev_evdev_io(idev_evdev *evdev) { ++ idev_element *e = &evdev->element; ++ struct input_event ev; ++ unsigned int flags; ++ int r, error = 0; ++ ++ /* ++ * Read input-events via libevdev until the input-queue is drained. In ++ * case we're disabled, don't do anything. The input-queue might ++ * overflow, but we don't care as we have to resync after wake-up, ++ * anyway. ++ * TODO: libevdev should give us a hint how many events to read. We ++ * really want to avoid starvation, so we shouldn't read forever in ++ * case we cannot keep up with the kernel. ++ * TODO: Make sure libevdev always reports SYN_DROPPED to us, regardless ++ * whether any event was synced afterwards. ++ * TODO: Forward SYN_DROPPED to attached devices. ++ */ ++ ++ flags = LIBEVDEV_READ_FLAG_NORMAL; ++ while (e->enabled) { ++ if (evdev->unsync) { ++ /* immediately resync, even if in sync right now */ ++ evdev->unsync = false; ++ evdev->resync = false; ++ flags = LIBEVDEV_READ_FLAG_NORMAL; ++ r = libevdev_next_event(evdev->evdev, flags | LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev); ++ if (r < 0 && r != -EAGAIN) { ++ r = 0; ++ goto error; ++ } else if (r != LIBEVDEV_READ_STATUS_SYNC) { ++ log_debug("idev-evdev: %s/%s: cannot force resync: %d", ++ e->session->name, e->name, r); ++ } ++ } else { ++ r = libevdev_next_event(evdev->evdev, flags, &ev); ++ } ++ ++ if (evdev->resync && r == -EAGAIN) { ++ /* end of re-sync */ ++ evdev->resync = false; ++ flags = LIBEVDEV_READ_FLAG_NORMAL; ++ } else if (r == -EAGAIN) { ++ /* no data available */ ++ break; ++ } else if (r < 0) { ++ /* read error */ ++ goto error; ++ } else if (r == LIBEVDEV_READ_STATUS_SYNC) { ++ if (evdev->resync) { ++ /* sync-event */ ++ r = idev_evdev_raise(evdev, &ev); ++ if (r != 0) { ++ error = r; ++ break; ++ } ++ } else { ++ /* start of sync */ ++ evdev->resync = true; ++ flags = LIBEVDEV_READ_FLAG_SYNC; ++ } ++ } else { ++ /* normal event */ ++ r = idev_evdev_raise(evdev, &ev); ++ if (r != 0) { ++ error = r; ++ break; ++ } ++ } ++ } ++ ++ if (error < 0) ++ log_debug("idev-evdev: %s/%s: error on data event: %s", ++ e->session->name, e->name, strerror(-error)); ++ return error; ++ ++error: ++ idev_evdev_hup(evdev); ++ return r; ++} ++ ++static int idev_evdev_event_fn(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ++ idev_evdev *evdev = userdata; ++ ++ /* fetch data as long as EPOLLIN is signalled */ ++ if (revents & EPOLLIN) ++ return idev_evdev_io(evdev); ++ ++ if (revents & (EPOLLHUP | EPOLLERR)) ++ idev_evdev_hup(evdev); ++ ++ return 0; ++} ++ ++static int idev_evdev_idle_fn(sd_event_source *s, void *userdata) { ++ idev_evdev *evdev = userdata; ++ ++ /* ++ * The idle-event is raised whenever we have to re-sync the libevdev ++ * state from the kernel. We simply call into idev_evdev_io() which ++ * flushes the state and re-syncs it if @unsync is set. ++ * State has to be synced whenever our view of the kernel device is ++ * out of date. This is the case when we open the device, if the ++ * kernel's receive buffer overflows, or on other exceptional ++ * situations. Events during re-syncs must be forwarded to the upper ++ * layers so they can update their view of the device. However, such ++ * events must only be handled passively, as they might be out-of-order ++ * and/or re-ordered. Therefore, we mark them as 'sync' events. ++ */ ++ ++ if (!evdev->unsync) ++ return 0; ++ ++ return idev_evdev_io(evdev); ++} ++ ++static void idev_evdev_destroy(idev_evdev *evdev) { ++ assert(evdev); ++ assert(evdev->fd < 0); ++ ++ libevdev_free(evdev->evdev); ++ evdev->evdev = NULL; ++} ++ ++static void idev_evdev_enable(idev_evdev *evdev) { ++ assert(evdev); ++ assert(evdev->fd_src); ++ assert(evdev->idle_src); ++ ++ sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_ON); ++ sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_ONESHOT); ++} ++ ++static void idev_evdev_disable(idev_evdev *evdev) { ++ assert(evdev); ++ assert(evdev->fd_src); ++ assert(evdev->idle_src); ++ ++ sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); ++ sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); ++} ++ ++static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { ++ idev_element *e = &evdev->element; ++ _cleanup_close_ int fd = dev_fd; ++ int r, flags; ++ ++ if (fd < 0 || evdev->fd == fd) { ++ fd = -1; ++ if (evdev->fd >= 0 && e->n_open > 0 && e->enabled) ++ idev_evdev_enable(evdev); ++ ++ return 0; ++ } ++ ++ idev_evdev_pause(evdev, true); ++ log_debug("idev-evdev: %s/%s: resume", e->session->name, e->name); ++ ++ r = fd_nonblock(fd, true); ++ if (r < 0) ++ return r; ++ ++ r = fd_cloexec(fd, true); ++ if (r < 0) ++ return r; ++ ++ flags = fcntl(fd, F_GETFL, 0); ++ if (flags < 0) ++ return r; ++ ++ flags &= O_ACCMODE; ++ if (flags == O_WRONLY) ++ return -EACCES; ++ ++ evdev->element.readable = true; ++ evdev->element.writable = true; ++ if (flags == O_RDONLY) ++ evdev->element.writable = false; ++ else if (flags == O_WRONLY) ++ evdev->element.readable = false; ++ ++ /* ++ * TODO: We *MUST* re-sync the device so we get a delta of the changed ++ * state while we didn't read events from the device. This works just ++ * fine with libevdev_change_fd(), however, libevdev_new_from_fd() (or ++ * libevdev_set_fd()) don't pass us events for the initial device ++ * state. So even if we force a re-sync, we will not get the delta for ++ * the initial device state. ++ * We really need to fix libevdev to support that! ++ */ ++ if (evdev->evdev) ++ r = libevdev_change_fd(evdev->evdev, fd); ++ else ++ r = libevdev_new_from_fd(fd, &evdev->evdev); ++ ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_io(e->session->context->event, ++ &evdev->fd_src, ++ fd, ++ EPOLLHUP | EPOLLERR | EPOLLIN, ++ idev_evdev_event_fn, ++ evdev); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_defer(e->session->context->event, ++ &evdev->idle_src, ++ idev_evdev_idle_fn, ++ evdev); ++ if (r < 0) { ++ evdev->fd_src = sd_event_source_unref(evdev->fd_src); ++ return r; ++ } ++ ++ if (e->n_open < 1 || !e->enabled) { ++ sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); ++ sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); ++ } ++ ++ evdev->unsync = true; ++ evdev->fd = fd; ++ ++ fd = -1; ++ return 0; ++} ++ ++static void idev_evdev_pause(idev_evdev *evdev, bool release) { ++ idev_element *e = &evdev->element; ++ ++ if (evdev->fd < 0) ++ return; ++ ++ log_debug("idev-evdev: %s/%s: pause", e->session->name, e->name); ++ ++ if (release) { ++ evdev->idle_src = sd_event_source_unref(evdev->idle_src); ++ evdev->fd_src = sd_event_source_unref(evdev->fd_src); ++ evdev->fd = safe_close(evdev->fd); ++ } else { ++ idev_evdev_disable(evdev); ++ } ++} ++ ++/* ++ * Unmanaged Evdev Element ++ * The unmanaged evdev element opens the evdev node for a given input device ++ * directly (/dev/input/eventX) and thus needs sufficient privileges. It opens ++ * the device only if we really require it and releases it as soon as we're ++ * disabled or closed. ++ * The unmanaged element can be used in all situations where you have direct ++ * access to input device nodes. Unlike managed evdev elements, it can be used ++ * outside of user sessions and in emergency situations where logind is not ++ * available. ++ */ ++ ++static void unmanaged_evdev_resume(idev_element *e) { ++ unmanaged_evdev *eu = unmanaged_evdev_from_element(e); ++ int r, fd; ++ ++ /* ++ * Unmanaged devices can be acquired on-demand. Therefore, don't ++ * acquire it unless someone opened the device *and* we're enabled. ++ */ ++ if (e->n_open < 1 || !e->enabled) ++ return; ++ ++ fd = eu->evdev.fd; ++ if (fd < 0) { ++ fd = open(eu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); ++ if (fd < 0) { ++ if (errno != EACCES && errno != EPERM) { ++ log_debug("idev-evdev: %s/%s: cannot open node %s: %m", ++ e->session->name, e->name, eu->devnode); ++ return; ++ } ++ ++ fd = open(eu->devnode, O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); ++ if (fd < 0) { ++ log_debug("idev-evdev: %s/%s: cannot open node %s: %m", ++ e->session->name, e->name, eu->devnode); ++ return; ++ } ++ ++ e->readable = true; ++ e->writable = false; ++ } else { ++ e->readable = true; ++ e->writable = true; ++ } ++ } ++ ++ r = idev_evdev_resume(&eu->evdev, fd); ++ if (r < 0) ++ log_debug("idev-evdev: %s/%s: cannot resume: %s", ++ e->session->name, e->name, strerror(-r)); ++} ++ ++static void unmanaged_evdev_pause(idev_element *e) { ++ unmanaged_evdev *eu = unmanaged_evdev_from_element(e); ++ ++ /* ++ * Release the device if the device is disabled or there is no-one who ++ * opened it. This guarantees we stay only available if we're opened ++ * *and* enabled. ++ */ ++ ++ idev_evdev_pause(&eu->evdev, true); ++} ++ ++static int unmanaged_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) { ++ _cleanup_(idev_element_freep) idev_element *e = NULL; ++ char name[IDEV_EVDEV_NAME_MAX]; ++ unmanaged_evdev *eu; ++ const char *devnode; ++ dev_t devnum; ++ int r; ++ ++ assert_return(s, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ devnode = udev_device_get_devnode(ud); ++ devnum = udev_device_get_devnum(ud); ++ if (!devnode || devnum == 0) ++ return -ENODEV; ++ ++ idev_evdev_name(name, devnum); ++ ++ eu = new0(unmanaged_evdev, 1); ++ if (!eu) ++ return -ENOMEM; ++ ++ e = &eu->evdev.element; ++ eu->evdev = IDEV_EVDEV_INIT(&unmanaged_evdev_vtable, s); ++ ++ eu->devnode = strdup(devnode); ++ if (!eu->devnode) ++ return -ENOMEM; ++ ++ r = idev_element_add(e, name); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = e; ++ e = NULL; ++ return 0; ++} ++ ++static void unmanaged_evdev_free(idev_element *e) { ++ unmanaged_evdev *eu = unmanaged_evdev_from_element(e); ++ ++ idev_evdev_destroy(&eu->evdev); ++ free(eu->devnode); ++ free(eu); ++} ++ ++static const idev_element_vtable unmanaged_evdev_vtable = { ++ .free = unmanaged_evdev_free, ++ .enable = unmanaged_evdev_resume, ++ .disable = unmanaged_evdev_pause, ++ .open = unmanaged_evdev_resume, ++ .close = unmanaged_evdev_pause, ++}; ++ ++/* ++ * Managed Evdev Element ++ * The managed evdev element uses systemd-logind to acquire evdev devices. This ++ * means, we do not open the device node /dev/input/eventX directly. Instead, ++ * logind passes us a file-descriptor whenever our session is activated. Thus, ++ * we don't need access to the device node directly. ++ * Furthermore, whenever the session is put asleep, logind revokes the ++ * file-descriptor so we loose access to the device. ++ * Managed evdev elements should be preferred over unmanaged elements whenever ++ * you run inside a user session with exclusive device access. ++ */ ++ ++static int managed_evdev_take_device_fn(sd_bus *bus, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ managed_evdev *em = userdata; ++ idev_element *e = &em->evdev.element; ++ idev_session *s = e->session; ++ int r, paused, fd; ++ ++ em->slot_take_device = sd_bus_slot_unref(em->slot_take_device); ++ ++ if (sd_bus_message_is_method_error(reply, NULL)) { ++ const sd_bus_error *error = sd_bus_message_get_error(reply); ++ ++ log_debug("idev-evdev: %s/%s: TakeDevice failed: %s: %s", ++ s->name, e->name, error->name, error->message); ++ return 0; ++ } ++ ++ em->acquired = true; ++ ++ r = sd_bus_message_read(reply, "hb", &fd, &paused); ++ if (r < 0) { ++ log_debug("idev-evdev: %s/%s: erroneous TakeDevice reply", s->name, e->name); ++ return 0; ++ } ++ ++ /* If the device is paused, ignore it; we will get the next fd via ++ * ResumeDevice signals. */ ++ if (paused) ++ return 0; ++ ++ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); ++ if (fd < 0) { ++ log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m", s->name, e->name); ++ return 0; ++ } ++ ++ r = idev_evdev_resume(&em->evdev, fd); ++ if (r < 0) ++ log_debug("idev-evdev: %s/%s: cannot resume: %s", ++ s->name, e->name, strerror(-r)); ++ ++ return 0; ++} ++ ++static void managed_evdev_resume(idev_element *e) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ managed_evdev *em = managed_evdev_from_element(e); ++ idev_session *s = e->session; ++ idev_context *c = s->context; ++ int r; ++ ++ /* ++ * Acquiring managed devices is heavy, so do it only once we're ++ * enabled *and* opened by someone. ++ */ ++ if (e->n_open < 1 || !e->enabled) ++ return; ++ ++ /* bail out if already pending */ ++ if (em->requested) ++ return; ++ ++ r = sd_bus_message_new_method_call(c->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ s->path, ++ "org.freedesktop.login1.Session", ++ "TakeDevice"); ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum)); ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_call_async(c->sysbus, ++ &em->slot_take_device, ++ m, ++ managed_evdev_take_device_fn, ++ em, ++ 0); ++ if (r < 0) ++ goto error; ++ ++ em->requested = true; ++ return; ++ ++error: ++ log_debug("idev-evdev: %s/%s: cannot send TakeDevice request: %s", ++ s->name, e->name, strerror(-r)); ++} ++ ++static void managed_evdev_pause(idev_element *e) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ managed_evdev *em = managed_evdev_from_element(e); ++ idev_session *s = e->session; ++ idev_context *c = s->context; ++ int r; ++ ++ /* ++ * Releasing managed devices is heavy. Once acquired, we get ++ * notifications for sleep/wake-up events, so there's no reason to ++ * release it if disabled but opened. However, if a device is closed, ++ * we release it immediately as we don't care for sleep/wake-up events ++ * then (even if we're actually enabled). ++ */ ++ ++ idev_evdev_pause(&em->evdev, false); ++ ++ if (e->n_open > 0 || !em->requested) ++ return; ++ ++ /* ++ * If TakeDevice() is pending or was successful, make sure to ++ * release the device again. We don't care for return-values, ++ * so send it without waiting or callbacks. ++ * If a failed TakeDevice() is pending, but someone else took ++ * the device on the same bus-connection, we might incorrectly ++ * release their device. This is an unlikely race, though. ++ * Furthermore, you really shouldn't have two users of the ++ * controller-API on the same session, on the same devices, *AND* on ++ * the same bus-connection. So we don't care for that race.. ++ */ ++ ++ idev_evdev_pause(&em->evdev, true); ++ em->requested = false; ++ ++ if (!em->acquired && !em->slot_take_device) ++ return; ++ ++ em->slot_take_device = sd_bus_slot_unref(em->slot_take_device); ++ em->acquired = false; ++ ++ r = sd_bus_message_new_method_call(c->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ s->path, ++ "org.freedesktop.login1.Session", ++ "ReleaseDevice"); ++ if (r >= 0) { ++ r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum)); ++ if (r >= 0) ++ r = sd_bus_send(c->sysbus, m, NULL); ++ } ++ ++ if (r < 0 && r != -ENOTCONN) ++ log_debug("idev-evdev: %s/%s: cannot send ReleaseDevice: %s", ++ s->name, e->name, strerror(-r)); ++} ++ ++static int managed_evdev_pause_device_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ managed_evdev *em = userdata; ++ idev_element *e = &em->evdev.element; ++ idev_session *s = e->session; ++ idev_context *c = s->context; ++ uint32_t major, minor; ++ const char *mode; ++ int r; ++ ++ /* ++ * We get PauseDevice() signals from logind whenever a device we ++ * requested was, or is about to be, paused. Arguments are major/minor ++ * number of the device and the mode of the operation. ++ * In case the event is not about our device, we ignore it. Otherwise, ++ * we treat it as asynchronous access-revocation (as if we got HUP on ++ * the device fd). Note that we might have already treated the HUP ++ * event via EPOLLHUP, whichever comes first. ++ * ++ * @mode can be one of the following: ++ * "pause": The device is about to be paused. We must react ++ * immediately and respond with PauseDeviceComplete(). Once ++ * we replied, logind will pause the device. Note that ++ * logind might apply any kind of timeout and force pause ++ * the device if we don't respond in a timely manner. In ++ * this case, we will receive a second PauseDevice event ++ * with @mode set to "force" (or similar). ++ * "force": The device was disabled forecfully by logind. Access is ++ * already revoked. This is just an asynchronous ++ * notification so we can put the device asleep (in case ++ * we didn't already notice the access revocation). ++ * "gone": This is like "force" but is sent if the device was ++ * paused due to a device-removal event. ++ * ++ * We always handle PauseDevice signals as "force" as we properly ++ * support asynchronous access revocation, anyway. But in case logind ++ * sent mode "pause", we also call PauseDeviceComplete() to immediately ++ * acknowledge the request. ++ */ ++ ++ r = sd_bus_message_read(signal, "uus", &major, &minor, &mode); ++ if (r < 0) { ++ log_debug("idev-evdev: %s/%s: erroneous PauseDevice signal", ++ s->name, e->name); ++ return 0; ++ } ++ ++ /* not our device? */ ++ if (makedev(major, minor) != em->devnum) ++ return 0; ++ ++ idev_evdev_pause(&em->evdev, true); ++ ++ if (streq(mode, "pause")) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ ++ /* ++ * Sending PauseDeviceComplete() is racy if logind triggers the ++ * timeout. That is, if we take too long and logind pauses the ++ * device by sending a forced PauseDevice, our ++ * PauseDeviceComplete call will be stray. That's fine, though. ++ * logind ignores such stray calls. Only if logind also sent a ++ * further PauseDevice() signal, it might match our call ++ * incorrectly to the newer PauseDevice(). That's fine, too, as ++ * we handle that event asynchronously, anyway. Therefore, ++ * whatever happens, we're fine. Yay! ++ */ ++ ++ r = sd_bus_message_new_method_call(c->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ s->path, ++ "org.freedesktop.login1.Session", ++ "PauseDeviceComplete"); ++ if (r >= 0) { ++ r = sd_bus_message_append(m, "uu", major, minor); ++ if (r >= 0) ++ r = sd_bus_send(c->sysbus, m, NULL); ++ } ++ ++ if (r < 0) ++ log_debug("idev-evdev: %s/%s: cannot send PauseDeviceComplete: %s", ++ s->name, e->name, strerror(-r)); ++ } ++ ++ return 0; ++} ++ ++static int managed_evdev_resume_device_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ managed_evdev *em = userdata; ++ idev_element *e = &em->evdev.element; ++ idev_session *s = e->session; ++ uint32_t major, minor; ++ int r, fd; ++ ++ /* ++ * We get ResumeDevice signals whenever logind resumed a previously ++ * paused device. The arguments contain the major/minor number of the ++ * related device and a new file-descriptor for the freshly opened ++ * device-node. ++ * If the signal is not about our device, we simply ignore it. ++ * Otherwise, we take the file-descriptor and immediately resume the ++ * device. ++ */ ++ ++ r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd); ++ if (r < 0) { ++ log_debug("idev-evdev: %s/%s: erroneous ResumeDevice signal", ++ s->name, e->name); ++ return 0; ++ } ++ ++ /* not our device? */ ++ if (makedev(major, minor) != em->devnum) ++ return 0; ++ ++ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); ++ if (fd < 0) { ++ log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m", ++ s->name, e->name); ++ return 0; ++ } ++ ++ r = idev_evdev_resume(&em->evdev, fd); ++ if (r < 0) ++ log_debug("idev-evdev: %s/%s: cannot resume: %s", ++ s->name, e->name, strerror(-r)); ++ ++ return 0; ++} ++ ++static int managed_evdev_setup_bus(managed_evdev *em) { ++ idev_element *e = &em->evdev.element; ++ idev_session *s = e->session; ++ idev_context *c = s->context; ++ _cleanup_free_ char *match = NULL; ++ int r; ++ ++ match = strjoin("type='signal'," ++ "sender='org.freedesktop.login1'," ++ "interface='org.freedesktop.login1.Session'," ++ "member='PauseDevice'," ++ "path='", s->path, "'", ++ NULL); ++ if (!match) ++ return -ENOMEM; ++ ++ r = sd_bus_add_match(c->sysbus, ++ &em->slot_pause_device, ++ match, ++ managed_evdev_pause_device_fn, ++ em); ++ if (r < 0) ++ return r; ++ ++ free(match); ++ match = strjoin("type='signal'," ++ "sender='org.freedesktop.login1'," ++ "interface='org.freedesktop.login1.Session'," ++ "member='ResumeDevice'," ++ "path='", s->path, "'", ++ NULL); ++ if (!match) ++ return -ENOMEM; ++ ++ r = sd_bus_add_match(c->sysbus, ++ &em->slot_resume_device, ++ match, ++ managed_evdev_resume_device_fn, ++ em); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) { ++ _cleanup_(idev_element_freep) idev_element *e = NULL; ++ char name[IDEV_EVDEV_NAME_MAX]; ++ managed_evdev *em; ++ dev_t devnum; ++ int r; ++ ++ assert_return(s, -EINVAL); ++ assert_return(s->context->sysbus, -EINVAL); ++ assert_return(s->managed, -EINVAL); ++ assert_return(s->context->sysbus, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ return -ENODEV; ++ ++ idev_evdev_name(name, devnum); ++ ++ em = new0(managed_evdev, 1); ++ if (!em) ++ return -ENOMEM; ++ ++ e = &em->evdev.element; ++ em->evdev = IDEV_EVDEV_INIT(&managed_evdev_vtable, s); ++ em->devnum = devnum; ++ ++ r = managed_evdev_setup_bus(em); ++ if (r < 0) ++ return r; ++ ++ r = idev_element_add(e, name); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = e; ++ e = NULL; ++ return 0; ++} ++ ++static void managed_evdev_free(idev_element *e) { ++ managed_evdev *em = managed_evdev_from_element(e); ++ ++ em->slot_resume_device = sd_bus_slot_unref(em->slot_resume_device); ++ em->slot_pause_device = sd_bus_slot_unref(em->slot_pause_device); ++ idev_evdev_destroy(&em->evdev); ++ free(em); ++} ++ ++static const idev_element_vtable managed_evdev_vtable = { ++ .free = managed_evdev_free, ++ .enable = managed_evdev_resume, ++ .disable = managed_evdev_pause, ++ .open = managed_evdev_resume, ++ .close = managed_evdev_pause, ++}; ++ ++/* ++ * Generic Constructor ++ * Instead of relying on the caller to choose between managed and unmanaged ++ * evdev devices, the idev_evdev_new() constructor does that for you (by ++ * looking at s->managed). ++ */ ++ ++bool idev_is_evdev(idev_element *e) { ++ return e && (e->vtable == &unmanaged_evdev_vtable || ++ e->vtable == &managed_evdev_vtable); ++} ++ ++idev_element *idev_find_evdev(idev_session *s, dev_t devnum) { ++ char name[IDEV_EVDEV_NAME_MAX]; ++ ++ assert_return(s, NULL); ++ assert_return(devnum != 0, NULL); ++ ++ idev_evdev_name(name, devnum); ++ return idev_find_element(s, name); ++} ++ ++int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) { ++ assert_return(s, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ return s->managed ? managed_evdev_new(out, s, ud) : unmanaged_evdev_new(out, s, ud); ++} +diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h +index bffefbb9c1..3301ebf6e4 100644 +--- a/src/libsystemd-terminal/idev-internal.h ++++ b/src/libsystemd-terminal/idev-internal.h +@@ -22,6 +22,8 @@ + #pragma once + + #include ++#include ++#include + #include + #include + #include +@@ -37,6 +39,14 @@ typedef struct idev_element idev_element; + typedef struct idev_element_vtable idev_element_vtable; + + /* ++ * Evdev Elements ++ */ ++ ++bool idev_is_evdev(idev_element *e); ++idev_element *idev_find_evdev(idev_session *s, dev_t devnum); ++int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud); ++ ++/* + * Element Links + */ + +diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c +index 5e3080797a..2316a66529 100644 +--- a/src/libsystemd-terminal/idev.c ++++ b/src/libsystemd-terminal/idev.c +@@ -20,6 +20,8 @@ + ***/ + + #include ++#include ++#include + #include + #include + #include +@@ -31,6 +33,7 @@ + #include "login-shared.h" + #include "macro.h" + #include "set.h" ++#include "udev-util.h" + #include "util.h" + + static void element_open(idev_element *e); +@@ -522,6 +525,51 @@ void idev_session_disable(idev_session *s) { + } + } + ++int idev_session_add_evdev(idev_session *s, struct udev_device *ud) { ++ idev_element *e; ++ dev_t devnum; ++ int r; ++ ++ assert_return(s, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ return 0; ++ ++ e = idev_find_evdev(s, devnum); ++ if (e) ++ return 0; ++ ++ r = idev_evdev_new(&e, s, ud); ++ if (r < 0) ++ return r; ++ ++ r = session_add_element(s, e); ++ if (r != 0) ++ return r; ++ ++ return 0; ++} ++ ++int idev_session_remove_evdev(idev_session *s, struct udev_device *ud) { ++ idev_element *e; ++ dev_t devnum; ++ ++ assert(s); ++ assert(ud); ++ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ return 0; ++ ++ e = idev_find_evdev(s, devnum); ++ if (!e) ++ return 0; ++ ++ return session_remove_element(s, e); ++} ++ + /* + * Contexts + */ +diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h +index 6f618f37af..c98fb1bfb0 100644 +--- a/src/libsystemd-terminal/idev.h ++++ b/src/libsystemd-terminal/idev.h +@@ -26,6 +26,8 @@ + #pragma once + + #include ++#include ++#include + #include + #include + #include +@@ -33,6 +35,7 @@ + #include "util.h" + + typedef struct idev_data idev_data; ++typedef struct idev_data_evdev idev_data_evdev; + + typedef struct idev_event idev_event; + typedef struct idev_device idev_device; +@@ -44,6 +47,7 @@ typedef struct idev_context idev_context; + */ + + enum { ++ IDEV_ELEMENT_EVDEV, + IDEV_ELEMENT_CNT + }; + +@@ -52,17 +56,30 @@ enum { + }; + + /* ++ * Evdev Elements ++ */ ++ ++struct idev_data_evdev { ++ struct input_event event; ++}; ++ ++/* + * Data Packets + */ + + enum { + IDEV_DATA_RESYNC, ++ IDEV_DATA_EVDEV, + IDEV_DATA_CNT + }; + + struct idev_data { + unsigned int type; + bool resync : 1; ++ ++ union { ++ idev_data_evdev evdev; ++ }; + }; + + /* +@@ -122,6 +139,9 @@ bool idev_session_is_enabled(idev_session *s); + void idev_session_enable(idev_session *s); + void idev_session_disable(idev_session *s); + ++int idev_session_add_evdev(idev_session *s, struct udev_device *ud); ++int idev_session_remove_evdev(idev_session *s, struct udev_device *ud); ++ + /* + * Contexts + */ diff --git a/0084-terminal-add-xkb-based-keyboard-devices-to-idev.patch b/0084-terminal-add-xkb-based-keyboard-devices-to-idev.patch new file mode 100644 index 0000000..b5f7f61 --- /dev/null +++ b/0084-terminal-add-xkb-based-keyboard-devices-to-idev.patch @@ -0,0 +1,1107 @@ +From e06cc7b07465369fb7c01c9778b84cf82c82fdcf Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 27 Aug 2014 18:34:55 +0200 +Subject: [PATCH] terminal: add xkb-based keyboard devices to idev + +The idev-keyboard object provides keyboard devices to the idev interface. +It uses libxkbcommon to provide proper keymap support. + +So far, the keyboard implementation is pretty straightforward with one +keyboard device per matching evdev element. We feed everything into the +system keymap and provide proper high-level keyboard events to the +application. Compose-features and IM need to be added later. +--- + Makefile.am | 1 + + configure.ac | 2 +- + src/libsystemd-terminal/idev-internal.h | 9 + + src/libsystemd-terminal/idev-keyboard.c | 846 ++++++++++++++++++++++++++++++++ + src/libsystemd-terminal/idev.c | 62 ++- + src/libsystemd-terminal/idev.h | 49 ++ + 6 files changed, 966 insertions(+), 3 deletions(-) + create mode 100644 src/libsystemd-terminal/idev-keyboard.c + +diff --git a/Makefile.am b/Makefile.am +index b51c522443..35a4c44a9f 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2976,6 +2976,7 @@ libsystemd_terminal_la_SOURCES = \ + src/libsystemd-terminal/idev-internal.h \ + src/libsystemd-terminal/idev.c \ + src/libsystemd-terminal/idev-evdev.c \ ++ src/libsystemd-terminal/idev-keyboard.c \ + src/libsystemd-terminal/sysview.h \ + src/libsystemd-terminal/sysview-internal.h \ + src/libsystemd-terminal/sysview.c \ +diff --git a/configure.ac b/configure.ac +index 3900c4065b..a25ad3f2e2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1066,7 +1066,7 @@ AM_CONDITIONAL(ENABLE_MULTI_SEAT_X, [test "$have_multi_seat_x" = "yes"]) + have_terminal=no + AC_ARG_ENABLE(terminal, AS_HELP_STRING([--enable-terminal], [enable terminal support])) + if test "x$enable_terminal" = "xyes"; then +- PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 ], [have_terminal=yes]) ++ PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 xkbcommon >= 0.4 ], [have_terminal=yes]) + AS_IF([test "x$have_terminal" != xyes -a "x$enable_terminal" = xyes], + [AC_MSG_ERROR([*** terminal support requested but required dependencies not available])], + [test "x$have_terminal" = xyes], +diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h +index 3301ebf6e4..c416f4fadd 100644 +--- a/src/libsystemd-terminal/idev-internal.h ++++ b/src/libsystemd-terminal/idev-internal.h +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include "hashmap.h" + #include "idev.h" + #include "list.h" +@@ -47,6 +48,14 @@ idev_element *idev_find_evdev(idev_session *s, dev_t devnum); + int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud); + + /* ++ * Keyboard Devices ++ */ ++ ++bool idev_is_keyboard(idev_device *d); ++idev_device *idev_find_keyboard(idev_session *s, const char *name); ++int idev_keyboard_new(idev_device **out, idev_session *s, const char *name); ++ ++/* + * Element Links + */ + +diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c +new file mode 100644 +index 0000000000..647aade932 +--- /dev/null ++++ b/src/libsystemd-terminal/idev-keyboard.c +@@ -0,0 +1,846 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 "bus-util.h" ++#include "hashmap.h" ++#include "idev.h" ++#include "idev-internal.h" ++#include "macro.h" ++#include "util.h" ++ ++typedef struct kbdmap kbdmap; ++typedef struct kbdctx kbdctx; ++typedef struct idev_keyboard idev_keyboard; ++ ++struct kbdmap { ++ unsigned long ref; ++ struct xkb_keymap *xkb_keymap; ++ xkb_mod_index_t modmap[IDEV_KBDMOD_CNT]; ++ xkb_led_index_t ledmap[IDEV_KBDLED_CNT]; ++}; ++ ++struct kbdctx { ++ unsigned long ref; ++ idev_context *context; ++ struct xkb_context *xkb_context; ++ struct kbdmap *kbdmap; ++ ++ sd_bus_slot *slot_locale_props_changed; ++ sd_bus_slot *slot_locale_get_all; ++ ++ char *locale_x11_model; ++ char *locale_x11_layout; ++ char *locale_x11_variant; ++ char *locale_x11_options; ++ char *last_x11_model; ++ char *last_x11_layout; ++ char *last_x11_variant; ++ char *last_x11_options; ++}; ++ ++struct idev_keyboard { ++ idev_device device; ++ kbdctx *kbdctx; ++ kbdmap *kbdmap; ++ ++ struct xkb_state *xkb_state; ++ ++ usec_t repeat_delay; ++ usec_t repeat_rate; ++ sd_event_source *repeat_timer; ++ ++ uint32_t n_syms; ++ idev_data evdata; ++ idev_data repdata; ++ ++ bool repeating : 1; ++}; ++ ++#define keyboard_from_device(_d) container_of((_d), idev_keyboard, device) ++ ++#define KBDCTX_KEY "keyboard.context" /* hashmap key for global kbdctx */ ++#define KBDXKB_SHIFT (8) /* xkb shifts evdev key-codes by 8 */ ++#define KBDKEY_UP (0) /* KEY UP event value */ ++#define KBDKEY_DOWN (1) /* KEY DOWN event value */ ++#define KBDKEY_REPEAT (2) /* KEY REPEAT event value */ ++ ++static const idev_device_vtable keyboard_vtable; ++ ++static int keyboard_update_kbdmap(idev_keyboard *k); ++ ++/* ++ * Keyboard Keymaps ++ */ ++ ++static const char * const kbdmap_modmap[IDEV_KBDMOD_CNT] = { ++ [IDEV_KBDMOD_IDX_SHIFT] = XKB_MOD_NAME_SHIFT, ++ [IDEV_KBDMOD_IDX_CTRL] = XKB_MOD_NAME_CTRL, ++ [IDEV_KBDMOD_IDX_ALT] = XKB_MOD_NAME_ALT, ++ [IDEV_KBDMOD_IDX_LINUX] = XKB_MOD_NAME_LOGO, ++ [IDEV_KBDMOD_IDX_CAPS] = XKB_MOD_NAME_CAPS, ++}; ++ ++static const char * const kbdmap_ledmap[IDEV_KBDLED_CNT] = { ++ [IDEV_KBDLED_IDX_NUM] = XKB_LED_NAME_NUM, ++ [IDEV_KBDLED_IDX_CAPS] = XKB_LED_NAME_CAPS, ++ [IDEV_KBDLED_IDX_SCROLL] = XKB_LED_NAME_SCROLL, ++}; ++ ++static kbdmap *kbdmap_ref(kbdmap *km) { ++ assert_return(km, NULL); ++ assert_return(km->ref > 0, NULL); ++ ++ ++km->ref; ++ return km; ++} ++ ++static kbdmap *kbdmap_unref(kbdmap *km) { ++ if (!km) ++ return NULL; ++ ++ assert_return(km->ref > 0, NULL); ++ ++ if (--km->ref > 0) ++ return NULL; ++ ++ xkb_keymap_unref(km->xkb_keymap); ++ free(km); ++ ++ return 0; ++} ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(kbdmap*, kbdmap_unref); ++ ++static int kbdmap_new_from_names(kbdmap **out, ++ kbdctx *kc, ++ const char *model, ++ const char *layout, ++ const char *variant, ++ const char *options) { ++ _cleanup_(kbdmap_unrefp) kbdmap *km = NULL; ++ struct xkb_rule_names rmlvo = { }; ++ unsigned int i; ++ ++ assert_return(out, -EINVAL); ++ ++ km = new0(kbdmap, 1); ++ if (!km) ++ return -ENOMEM; ++ ++ km->ref = 1; ++ ++ rmlvo.rules = "evdev"; ++ rmlvo.model = model; ++ rmlvo.layout = layout; ++ rmlvo.variant = variant; ++ rmlvo.options = options; ++ ++ errno = 0; ++ km->xkb_keymap = xkb_keymap_new_from_names(kc->xkb_context, &rmlvo, 0); ++ if (!km->xkb_keymap) ++ return errno > 0 ? -errno : -EFAULT; ++ ++ for (i = 0; i < IDEV_KBDMOD_CNT; ++i) { ++ const char *t = kbdmap_modmap[i]; ++ ++ if (t) ++ km->modmap[i] = xkb_keymap_mod_get_index(km->xkb_keymap, t); ++ else ++ km->modmap[i] = XKB_MOD_INVALID; ++ } ++ ++ for (i = 0; i < IDEV_KBDLED_CNT; ++i) { ++ const char *t = kbdmap_ledmap[i]; ++ ++ if (t) ++ km->ledmap[i] = xkb_keymap_led_get_index(km->xkb_keymap, t); ++ else ++ km->ledmap[i] = XKB_LED_INVALID; ++ } ++ ++ *out = km; ++ km = NULL; ++ return 0; ++} ++ ++/* ++ * Keyboard Context ++ */ ++ ++static void move_str(char **dest, char **src) { ++ free(*dest); ++ *dest = *src; ++ *src = NULL; ++} ++ ++static int kbdctx_refresh_keymap(kbdctx *kc) { ++ idev_session *s; ++ idev_device *d; ++ Iterator i, j; ++ kbdmap *km; ++ int r; ++ ++ if (kc->kbdmap && ++ streq_ptr(kc->locale_x11_model, kc->last_x11_model) && ++ streq_ptr(kc->locale_x11_layout, kc->last_x11_layout) && ++ streq_ptr(kc->locale_x11_variant, kc->last_x11_variant) && ++ streq_ptr(kc->locale_x11_options, kc->last_x11_options)) ++ return 0 ; ++ ++ move_str(&kc->last_x11_model, &kc->locale_x11_model); ++ move_str(&kc->last_x11_layout, &kc->locale_x11_layout); ++ move_str(&kc->last_x11_variant, &kc->locale_x11_variant); ++ move_str(&kc->last_x11_options, &kc->locale_x11_options); ++ ++ log_debug("idev-keyboard: new default keymap: [%s / %s / %s / %s]", ++ kc->last_x11_model, kc->last_x11_layout, kc->last_x11_variant, kc->last_x11_options); ++ ++ /* TODO: add a fallback keymap that's compiled-in */ ++ r = kbdmap_new_from_names(&km, kc, kc->last_x11_model, kc->last_x11_layout, ++ kc->last_x11_variant, kc->last_x11_options); ++ if (r < 0) { ++ log_debug("idev-keyboard: cannot create keymap from locale1: %s", ++ strerror(-r)); ++ return r; ++ } ++ ++ kbdmap_unref(kc->kbdmap); ++ kc->kbdmap = km; ++ ++ HASHMAP_FOREACH(s, kc->context->session_map, i) ++ HASHMAP_FOREACH(d, s->device_map, j) ++ if (idev_is_keyboard(d)) ++ keyboard_update_kbdmap(keyboard_from_device(d)); ++ ++ return 0; ++} ++ ++static const struct bus_properties_map kbdctx_locale_map[] = { ++ { "X11Model", "s", NULL, offsetof(kbdctx, locale_x11_model) }, ++ { "X11Layout", "s", NULL, offsetof(kbdctx, locale_x11_layout) }, ++ { "X11Variant", "s", NULL, offsetof(kbdctx, locale_x11_variant) }, ++ { "X11Options", "s", NULL, offsetof(kbdctx, locale_x11_options) }, ++}; ++ ++static int kbdctx_locale_get_all_fn(sd_bus *bus, ++ sd_bus_message *m, ++ void *userdata, ++ sd_bus_error *ret_err) { ++ kbdctx *kc = userdata; ++ int r; ++ ++ kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all); ++ ++ if (sd_bus_message_is_method_error(m, NULL)) { ++ const sd_bus_error *error = sd_bus_message_get_error(m); ++ ++ log_debug("idev-keyboard: GetAll() on locale1 failed: %s: %s", ++ error->name, error->message); ++ return 0; ++ } ++ ++ r = bus_message_map_all_properties(bus, m, kbdctx_locale_map, kc); ++ if (r < 0) { ++ log_debug("idev-keyboard: erroneous GetAll() reply from locale1"); ++ return 0; ++ } ++ ++ kbdctx_refresh_keymap(kc); ++ return 0; ++} ++ ++static int kbdctx_query_locale(kbdctx *kc) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ int r; ++ ++ kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all); ++ ++ r = sd_bus_message_new_method_call(kc->context->sysbus, ++ &m, ++ "org.freedesktop.locale1", ++ "/org/freedesktop/locale1", ++ "org.freedesktop.DBus.Properties", ++ "GetAll"); ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_message_append(m, "s", "org.freedesktop.locale1"); ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_call_async(kc->context->sysbus, ++ &kc->slot_locale_get_all, ++ m, ++ kbdctx_locale_get_all_fn, ++ kc, ++ 0); ++ if (r < 0) ++ goto error; ++ ++ return 0; ++ ++error: ++ log_debug("idev-keyboard: cannot send GetAll to locale1: %s", strerror(-r)); ++ return r; ++} ++ ++static int kbdctx_locale_props_changed_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_err) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ kbdctx *kc = userdata; ++ int r; ++ ++ kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all); ++ ++ r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc); ++ if (r < 0) { ++ log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r)); ++ return r; ++ } ++ ++ if (r > 0) { ++ r = kbdctx_query_locale(kc); ++ if (r < 0) ++ return r; ++ } ++ ++ kbdctx_refresh_keymap(kc); ++ return 0; ++} ++ ++static int kbdctx_setup_bus(kbdctx *kc) { ++ int r; ++ ++ r = sd_bus_add_match(kc->context->sysbus, ++ &kc->slot_locale_props_changed, ++ "type='signal'," ++ "sender='org.freedesktop.locale1'," ++ "interface='org.freedesktop.DBus.Properties'," ++ "member='PropertiesChanged'," ++ "path='/org/freedesktop/locale1'", ++ kbdctx_locale_props_changed_fn, ++ kc); ++ if (r < 0) { ++ log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r)); ++ return r; ++ } ++ ++ return kbdctx_query_locale(kc); ++} ++ ++static kbdctx *kbdctx_ref(kbdctx *kc) { ++ assert_return(kc, NULL); ++ assert_return(kc->ref > 0, NULL); ++ ++ ++kc->ref; ++ return kc; ++} ++ ++static kbdctx *kbdctx_unref(kbdctx *kc) { ++ if (!kc) ++ return NULL; ++ ++ assert_return(kc->ref > 0, NULL); ++ ++ if (--kc->ref > 0) ++ return NULL; ++ ++ free(kc->last_x11_options); ++ free(kc->last_x11_variant); ++ free(kc->last_x11_layout); ++ free(kc->last_x11_model); ++ free(kc->locale_x11_options); ++ free(kc->locale_x11_variant); ++ free(kc->locale_x11_layout); ++ free(kc->locale_x11_model); ++ kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all); ++ kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed); ++ kc->kbdmap = kbdmap_unref(kc->kbdmap); ++ xkb_context_unref(kc->xkb_context); ++ hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc); ++ free(kc); ++ ++ return NULL; ++} ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref); ++ ++static int kbdctx_new(kbdctx **out, idev_context *c) { ++ _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL; ++ int r; ++ ++ assert_return(out, -EINVAL); ++ assert_return(c, -EINVAL); ++ ++ kc = new0(kbdctx, 1); ++ if (!kc) ++ return -ENOMEM; ++ ++ kc->ref = 1; ++ kc->context = c; ++ ++ errno = 0; ++ kc->xkb_context = xkb_context_new(0); ++ if (!kc->xkb_context) ++ return errno > 0 ? -errno : -EFAULT; ++ ++ r = kbdctx_refresh_keymap(kc); ++ if (r < 0) ++ return r; ++ ++ if (c->sysbus) { ++ r = kbdctx_setup_bus(kc); ++ if (r < 0) ++ return r; ++ } ++ ++ r = hashmap_put(c->data_map, KBDCTX_KEY, kc); ++ if (r < 0) ++ return r; ++ ++ *out = kc; ++ kc = NULL; ++ return 0; ++} ++ ++static int get_kbdctx(idev_context *c, kbdctx **out) { ++ kbdctx *kc; ++ ++ assert_return(c, -EINVAL); ++ assert_return(out, -EINVAL); ++ ++ kc = hashmap_get(c->data_map, KBDCTX_KEY); ++ if (kc) { ++ *out = kbdctx_ref(kc); ++ return 0; ++ } ++ ++ return kbdctx_new(out, c); ++} ++ ++/* ++ * Keyboard Devices ++ */ ++ ++bool idev_is_keyboard(idev_device *d) { ++ return d && d->vtable == &keyboard_vtable; ++} ++ ++idev_device *idev_find_keyboard(idev_session *s, const char *name) { ++ char *kname; ++ ++ assert_return(s, NULL); ++ assert_return(name, NULL); ++ ++ kname = strappenda("keyboard/", name); ++ return hashmap_get(s->device_map, kname); ++} ++ ++static int keyboard_raise_data(idev_keyboard *k, idev_data *data) { ++ idev_device *d = &k->device; ++ int r; ++ ++ r = idev_session_raise_device_data(d->session, d, data); ++ if (r < 0) ++ log_debug("idev-keyboard: %s/%s: error while raising data event: %s", ++ d->session->name, d->name, strerror(-r)); ++ ++ return r; ++} ++ ++static void keyboard_arm(idev_keyboard *k, usec_t usecs) { ++ int r; ++ ++ if (usecs != 0) { ++ usecs += now(CLOCK_MONOTONIC); ++ r = sd_event_source_set_time(k->repeat_timer, usecs); ++ if (r >= 0) ++ sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT); ++ } else { ++ sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF); ++ } ++} ++ ++static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) { ++ idev_keyboard *k = userdata; ++ ++ keyboard_arm(k, k->repeat_rate); ++ return keyboard_raise_data(k, &k->repdata); ++} ++ ++int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) { ++ _cleanup_(idev_device_freep) idev_device *d = NULL; ++ idev_keyboard *k; ++ char *kname; ++ int r; ++ ++ assert_return(out, -EINVAL); ++ assert_return(s, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ k = new0(idev_keyboard, 1); ++ if (!k) ++ return -ENOMEM; ++ ++ d = &k->device; ++ k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s); ++ k->repeat_delay = 250 * USEC_PER_MSEC; ++ k->repeat_rate = 30 * USEC_PER_MSEC; ++ ++ /* TODO: add key-repeat configuration */ ++ ++ r = get_kbdctx(s->context, &k->kbdctx); ++ if (r < 0) ++ return r; ++ ++ r = keyboard_update_kbdmap(k); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_time(s->context->event, ++ &k->repeat_timer, ++ CLOCK_MONOTONIC, ++ 0, ++ 10 * USEC_PER_MSEC, ++ keyboard_repeat_timer_fn, ++ k); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF); ++ if (r < 0) ++ return r; ++ ++ kname = strappenda("keyboard/", name); ++ r = idev_device_add(d, kname); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = d; ++ d = NULL; ++ return 0; ++} ++ ++static void keyboard_free(idev_device *d) { ++ idev_keyboard *k = keyboard_from_device(d); ++ ++ free(k->repdata.keyboard.codepoints); ++ free(k->repdata.keyboard.keysyms); ++ free(k->evdata.keyboard.codepoints); ++ free(k->evdata.keyboard.keysyms); ++ k->repeat_timer = sd_event_source_unref(k->repeat_timer); ++ k->kbdmap = kbdmap_unref(k->kbdmap); ++ k->kbdctx = kbdctx_unref(k->kbdctx); ++ free(k); ++} ++ ++static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) { ++ xkb_layout_index_t n_lo, lo; ++ xkb_level_index_t lv; ++ struct xkb_keymap *keymap; ++ const xkb_keysym_t *s; ++ int num; ++ ++ if (n_syms == 1 && syms[0] < 128) ++ return syms[0]; ++ ++ keymap = xkb_state_get_keymap(state); ++ n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT); ++ ++ for (lo = 0; lo < n_lo; ++lo) { ++ lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo); ++ num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s); ++ if (num == 1 && s[0] < 128) ++ return s[0]; ++ } ++ ++ return -1; ++} ++ ++static int keyboard_fill(idev_keyboard *k, ++ idev_data *dst, ++ bool resync, ++ uint16_t code, ++ uint32_t value, ++ uint32_t n_syms, ++ const uint32_t *keysyms) { ++ idev_data_keyboard *kev; ++ uint32_t i; ++ ++ assert(dst == &k->evdata || dst == &k->repdata); ++ ++ if (n_syms > k->n_syms) { ++ uint32_t *t; ++ ++ t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms); ++ if (!t) ++ return -ENOMEM; ++ k->evdata.keyboard.keysyms = t; ++ ++ t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms); ++ if (!t) ++ return -ENOMEM; ++ k->evdata.keyboard.codepoints = t; ++ ++ t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms); ++ if (!t) ++ return -ENOMEM; ++ k->repdata.keyboard.keysyms = t; ++ ++ t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms); ++ if (!t) ++ return -ENOMEM; ++ k->repdata.keyboard.codepoints = t; ++ ++ k->n_syms = n_syms; ++ } ++ ++ dst->type = IDEV_DATA_KEYBOARD; ++ dst->resync = resync; ++ kev = &dst->keyboard; ++ kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms); ++ kev->value = value; ++ kev->keycode = code; ++ kev->mods = 0; ++ kev->consumed_mods = 0; ++ kev->n_syms = n_syms; ++ memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms); ++ ++ for (i = 0; i < n_syms; ++i) { ++ kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]); ++ if (!kev->codepoints[i]) ++ kev->codepoints[i] = 0xffffffffUL; ++ } ++ ++ for (i = 0; i < IDEV_KBDMOD_CNT; ++i) { ++ int r; ++ ++ if (k->kbdmap->modmap[i] == XKB_MOD_INVALID) ++ continue; ++ ++ r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE); ++ if (r > 0) ++ kev->mods |= 1 << i; ++ ++ r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]); ++ if (r > 0) ++ kev->consumed_mods |= 1 << i; ++ } ++ ++ return 0; ++} ++ ++static void keyboard_repeat(idev_keyboard *k) { ++ idev_data *evdata = &k->evdata; ++ idev_data *repdata = &k->repdata; ++ idev_data_keyboard *evkbd = &evdata->keyboard; ++ idev_data_keyboard *repkbd = &repdata->keyboard; ++ const xkb_keysym_t *keysyms; ++ idev_device *d = &k->device; ++ bool repeats; ++ int r, num; ++ ++ if (evdata->resync) { ++ /* ++ * We received a re-sync event. During re-sync, any number of ++ * key-events may have been lost and sync-events may be ++ * re-ordered. Always disable key-repeat for those events. Any ++ * following event will trigger it again. ++ */ ++ ++ k->repeating = false; ++ keyboard_arm(k, 0); ++ return; ++ } ++ ++ repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT); ++ ++ if (k->repeating && repkbd->keycode == evkbd->keycode) { ++ /* ++ * We received an event for the key we currently repeat. If it ++ * was released, stop key-repeat. Otherwise, ignore the event. ++ */ ++ ++ if (evkbd->value == KBDKEY_UP) { ++ k->repeating = false; ++ keyboard_arm(k, 0); ++ } ++ } else if (evkbd->value == KBDKEY_DOWN && repeats) { ++ /* ++ * We received a key-down event for a key that repeats. The ++ * previous condition caught keys we already repeat, so we know ++ * this is a different key or no key-repeat is running. Start ++ * new key-repeat. ++ */ ++ ++ errno = 0; ++ num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms); ++ if (num < 0) ++ r = errno > 0 ? errno : -EFAULT; ++ else ++ r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms); ++ ++ if (r < 0) { ++ log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s", ++ d->session->name, d->name, strerror(-r)); ++ k->repeating = false; ++ keyboard_arm(k, 0); ++ } else { ++ k->repeating = true; ++ keyboard_arm(k, k->repeat_delay); ++ } ++ } else if (k->repeating && !repeats) { ++ /* ++ * We received an event for a key that does not repeat, but we ++ * currently repeat a previously received key. The new key is ++ * usually a modifier, but might be any kind of key. In this ++ * case, we continue repeating the old key, but update the ++ * symbols according to the new state. ++ */ ++ ++ errno = 0; ++ num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms); ++ if (num < 0) ++ r = errno > 0 ? errno : -EFAULT; ++ else ++ r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms); ++ ++ if (r < 0) { ++ log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s", ++ d->session->name, d->name, strerror(-r)); ++ k->repeating = false; ++ keyboard_arm(k, 0); ++ } ++ } ++} ++ ++static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) { ++ struct input_event *ev = &data->evdev.event; ++ enum xkb_state_component compch; ++ const xkb_keysym_t *keysyms; ++ idev_device *d = &k->device; ++ int num, r; ++ ++ if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN) ++ return 0; ++ ++ /* TODO: We should audit xkb-actions, whether they need @resync as ++ * flag. Most actions should just be executed, however, there might ++ * be actions that depend on modifier-orders. Those should be ++ * suppressed. */ ++ ++ num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms); ++ compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value); ++ ++ if (compch & XKB_STATE_LEDS) { ++ /* TODO: update LEDs */ ++ } ++ ++ if (num < 0) ++ goto error; ++ ++ r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms); ++ if (r < 0) ++ goto error; ++ ++ keyboard_repeat(k); ++ return keyboard_raise_data(k, &k->evdata); ++ ++error: ++ log_debug("idev-keyboard: %s/%s: cannot handle event: %s", ++ d->session->name, d->name, strerror(-r)); ++ k->repeating = false; ++ keyboard_arm(k, 0); ++ return 0; ++} ++ ++static int keyboard_feed(idev_device *d, idev_data *data) { ++ idev_keyboard *k = keyboard_from_device(d); ++ ++ switch (data->type) { ++ case IDEV_DATA_RESYNC: ++ /* ++ * If the underlying device is re-synced, key-events might be ++ * sent re-ordered. Thus, we don't know which key was pressed ++ * last. Key-repeat might get confused, hence, disable it ++ * during re-syncs. The first following event will enable it ++ * again. ++ */ ++ ++ k->repeating = false; ++ keyboard_arm(k, 0); ++ return 0; ++ case IDEV_DATA_EVDEV: ++ return keyboard_feed_evdev(k, data); ++ default: ++ return 0; ++ } ++} ++ ++static int keyboard_update_kbdmap(idev_keyboard *k) { ++ idev_device *d = &k->device; ++ struct xkb_state *state; ++ kbdmap *km; ++ int r; ++ ++ assert(k); ++ ++ km = k->kbdctx->kbdmap; ++ if (km == k->kbdmap) ++ return 0; ++ ++ errno = 0; ++ state = xkb_state_new(km->xkb_keymap); ++ if (!state) { ++ r = errno > 0 ? -errno : -EFAULT; ++ goto error; ++ } ++ ++ kbdmap_unref(k->kbdmap); ++ k->kbdmap = kbdmap_ref(km); ++ xkb_state_unref(k->xkb_state); ++ k->xkb_state = state; ++ ++ /* TODO: On state-change, we should trigger a resync so the whole ++ * event-state is flushed into the new xkb-state. libevdev currently ++ * does not support that, though. */ ++ ++ return 0; ++ ++error: ++ log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s", ++ d->session->name, d->name, strerror(-r)); ++ return r; ++} ++ ++static const idev_device_vtable keyboard_vtable = { ++ .free = keyboard_free, ++ .feed = keyboard_feed, ++}; +diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c +index 2316a66529..0ed518cded 100644 +--- a/src/libsystemd-terminal/idev.c ++++ b/src/libsystemd-terminal/idev.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include "hashmap.h" + #include "idev.h" + #include "idev-internal.h" +@@ -525,10 +526,40 @@ void idev_session_disable(idev_session *s) { + } + } + ++static int add_link(idev_element *e, idev_device *d) { ++ idev_link *l; ++ ++ assert(e); ++ assert(d); ++ ++ l = new0(idev_link, 1); ++ if (!l) ++ return -ENOMEM; ++ ++ l->element = e; ++ l->device = d; ++ LIST_PREPEND(links_by_element, e->links, l); ++ LIST_PREPEND(links_by_device, d->links, l); ++ device_attach(d, l); ++ ++ return 0; ++} ++ ++static int guess_type(struct udev_device *d) { ++ const char *id_key; ++ ++ id_key = udev_device_get_property_value(d, "ID_INPUT_KEY"); ++ if (streq_ptr(id_key, "1")) ++ return IDEV_DEVICE_KEYBOARD; ++ ++ return IDEV_DEVICE_CNT; ++} ++ + int idev_session_add_evdev(idev_session *s, struct udev_device *ud) { + idev_element *e; ++ idev_device *d; + dev_t devnum; +- int r; ++ int r, type; + + assert_return(s, -EINVAL); + assert_return(ud, -EINVAL); +@@ -549,7 +580,34 @@ int idev_session_add_evdev(idev_session *s, struct udev_device *ud) { + if (r != 0) + return r; + +- return 0; ++ type = guess_type(ud); ++ if (type < 0) ++ return type; ++ ++ switch (type) { ++ case IDEV_DEVICE_KEYBOARD: ++ d = idev_find_keyboard(s, e->name); ++ if (d) { ++ log_debug("idev: %s: keyboard for new evdev element '%s' already available", ++ s->name, e->name); ++ return 0; ++ } ++ ++ r = idev_keyboard_new(&d, s, e->name); ++ if (r < 0) ++ return r; ++ ++ r = add_link(e, d); ++ if (r < 0) { ++ idev_device_free(d); ++ return r; ++ } ++ ++ return session_add_device(s, d); ++ default: ++ /* unknown elements are silently ignored */ ++ return 0; ++ } + } + + int idev_session_remove_evdev(idev_session *s, struct udev_device *ud) { +diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h +index c98fb1bfb0..0ae044cfd5 100644 +--- a/src/libsystemd-terminal/idev.h ++++ b/src/libsystemd-terminal/idev.h +@@ -32,10 +32,12 @@ + #include + #include + #include ++#include + #include "util.h" + + typedef struct idev_data idev_data; + typedef struct idev_data_evdev idev_data_evdev; ++typedef struct idev_data_keyboard idev_data_keyboard; + + typedef struct idev_event idev_event; + typedef struct idev_device idev_device; +@@ -52,6 +54,7 @@ enum { + }; + + enum { ++ IDEV_DEVICE_KEYBOARD, + IDEV_DEVICE_CNT + }; + +@@ -64,12 +67,57 @@ struct idev_data_evdev { + }; + + /* ++ * Keyboard Devices ++ */ ++ ++struct xkb_state; ++ ++enum { ++ IDEV_KBDMOD_IDX_SHIFT, ++ IDEV_KBDMOD_IDX_CTRL, ++ IDEV_KBDMOD_IDX_ALT, ++ IDEV_KBDMOD_IDX_LINUX, ++ IDEV_KBDMOD_IDX_CAPS, ++ IDEV_KBDMOD_CNT, ++ ++ IDEV_KBDMOD_SHIFT = 1 << IDEV_KBDMOD_IDX_SHIFT, ++ IDEV_KBDMOD_CTRL = 1 << IDEV_KBDMOD_IDX_CTRL, ++ IDEV_KBDMOD_ALT = 1 << IDEV_KBDMOD_IDX_ALT, ++ IDEV_KBDMOD_LINUX = 1 << IDEV_KBDMOD_IDX_LINUX, ++ IDEV_KBDMOD_CAPS = 1 << IDEV_KBDMOD_IDX_CAPS, ++}; ++ ++enum { ++ IDEV_KBDLED_IDX_NUM, ++ IDEV_KBDLED_IDX_CAPS, ++ IDEV_KBDLED_IDX_SCROLL, ++ IDEV_KBDLED_CNT, ++ ++ IDEV_KBDLED_NUM = 1 << IDEV_KBDLED_IDX_NUM, ++ IDEV_KBDLED_CAPS = 1 << IDEV_KBDLED_IDX_CAPS, ++ IDEV_KBDLED_SCROLL = 1 << IDEV_KBDLED_IDX_SCROLL, ++}; ++ ++struct idev_data_keyboard { ++ struct xkb_state *xkb_state; ++ int8_t ascii; ++ uint8_t value; ++ uint16_t keycode; ++ uint32_t mods; ++ uint32_t consumed_mods; ++ uint32_t n_syms; ++ uint32_t *keysyms; ++ uint32_t *codepoints; ++}; ++ ++/* + * Data Packets + */ + + enum { + IDEV_DATA_RESYNC, + IDEV_DATA_EVDEV, ++ IDEV_DATA_KEYBOARD, + IDEV_DATA_CNT + }; + +@@ -79,6 +127,7 @@ struct idev_data { + + union { + idev_data_evdev evdev; ++ idev_data_keyboard keyboard; + }; + }; + diff --git a/0085-terminal-add-systemd-evcat-input-debugging-tool.patch b/0085-terminal-add-systemd-evcat-input-debugging-tool.patch new file mode 100644 index 0000000..cfaf3d4 --- /dev/null +++ b/0085-terminal-add-systemd-evcat-input-debugging-tool.patch @@ -0,0 +1,566 @@ +From 8e9371905c743cf997b2e8fa7fe3238f81f741fe Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 27 Aug 2014 18:38:01 +0200 +Subject: [PATCH] terminal: add systemd-evcat input debugging tool + +Like systemd-subterm, this new systemd-evcat tool should only be used to +debug libsystemd-terminal. systemd-evcat attaches to the running session +and pushes all evdev devices attached to the current session into an +idev-session. All events of the created idev-devices are then printed to +stdout for input-event debugging. +--- + .gitignore | 1 + + Makefile.am | 14 ++ + src/libsystemd-terminal/evcat.c | 499 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 514 insertions(+) + create mode 100644 src/libsystemd-terminal/evcat.c + +diff --git a/.gitignore b/.gitignore +index 8aed0b9ba6..f8650870a3 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -69,6 +69,7 @@ + /systemd-detect-virt + /systemd-efi-boot-generator + /systemd-escape ++/systemd-evcat + /systemd-firstboot + /systemd-fsck + /systemd-fstab-generator +diff --git a/Makefile.am b/Makefile.am +index 35a4c44a9f..e091febc1f 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2954,6 +2954,7 @@ noinst_LTLIBRARIES += \ + libsystemd-terminal.la + + noinst_PROGRAMS += \ ++ systemd-evcat \ + systemd-subterm + + unifontdatadir=$(datadir)/unifont +@@ -2995,6 +2996,19 @@ libsystemd_terminal_la_LIBADD = \ + libsystemd-shared.la \ + $(TERMINAL_LIBS) + ++systemd_evcat_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(TERMINAL_CFLAGS) ++ ++systemd_evcat_SOURCES = \ ++ src/libsystemd-terminal/evcat.c ++ ++systemd_evcat_LDADD = \ ++ libsystemd-terminal.la \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la \ ++ $(TERMINAL_LIBS) ++ + systemd_subterm_SOURCES = \ + src/libsystemd-terminal/subterm.c + +diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c +new file mode 100644 +index 0000000000..590a30d873 +--- /dev/null ++++ b/src/libsystemd-terminal/evcat.c +@@ -0,0 +1,499 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++/* ++ * Event Catenation ++ * The evcat tool catenates input events of all requested devices and prints ++ * them to standard-output. It's only meant for debugging of input-related ++ * problems. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "build.h" ++#include "bus-util.h" ++#include "event-util.h" ++#include "idev.h" ++#include "macro.h" ++#include "sysview.h" ++#include "term-internal.h" ++#include "util.h" ++ ++typedef struct Evcat Evcat; ++ ++struct Evcat { ++ char *session; ++ char *seat; ++ sd_event *event; ++ sd_bus *bus; ++ sysview_context *sysview; ++ idev_context *idev; ++ idev_session *idev_session; ++ ++ bool managed : 1; ++}; ++ ++static Evcat *evcat_free(Evcat *e) { ++ if (!e) ++ return NULL; ++ ++ e->idev_session = idev_session_free(e->idev_session); ++ e->idev = idev_context_unref(e->idev); ++ e->sysview = sysview_context_free(e->sysview); ++ e->bus = sd_bus_unref(e->bus); ++ e->event = sd_event_unref(e->event); ++ free(e->seat); ++ free(e->session); ++ free(e); ++ ++ tcflush(0, TCIOFLUSH); ++ ++ return NULL; ++} ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Evcat*, evcat_free); ++ ++static bool is_managed(const char *session) { ++ unsigned int vtnr; ++ struct stat st; ++ long mode; ++ int r; ++ ++ /* Using logind's Controller API is highly fragile if there is already ++ * a session controller running. If it is registered as controller ++ * itself, TakeControl will simply fail. But if its a legacy controller ++ * that does not use logind's controller API, we must never register ++ * our own controller. Otherwise, we really mess up the VT. Therefore, ++ * only run in managed mode if there's no-one else. */ ++ ++ if (geteuid() == 0) ++ return false; ++ ++ if (!isatty(1)) ++ return false; ++ ++ if (!session) ++ return false; ++ ++ r = sd_session_get_vt(session, &vtnr); ++ if (r < 0 || vtnr < 1 || vtnr > 63) ++ return false; ++ ++ mode = 0; ++ r = ioctl(1, KDGETMODE, &mode); ++ if (r < 0 || mode != KD_TEXT) ++ return false; ++ ++ r = fstat(1, &st); ++ if (r < 0 || minor(st.st_rdev) != vtnr) ++ return false; ++ ++ return true; ++} ++ ++static int evcat_new(Evcat **out) { ++ _cleanup_(evcat_freep) Evcat *e = NULL; ++ int r; ++ ++ assert(out); ++ ++ e = new0(Evcat, 1); ++ if (!e) ++ return log_oom(); ++ ++ r = sd_pid_get_session(getpid(), &e->session); ++ if (r < 0) { ++ log_error("Cannot retrieve logind session: %s", strerror(-r)); ++ return r; ++ } ++ ++ r = sd_session_get_seat(e->session, &e->seat); ++ if (r < 0) { ++ log_error("Cannot retrieve seat of logind session: %s", strerror(-r)); ++ return r; ++ } ++ ++ e->managed = is_managed(e->session); ++ ++ r = sd_event_default(&e->event); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_open_system(&e->bus); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_attach_event(e->bus, e->event, SD_EVENT_PRIORITY_NORMAL); ++ if (r < 0) ++ return r; ++ ++ r = sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_signal(e->event, NULL, SIGTERM, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_signal(e->event, NULL, SIGINT, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sysview_context_new(&e->sysview, ++ SYSVIEW_CONTEXT_SCAN_LOGIND | ++ SYSVIEW_CONTEXT_SCAN_EVDEV, ++ e->event, ++ e->bus, ++ NULL); ++ if (r < 0) ++ return r; ++ ++ r = idev_context_new(&e->idev, e->event, e->bus); ++ if (r < 0) ++ return r; ++ ++ *out = e; ++ e = NULL; ++ return 0; ++} ++ ++static void kdata_print(idev_data *data) { ++ idev_data_keyboard *k = &data->keyboard; ++ char buf[128]; ++ uint32_t i, c; ++ int cwidth; ++ ++ /* Key-press state: UP/DOWN/REPEAT */ ++ printf(" %-6s", k->value == 0 ? "UP" : ++ k->value == 1 ? "DOWN" : ++ "REPEAT"); ++ ++ /* Keycode that triggered the event */ ++ printf(" | %5u", (unsigned)k->keycode); ++ ++ /* Well-known name of the keycode */ ++ printf(" | %-20s", libevdev_event_code_get_name(EV_KEY, k->keycode) ? : ""); ++ ++ /* Well-known modifiers */ ++ printf(" | %-5s", (k->mods & IDEV_KBDMOD_SHIFT) ? "SHIFT" : ""); ++ printf(" %-4s", (k->mods & IDEV_KBDMOD_CTRL) ? "CTRL" : ""); ++ printf(" %-3s", (k->mods & IDEV_KBDMOD_ALT) ? "ALT" : ""); ++ printf(" %-5s", (k->mods & IDEV_KBDMOD_LINUX) ? "LINUX" : ""); ++ printf(" %-4s", (k->mods & IDEV_KBDMOD_CAPS) ? "CAPS" : ""); ++ ++ /* Resolved symbols */ ++ printf(" |"); ++ for (i = 0; i < k->n_syms; ++i) { ++ buf[0] = 0; ++ xkb_keysym_get_name(k->keysyms[i], buf, sizeof(buf)); ++ ++ if (is_locale_utf8()) { ++ c = k->codepoints[i]; ++ if (c < 0x110000 && c > 0x20 && (c < 0x7f || c > 0x9f)) { ++ /* "%4lc" doesn't work well, so hard-code it */ ++ cwidth = mk_wcwidth(c); ++ while (cwidth++ < 2) ++ printf(" "); ++ ++ printf(" '%lc':", (wchar_t)c); ++ } else { ++ printf(" "); ++ } ++ } ++ ++ printf(" XKB_KEY_%-30s", buf); ++ } ++ ++ printf("\n"); ++} ++ ++static bool kdata_is_exit(idev_data *data) { ++ idev_data_keyboard *k = &data->keyboard; ++ ++ if (k->value != 1) ++ return false; ++ if (k->n_syms != 1) ++ return false; ++ ++ return k->codepoints[0] == 'q'; ++} ++ ++static int evcat_idev_fn(idev_session *session, void *userdata, idev_event *ev) { ++ Evcat *e = userdata; ++ ++ switch (ev->type) { ++ case IDEV_EVENT_DEVICE_ADD: ++ idev_device_enable(ev->device_add.device); ++ break; ++ case IDEV_EVENT_DEVICE_REMOVE: ++ idev_device_disable(ev->device_remove.device); ++ break; ++ case IDEV_EVENT_DEVICE_DATA: ++ switch (ev->device_data.data.type) { ++ case IDEV_DATA_KEYBOARD: ++ if (kdata_is_exit(&ev->device_data.data)) ++ sd_event_exit(e->event, 0); ++ else ++ kdata_print(&ev->device_data.data); ++ ++ break; ++ } ++ ++ break; ++ } ++ ++ return 0; ++} ++ ++static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *ev) { ++ unsigned int flags, type; ++ Evcat *e = userdata; ++ sysview_device *d; ++ const char *name; ++ int r; ++ ++ switch (ev->type) { ++ case SYSVIEW_EVENT_SESSION_FILTER: ++ if (streq_ptr(e->session, ev->session_filter.id)) ++ return 1; ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_ADD: ++ assert(!e->idev_session); ++ ++ name = sysview_session_get_name(ev->session_add.session); ++ flags = 0; ++ ++ if (e->managed) ++ flags |= IDEV_SESSION_MANAGED; ++ ++ r = idev_session_new(&e->idev_session, ++ e->idev, ++ flags, ++ name, ++ evcat_idev_fn, ++ e); ++ if (r < 0) { ++ log_error("Cannot create idev session: %s", strerror(-r)); ++ return r; ++ } ++ ++ idev_session_enable(e->idev_session); ++ ++ if (e->managed) { ++ r = sysview_session_take_control(ev->session_add.session); ++ if (r < 0) { ++ log_error("Cannot request session control: %s", strerror(-r)); ++ return r; ++ } ++ } ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_REMOVE: ++ idev_session_disable(e->idev_session); ++ e->idev_session = idev_session_free(e->idev_session); ++ sd_event_exit(e->event, 0); ++ break; ++ case SYSVIEW_EVENT_SESSION_ATTACH: ++ d = ev->session_attach.device; ++ type = sysview_device_get_type(d); ++ if (type == SYSVIEW_DEVICE_EVDEV) { ++ r = idev_session_add_evdev(e->idev_session, sysview_device_get_ud(d)); ++ if (r < 0) { ++ log_error("Cannot add evdev device to idev: %s", strerror(-r)); ++ return r; ++ } ++ } ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_DETACH: ++ d = ev->session_detach.device; ++ type = sysview_device_get_type(d); ++ if (type == SYSVIEW_DEVICE_EVDEV) { ++ r = idev_session_remove_evdev(e->idev_session, sysview_device_get_ud(d)); ++ if (r < 0) { ++ log_error("Cannot remove evdev device from idev: %s", strerror(-r)); ++ return r; ++ } ++ } ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_CONTROL: ++ r = ev->session_control.error; ++ if (r < 0) { ++ log_error("Cannot acquire session control: %s", strerror(-r)); ++ return r; ++ } ++ ++ r = ioctl(1, KDSKBMODE, K_UNICODE); ++ if (r < 0) { ++ log_error("Cannot set K_UNICODE on stdout: %m"); ++ return -errno; ++ } ++ ++ r = ioctl(1, KDSETMODE, KD_TEXT); ++ if (r < 0) { ++ log_error("Cannot set KD_TEXT on stdout: %m"); ++ return -errno; ++ } ++ ++ printf("\n"); ++ ++ break; ++ } ++ ++ return 0; ++} ++ ++static int evcat_run(Evcat *e) { ++ struct termios in_attr, saved_attr; ++ int r; ++ ++ assert(e); ++ ++ if (!e->managed && geteuid() > 0) ++ log_warning("You run in unmanaged mode without being root. This is likely to produce no output.."); ++ ++ printf("evcat - Read and catenate events from selected input devices\n" ++ " Running on seat '%s' in user-session '%s'\n" ++ " Exit by pressing ^C or 'q'\n\n", ++ e->seat ? : "seat0", e->session ? : ""); ++ ++ r = sysview_context_start(e->sysview, evcat_sysview_fn, e); ++ if (r < 0) ++ goto out; ++ ++ r = tcgetattr(0, &in_attr); ++ if (r < 0) { ++ r = -errno; ++ goto out; ++ } ++ ++ saved_attr = in_attr; ++ in_attr.c_lflag &= ~ECHO; ++ ++ r = tcsetattr(0, TCSANOW, &in_attr); ++ if (r < 0) { ++ r = -errno; ++ goto out; ++ } ++ ++ r = sd_event_loop(e->event); ++ tcsetattr(0, TCSANOW, &saved_attr); ++ printf("exiting..\n"); ++ ++out: ++ sysview_context_stop(e->sysview); ++ return r; ++} ++ ++static int help(void) { ++ printf("%s [OPTIONS...]\n\n" ++ "Read and catenate events from selected input devices.\n\n" ++ " -h --help Show this help\n" ++ " --version Show package version\n" ++ , program_invocation_short_name); ++ ++ return 0; ++} ++ ++static int parse_argv(int argc, char *argv[]) { ++ enum { ++ ARG_VERSION = 0x100, ++ }; ++ static const struct option options[] = { ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, ARG_VERSION }, ++ {}, ++ }; ++ int c; ++ ++ assert(argc >= 0); ++ assert(argv); ++ ++ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) ++ switch (c) { ++ case 'h': ++ help(); ++ return 0; ++ ++ case ARG_VERSION: ++ puts(PACKAGE_STRING); ++ puts(SYSTEMD_FEATURES); ++ return 0; ++ ++ case '?': ++ return -EINVAL; ++ ++ default: ++ assert_not_reached("Unhandled option"); ++ } ++ ++ if (argc > optind) { ++ log_error("Too many arguments"); ++ return -EINVAL; ++ } ++ ++ return 1; ++} ++ ++int main(int argc, char *argv[]) { ++ _cleanup_(evcat_freep) Evcat *e = NULL; ++ int r; ++ ++ log_set_target(LOG_TARGET_AUTO); ++ log_parse_environment(); ++ log_open(); ++ ++ setlocale(LC_ALL, ""); ++ if (!is_locale_utf8()) ++ log_warning("Locale is not set to UTF-8. Codepoints will not be printed!"); ++ ++ r = parse_argv(argc, argv); ++ if (r <= 0) ++ goto finish; ++ ++ r = evcat_new(&e); ++ if (r < 0) ++ goto finish; ++ ++ r = evcat_run(e); ++ ++finish: ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} diff --git a/0086-man-add-sample-glib-sd-event-integration.patch b/0086-man-add-sample-glib-sd-event-integration.patch new file mode 100644 index 0000000..8e138af --- /dev/null +++ b/0086-man-add-sample-glib-sd-event-integration.patch @@ -0,0 +1,93 @@ +From c609cb9898dc8dec5dcb0b1d111b3f6b6a5e09d4 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 27 Aug 2014 19:04:29 +0200 +Subject: [PATCH] man: add sample glib/sd-event integration + +This should be moved to man pages, but for now the C code is included directly. + +Suggested by Zbyszek. +--- + man/glib-event-glue.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 74 insertions(+) + create mode 100644 man/glib-event-glue.c + +diff --git a/man/glib-event-glue.c b/man/glib-event-glue.c +new file mode 100644 +index 0000000000..95aaea1e63 +--- /dev/null ++++ b/man/glib-event-glue.c +@@ -0,0 +1,74 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ Copyright 2014 Tom Gundersen ++ ++ 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. ++***/ ++ ++#include ++#include ++#include ++ ++#include "glib-event-glue.h" ++ ++typedef struct SDEventSource { ++ GSource source; ++ GPollFD pollfd; ++ sd_event *event; ++} SDEventSource; ++ ++static gboolean event_prepare(GSource *source, gint *timeout_) { ++ return sd_event_prepare(((SDEventSource *)source)->event) > 0; ++} ++ ++static gboolean event_check(GSource *source) { ++ return sd_event_wait(((SDEventSource *)source)->event, 0) > 0; ++} ++ ++static gboolean event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { ++ return sd_event_dispatch(((SDEventSource *)source)->event) > 0; ++} ++ ++static void event_finalize(GSource *source) { ++ sd_event_unref(((SDEventSource *)source)->event); ++} ++ ++static GSourceFuncs event_funcs = { ++ .prepare = event_prepare, ++ .check = event_check, ++ .dispatch = event_dispatch, ++ .finalize = event_finalize, ++}; ++ ++GSource *g_sd_event_create_source(sd_event *event) { ++ SDEventSource *source; ++ ++ source = (SDEventSource *)g_source_new(&event_funcs, sizeof(SDEventSource)); ++ ++ source->event = sd_event_ref(event); ++ source->pollfd.fd = sd_event_get_fd(event); ++ source->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR; ++ ++ g_source_add_poll((GSource *)source, &source->pollfd); ++ ++ return (GSource *)source; ++} diff --git a/0087-util-fix-minimal-race-where-we-might-miss-SIGTERMs-w.patch b/0087-util-fix-minimal-race-where-we-might-miss-SIGTERMs-w.patch new file mode 100644 index 0000000..b538002 --- /dev/null +++ b/0087-util-fix-minimal-race-where-we-might-miss-SIGTERMs-w.patch @@ -0,0 +1,91 @@ +From 8a7c93d858c342744adf481565d8bb03b9713dcf Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 27 Aug 2014 21:42:20 +0200 +Subject: [PATCH] util: fix minimal race where we might miss SIGTERMs when + forking off an agent + +Before forking, block all signals, and unblock them afterwards. This way +the child will have them blocked, and we won't lose them. +--- + src/shared/util.c | 35 +++++++++++++++++++++++------------ + 1 file changed, 23 insertions(+), 12 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 9e4ff85ffb..cf9d487b82 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -5102,9 +5102,9 @@ int fd_inc_rcvbuf(int fd, size_t n) { + } + + int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { +- pid_t parent_pid, agent_pid; +- int fd; + bool stdout_is_tty, stderr_is_tty; ++ pid_t parent_pid, agent_pid; ++ sigset_t ss, saved_ss; + unsigned n, i; + va_list ap; + char **l; +@@ -5112,16 +5112,25 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa + assert(pid); + assert(path); + +- parent_pid = getpid(); +- + /* Spawns a temporary TTY agent, making sure it goes away when + * we go away */ + ++ parent_pid = getpid(); ++ ++ /* First we temporarily block all signals, so that the new ++ * child has them blocked initially. This way, we can be sure ++ * that SIGTERMs are not lost we might send to the agent. */ ++ assert_se(sigfillset(&ss) >= 0); ++ assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0); ++ + agent_pid = fork(); +- if (agent_pid < 0) ++ if (agent_pid < 0) { ++ assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); + return -errno; ++ } + + if (agent_pid != 0) { ++ assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); + *pid = agent_pid; + return 0; + } +@@ -5132,24 +5141,26 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + ++ /* Make sure we actually can kill the agent, if we need to, in ++ * case somebody invoked us from a shell script that trapped ++ * SIGTERM or so... */ ++ reset_all_signal_handlers(); ++ reset_signal_mask(); ++ + /* Check whether our parent died before we were able +- * to set the death signal */ ++ * to set the death signal and unblock the signals */ + if (getppid() != parent_pid) + _exit(EXIT_SUCCESS); + + /* Don't leak fds to the agent */ + close_all_fds(except, n_except); + +- /* Make sure we actually can kill the agent, if we need to, in +- * case somebody invoked us from a shell script that trapped +- * SIGTERM or so... */ +- reset_all_signal_handlers(); +- reset_signal_mask(); +- + stdout_is_tty = isatty(STDOUT_FILENO); + stderr_is_tty = isatty(STDERR_FILENO); + + if (!stdout_is_tty || !stderr_is_tty) { ++ int fd; ++ + /* Detach from stdout/stderr. and reopen + * /dev/tty for them. This is important to + * ensure that when systemctl is started via diff --git a/0088-update-TODO.patch b/0088-update-TODO.patch new file mode 100644 index 0000000..1580985 --- /dev/null +++ b/0088-update-TODO.patch @@ -0,0 +1,22 @@ +From eff3f4f9e92b56d9dfb90d5094e48cc743c776cc Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 27 Aug 2014 21:43:33 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/TODO b/TODO +index a00c13dab2..bc81a70eb1 100644 +--- a/TODO ++++ b/TODO +@@ -24,6 +24,8 @@ External: + + Features: + ++* nspawn --network-interface= doesn't work... ++ + * dbus: add new message hdr field for allowing interactive auth, write spec for it. update dbus spec to mandate that unknown flags *must* be ignored... + + * maybe introduce AssertXYZ= similar to ConditionXYZ= that causes a unit to fail (instead of skipping it) if some condition is not true... diff --git a/0089-terminal-remove-unused-variable.patch b/0089-terminal-remove-unused-variable.patch new file mode 100644 index 0000000..14b02ae --- /dev/null +++ b/0089-terminal-remove-unused-variable.patch @@ -0,0 +1,21 @@ +From 00b333bb1039809a42ba4c7f25ba85f68766477d Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Wed, 27 Aug 2014 23:23:10 +0200 +Subject: [PATCH] terminal: remove unused variable + +--- + src/libsystemd-terminal/idev-keyboard.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c +index 647aade932..7ab4db2cf7 100644 +--- a/src/libsystemd-terminal/idev-keyboard.c ++++ b/src/libsystemd-terminal/idev-keyboard.c +@@ -312,7 +312,6 @@ static int kbdctx_locale_props_changed_fn(sd_bus *bus, + sd_bus_message *signal, + void *userdata, + sd_bus_error *ret_err) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + kbdctx *kc = userdata; + int r; + diff --git a/0090-sd-journal-properly-convert-object-size-on-big-endia.patch b/0090-sd-journal-properly-convert-object-size-on-big-endia.patch new file mode 100644 index 0000000..1efcaac --- /dev/null +++ b/0090-sd-journal-properly-convert-object-size-on-big-endia.patch @@ -0,0 +1,36 @@ +From 57cd09acf2c63a414aa2131c00a2b3f600eb0133 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 23 Aug 2014 22:35:03 -0400 +Subject: [PATCH] sd-journal: properly convert object->size on big endian + +mmap code crashes when attempting to map an object of zero size. + +https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=758392 +https://bugs.freedesktop.org/show_bug.cgi?id=82894 +--- + src/journal/journal-file.h | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index 3d416820b0..da2ef3b795 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -214,14 +214,15 @@ static unsigned type_to_context(int type) { + + static inline int journal_file_object_keep(JournalFile *f, Object *o, uint64_t offset) { + unsigned context = type_to_context(o->object.type); ++ uint64_t s = le64toh(o->object.size); + + return mmap_cache_get(f->mmap, f->fd, f->prot, context, true, +- offset, o->object.size, &f->last_stat, NULL); ++ offset, s, &f->last_stat, NULL); + } + + static inline int journal_file_object_release(JournalFile *f, Object *o, uint64_t offset) { + unsigned context = type_to_context(o->object.type); ++ uint64_t s = le64toh(o->object.size); + +- return mmap_cache_release(f->mmap, f->fd, f->prot, context, +- offset, o->object.size); ++ return mmap_cache_release(f->mmap, f->fd, f->prot, context, offset, s); + } diff --git a/0091-sd-journal-verify-that-object-start-with-the-field-n.patch b/0091-sd-journal-verify-that-object-start-with-the-field-n.patch new file mode 100644 index 0000000..4a5016b --- /dev/null +++ b/0091-sd-journal-verify-that-object-start-with-the-field-n.patch @@ -0,0 +1,51 @@ +From 0f99f74a14ef193c1ebde687c5cc76e1d67b85ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 26 Aug 2014 23:54:31 -0400 +Subject: [PATCH] sd-journal: verify that object start with the field name + +If the journal is corrupted, we might return an object that does +not start with the expected field name and/or is shorter than it +should. +--- + src/journal/journal-file.c | 1 - + src/journal/sd-journal.c | 15 +++++++++++++++ + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 986e94de39..7286e14ddb 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -425,7 +425,6 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec + if (!VALID64(offset)) + return -EFAULT; + +- + r = journal_file_move_to(f, type_to_context(type), false, offset, sizeof(ObjectHeader), &t); + if (r < 0) + return r; +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 80ff8fef57..693707cb34 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -2571,6 +2571,21 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ + if (r < 0) + return r; + ++ /* Check if we have at least the field name and "=". */ ++ if (ol <= k) { ++ log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu", ++ j->unique_file->path, j->unique_offset, ++ ol, k + 1); ++ return -EBADMSG; ++ } ++ ++ if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') { ++ log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"", ++ j->unique_file->path, j->unique_offset, ++ j->unique_field); ++ return -EBADMSG; ++ } ++ + /* OK, now let's see if we already returned this data + * object by checking if it exists in the earlier + * traversed files. */ diff --git a/0092-terminal-sysview-don-t-return-uninitialized-error-co.patch b/0092-terminal-sysview-don-t-return-uninitialized-error-co.patch new file mode 100644 index 0000000..9749b4d --- /dev/null +++ b/0092-terminal-sysview-don-t-return-uninitialized-error-co.patch @@ -0,0 +1,26 @@ +From 371ad55d460559b4262e25d0f9b64dc37c3f7565 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 11:01:31 +0200 +Subject: [PATCH] terminal: sysview: don't return uninitialized error codes + +In case 'scan_evdev' and 'scan_drm' are both false, we never set 'r' to +anyhting, thus return an uninitialized error code. Fix this by always +returning 0 as we catch negative codes earlier, anyway. Thanks to Thomas +H.P. Anderson for the report. +--- + src/libsystemd-terminal/sysview.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index d885cb4d4a..f5363dedf4 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -821,7 +821,7 @@ static int context_ud_prepare_monitor(sysview_context *c, struct udev_monitor *m + return r; + } + +- return r; ++ return 0; + } + + static int context_ud_prepare_scan(sysview_context *c, struct udev_enumerate *e) { diff --git a/0093-nspawn-fix-network-interface.patch b/0093-nspawn-fix-network-interface.patch new file mode 100644 index 0000000..48f22b5 --- /dev/null +++ b/0093-nspawn-fix-network-interface.patch @@ -0,0 +1,37 @@ +From 3125b3ef5db70d45882c7d6f617705802c5f939e Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 28 Aug 2014 12:15:51 +0200 +Subject: [PATCH] nspawn: fix --network-interface + +Use SETLINK when modifying an existing link. +--- + TODO | 2 -- + src/nspawn/nspawn.c | 2 +- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/TODO b/TODO +index bc81a70eb1..a00c13dab2 100644 +--- a/TODO ++++ b/TODO +@@ -24,8 +24,6 @@ External: + + Features: + +-* nspawn --network-interface= doesn't work... +- + * dbus: add new message hdr field for allowing interactive auth, write spec for it. update dbus spec to mandate that unknown flags *must* be ignored... + + * maybe introduce AssertXYZ= similar to ConditionXYZ= that causes a unit to fail (instead of skipping it) if some condition is not true... +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 56d9cc68c6..5af89c9b32 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -1886,7 +1886,7 @@ static int move_network_interfaces(pid_t pid) { + if (ifi < 0) + return ifi; + +- r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, ifi); ++ r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi); + if (r < 0) { + log_error("Failed to allocate netlink message: %s", strerror(-r)); + return r; diff --git a/0094-terminal-free-xkb-state-on-keyboard-destruction.patch b/0094-terminal-free-xkb-state-on-keyboard-destruction.patch new file mode 100644 index 0000000..aca5614 --- /dev/null +++ b/0094-terminal-free-xkb-state-on-keyboard-destruction.patch @@ -0,0 +1,23 @@ +From 200716a628b70fe723e7d4e09bb2ece10c10bdc0 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 12:21:33 +0200 +Subject: [PATCH] terminal: free xkb state on keyboard destruction + +Fix leaking the xkb-state during keyboard destruction, leaking lots of xkb +references into the wild. +--- + src/libsystemd-terminal/idev-keyboard.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c +index 7ab4db2cf7..03f54bb74f 100644 +--- a/src/libsystemd-terminal/idev-keyboard.c ++++ b/src/libsystemd-terminal/idev-keyboard.c +@@ -550,6 +550,7 @@ int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) { + static void keyboard_free(idev_device *d) { + idev_keyboard *k = keyboard_from_device(d); + ++ xkb_state_unref(k->xkb_state); + free(k->repdata.keyboard.codepoints); + free(k->repdata.keyboard.keysyms); + free(k->evdata.keyboard.codepoints); diff --git a/0095-terminal-free-sysview-device-names-on-destruction.patch b/0095-terminal-free-sysview-device-names-on-destruction.patch new file mode 100644 index 0000000..8ed758f --- /dev/null +++ b/0095-terminal-free-sysview-device-names-on-destruction.patch @@ -0,0 +1,38 @@ +From fa9838ddd62ea31f8aea99757916a16d76b31cbc Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 12:25:58 +0200 +Subject: [PATCH] terminal: free sysview-device names on destruction + +Don't leak the device-names during device destruction in sysview. Somehow, +the device-name is "const char*", so make it "char*" first to avoid +warnings when calling free() on it. +--- + src/libsystemd-terminal/sysview-internal.h | 2 +- + src/libsystemd-terminal/sysview.c | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/sysview-internal.h b/src/libsystemd-terminal/sysview-internal.h +index 5aee9f67d8..9299fabb82 100644 +--- a/src/libsystemd-terminal/sysview-internal.h ++++ b/src/libsystemd-terminal/sysview-internal.h +@@ -39,7 +39,7 @@ + + struct sysview_device { + sysview_seat *seat; +- const char *name; ++ char *name; + unsigned int type; + + union { +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index f5363dedf4..bd345fa22e 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -98,6 +98,7 @@ sysview_device *sysview_device_free(sysview_device *device) { + break; + } + ++ free(device->name); + free(device); + + return NULL; diff --git a/0096-bus-fix-use-after-free-in-slot-release.patch b/0096-bus-fix-use-after-free-in-slot-release.patch new file mode 100644 index 0000000..f4d20d2 --- /dev/null +++ b/0096-bus-fix-use-after-free-in-slot-release.patch @@ -0,0 +1,70 @@ +From d974ad0524942882f489914013d08ab16d147170 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 12:42:03 +0200 +Subject: [PATCH] bus: fix use-after-free in slot-release + +We must not access slot->floating after we possible dropped the last +reference to it. Fix all callback-invocations to first check +slot->floating and possible disconnect the slot, then release the last +reference. +--- + src/libsystemd/sd-bus/sd-bus.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index a204d67590..8caa404227 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -2107,7 +2107,7 @@ static int process_timeout(sd_bus *bus) { + r = c->callback(bus, m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; +- bus->current_slot = sd_bus_slot_unref(slot); ++ bus->current_slot = NULL; + bus->current_message = NULL; + + if (slot->floating) { +@@ -2115,6 +2115,8 @@ static int process_timeout(sd_bus *bus) { + sd_bus_slot_unref(slot); + } + ++ sd_bus_slot_unref(slot); ++ + return bus_maybe_reply_error(m, r, &error_buffer); + } + +@@ -2203,13 +2205,15 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { + r = c->callback(bus, m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; +- bus->current_slot = sd_bus_slot_unref(slot); ++ bus->current_slot = NULL; + + if (slot->floating) { + bus_slot_disconnect(slot); + sd_bus_slot_unref(slot); + } + ++ sd_bus_slot_unref(slot); ++ + return bus_maybe_reply_error(m, r, &error_buffer); + } + +@@ -2529,7 +2533,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { + r = c->callback(bus, m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; +- bus->current_slot = sd_bus_slot_unref(slot); ++ bus->current_slot = NULL; + bus->current_message = NULL; + + if (slot->floating) { +@@ -2537,6 +2541,8 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { + sd_bus_slot_unref(slot); + } + ++ sd_bus_slot_unref(slot); ++ + return bus_maybe_reply_error(m, r, &error_buffer); + } + diff --git a/0097-macro-use-unique-variable-names-for-math-macros.patch b/0097-macro-use-unique-variable-names-for-math-macros.patch new file mode 100644 index 0000000..d5d4c8e --- /dev/null +++ b/0097-macro-use-unique-variable-names-for-math-macros.patch @@ -0,0 +1,131 @@ +From 667a0377fb25ddb0c3efbc43d186ffd4c097ce41 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 14:45:38 +0200 +Subject: [PATCH] macro: use unique variable names for math-macros + +Similar to container_of(), we now use unique variable names for the bascic +math macros MAX, MIN, CLAMP, LESS_BY. Furthermore, unit tests are added to +verify they work as expected. + +For a rationale, see: + commit fb835651aff79a1e7fc5795086c9b26e59a8e6ca + Author: David Herrmann + Date: Fri Aug 22 14:41:37 2014 +0200 + + shared: make container_of() use unique variable names +--- + src/shared/macro.h | 53 +++++++++++++++++++++++++++++----------------------- + src/test/test-util.c | 17 +++++++++++++++++ + 2 files changed, 47 insertions(+), 23 deletions(-) + +diff --git a/src/shared/macro.h b/src/shared/macro.h +index e6734804bd..9ee332c8df 100644 +--- a/src/shared/macro.h ++++ b/src/shared/macro.h +@@ -134,12 +134,13 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { + }) + + #undef MAX +-#define MAX(a,b) \ ++#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) ++#define __MAX(aq, a, bq, b) \ + __extension__ ({ \ +- const typeof(a) _a = (a); \ +- const typeof(b) _b = (b); \ +- _a > _b ? _a : _b; \ +- }) ++ const typeof(a) UNIQ_T(A, aq) = (a); \ ++ const typeof(b) UNIQ_T(B, bq) = (b); \ ++ UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ ++ }) + + /* evaluates to (void) if _A or _B are not constant or of different types */ + #define CONST_MAX(_A, _B) \ +@@ -160,12 +161,13 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { + }) + + #undef MIN +-#define MIN(a,b) \ ++#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) ++#define __MIN(aq, a, bq, b) \ + __extension__ ({ \ +- const typeof(a) _a = (a); \ +- const typeof(b) _b = (b); \ +- _a < _b ? _a : _b; \ +- }) ++ const typeof(a) UNIQ_T(A, aq) = (a); \ ++ const typeof(b) UNIQ_T(B, bq) = (b); \ ++ UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ ++ }) + + #define MIN3(x,y,z) \ + __extension__ ({ \ +@@ -173,22 +175,27 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { + MIN(_c, z); \ + }) + +-#define LESS_BY(A,B) \ ++#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) ++#define __LESS_BY(aq, a, bq, b) \ + __extension__ ({ \ +- const typeof(A) _A = (A); \ +- const typeof(B) _B = (B); \ +- _A > _B ? _A - _B : 0; \ +- }) ++ const typeof(a) UNIQ_T(A, aq) = (a); \ ++ const typeof(b) UNIQ_T(B, bq) = (b); \ ++ UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) - UNIQ_T(B,bq) : 0; \ ++ }) + +-#ifndef CLAMP +-#define CLAMP(x, low, high) \ ++#undef CLAMP ++#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) ++#define __CLAMP(xq, x, lowq, low, highq, high) \ + __extension__ ({ \ +- const typeof(x) _x = (x); \ +- const typeof(low) _low = (low); \ +- const typeof(high) _high = (high); \ +- ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \ +- }) +-#endif ++ const typeof(x) UNIQ_T(X,xq) = (x); \ ++ const typeof(low) UNIQ_T(LOW,lowq) = (low); \ ++ const typeof(high) UNIQ_T(HIGH,highq) = (high); \ ++ UNIQ_T(X,xq) > UNIQ_T(HIGH,highq) ? \ ++ UNIQ_T(HIGH,highq) : \ ++ UNIQ_T(X,xq) < UNIQ_T(LOW,lowq) ? \ ++ UNIQ_T(LOW,lowq) : \ ++ UNIQ_T(X,xq); \ ++ }) + + #define assert_se(expr) \ + do { \ +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 795f3a1b3d..72a8a6b130 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -94,6 +94,23 @@ static void test_max(void) { + assert_cc(MAXSIZE(char[3], uint16_t) == 3); + assert_cc(MAXSIZE(char[3], uint32_t) == 4); + assert_cc(MAXSIZE(char, long) == sizeof(long)); ++ ++ assert_se(MAX(-5, 5) == 5); ++ assert_se(MAX(5, 5) == 5); ++ assert_se(MAX(MAX(1, MAX(2, MAX(3, 4))), 5) == 5); ++ assert_se(MAX(MAX(1, MAX(2, MAX(3, 2))), 1) == 3); ++ assert_se(MAX(MIN(1, MIN(2, MIN(3, 4))), 5) == 5); ++ assert_se(MAX(MAX(1, MIN(2, MIN(3, 2))), 1) == 2); ++ assert_se(LESS_BY(8, 4) == 4); ++ assert_se(LESS_BY(8, 8) == 0); ++ assert_se(LESS_BY(4, 8) == 0); ++ assert_se(LESS_BY(16, LESS_BY(8, 4)) == 12); ++ assert_se(LESS_BY(4, LESS_BY(8, 4)) == 0); ++ assert_se(CLAMP(-5, 0, 1) == 0); ++ assert_se(CLAMP(5, 0, 1) == 1); ++ assert_se(CLAMP(5, -10, 1) == 1); ++ assert_se(CLAMP(5, -10, 10) == 5); ++ assert_se(CLAMP(CLAMP(0, -10, 10), CLAMP(-5, 10, 20), CLAMP(100, -5, 20)) == 10); + } + + static void test_container_of(void) { diff --git a/0098-use-the-switch_root-function-in-shutdown.patch b/0098-use-the-switch_root-function-in-shutdown.patch new file mode 100644 index 0000000..49fbbec --- /dev/null +++ b/0098-use-the-switch_root-function-in-shutdown.patch @@ -0,0 +1,275 @@ +From 5a4bf02ff57e4dd3453f2b868c72fe45f60033a3 Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Thu, 21 Aug 2014 16:21:26 +0200 +Subject: [PATCH] use the switch_root function in shutdown + +removes code duplication + +also move switch-root to shared +--- + Makefile.am | 4 +- + src/core/main.c | 4 +- + src/core/shutdown.c | 90 +++++++------------------------------- + src/{core => shared}/switch-root.c | 35 +++++++-------- + src/{core => shared}/switch-root.h | 2 +- + 5 files changed, 39 insertions(+), 96 deletions(-) + rename src/{core => shared}/switch-root.c (81%) + rename src/{core => shared}/switch-root.h (88%) + +diff --git a/Makefile.am b/Makefile.am +index e091febc1f..1facb8da43 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -868,6 +868,8 @@ libsystemd_shared_la_SOURCES = \ + src/shared/memfd.h \ + src/shared/uid-range.c \ + src/shared/uid-range.h \ ++ src/shared/switch-root.h \ ++ src/shared/switch-root.c \ + src/shared/nss-util.h + + nodist_libsystemd_shared_la_SOURCES = \ +@@ -1109,8 +1111,6 @@ libsystemd_core_la_SOURCES = \ + src/core/namespace.h \ + src/core/build.h \ + src/core/sysfs-show.h \ +- src/core/switch-root.h \ +- src/core/switch-root.c \ + src/core/killall.h \ + src/core/killall.c \ + src/core/audit-fd.c \ +diff --git a/src/core/main.c b/src/core/main.c +index 95ab40fffc..64c2b3f3a1 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1853,8 +1853,8 @@ finish: + * deserializing. */ + broadcast_signal(SIGTERM, false, true); + +- /* And switch root */ +- r = switch_root(switch_root_dir); ++ /* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */ ++ r = switch_root(switch_root_dir, "/mnt", true, MS_MOVE); + if (r < 0) + log_error("Failed to switch root, ignoring: %s", strerror(-r)); + } +diff --git a/src/core/shutdown.c b/src/core/shutdown.c +index 0e2ea5754f..1e88b05790 100644 +--- a/src/core/shutdown.c ++++ b/src/core/shutdown.c +@@ -48,6 +48,7 @@ + #include "killall.h" + #include "cgroup-util.h" + #include "def.h" ++#include "switch-root.h" + + #define FINALIZE_ATTEMPTS 50 + +@@ -131,16 +132,7 @@ static int parse_argv(int argc, char *argv[]) { + return 0; + } + +-static int prepare_new_root(void) { +- static const char dirs[] = +- "/run/initramfs/oldroot\0" +- "/run/initramfs/proc\0" +- "/run/initramfs/sys\0" +- "/run/initramfs/dev\0" +- "/run/initramfs/run\0"; +- +- const char *dir; +- ++static int switch_root_initramfs(void) { + if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) { + log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m"); + return -errno; +@@ -151,66 +143,13 @@ static int prepare_new_root(void) { + return -errno; + } + +- NULSTR_FOREACH(dir, dirs) +- if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) { +- log_error("Failed to mkdir %s: %m", dir); +- return -errno; +- } +- +- if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) { +- log_error("Failed to mount bind /sys on /run/initramfs/sys: %m"); +- return -errno; +- } +- +- if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) { +- log_error("Failed to mount bind /proc on /run/initramfs/proc: %m"); +- return -errno; +- } +- +- if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) { +- log_error("Failed to mount bind /dev on /run/initramfs/dev: %m"); +- return -errno; +- } +- +- if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) { +- log_error("Failed to mount bind /run on /run/initramfs/run: %m"); +- return -errno; +- } +- +- return 0; ++ /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file desriptors. ++ * /run/initramfs/shutdown will take care of these. ++ * Also do not detach the old root, because /run/initramfs/shutdown needs to access it. ++ */ ++ return switch_root("/run/initramfs", "/oldroot", false, MS_BIND); + } + +-static int pivot_to_new_root(void) { +- +- if (chdir("/run/initramfs") < 0) { +- log_error("Failed to change directory to /run/initramfs: %m"); +- return -errno; +- } +- +- /* Work-around for a kernel bug: for some reason the kernel +- * refuses switching root if any file systems are mounted +- * MS_SHARED. Hence remount them MS_PRIVATE here as a +- * work-around. +- * +- * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */ +- if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) +- log_warning("Failed to make \"/\" private mount: %m"); +- +- if (pivot_root(".", "oldroot") < 0) { +- log_error("pivot failed: %m"); +- /* only chroot if pivot root succeeded */ +- return -errno; +- } +- +- chroot("."); +- +- setsid(); +- make_console_stdio(); +- +- log_info("Successfully changed into root pivot."); +- +- return 0; +-} + + int main(int argc, char *argv[]) { + bool need_umount, need_swapoff, need_loop_detach, need_dm_detach; +@@ -372,16 +311,21 @@ int main(int argc, char *argv[]) { + + if (!in_container && !in_initrd() && + access("/run/initramfs/shutdown", X_OK) == 0) { +- +- if (prepare_new_root() >= 0 && +- pivot_to_new_root() >= 0) { ++ r = switch_root_initramfs(); ++ if (r >= 0) { + arguments[0] = (char*) "/shutdown"; + +- log_info("Returning to initrd..."); ++ setsid(); ++ make_console_stdio(); ++ ++ log_info("Successfully changed into root pivot.\n" ++ "Returning to initrd..."); + + execv("/shutdown", arguments); + log_error("Failed to execute shutdown binary: %m"); +- } ++ } else ++ log_error("Failed to switch root to \"/run/initramfs\": %s", strerror(-r)); ++ + } + + if (need_umount || need_swapoff || need_loop_detach || need_dm_detach) +diff --git a/src/core/switch-root.c b/src/shared/switch-root.c +similarity index 81% +rename from src/core/switch-root.c +rename to src/shared/switch-root.c +index 0ea61dbb29..5f075e6003 100644 +--- a/src/core/switch-root.c ++++ b/src/shared/switch-root.c +@@ -34,7 +34,7 @@ + #include "base-filesystem.h" + #include "missing.h" + +-int switch_root(const char *new_root) { ++int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) { + + /* Don't try to unmount/move the old "/", there's no way to do it. */ + static const char move_mounts[] = +@@ -52,14 +52,8 @@ int switch_root(const char *new_root) { + if (path_equal(new_root, "/")) + return 0; + +- /* When using pivot_root() we assume that /mnt exists as place +- * we can temporarily move the old root to. As we immediately +- * unmount it from there it doesn't matter much which +- * directory we choose for this, but it should be more likely +- * than not that /mnt exists and is suitable as mount point +- * and is on the same fs as the old root dir */ +- temporary_old_root = strappenda(new_root, "/mnt"); +- mkdir_p(temporary_old_root, 0755); ++ temporary_old_root = strappenda(new_root, oldroot); ++ mkdir_p_label(temporary_old_root, 0755); + + old_root_remove = in_initrd(); + +@@ -84,7 +78,7 @@ int switch_root(const char *new_root) { + snprintf(new_mount, sizeof(new_mount), "%s%s", new_root, i); + char_array_0(new_mount); + +- mkdir_p(new_mount, 0755); ++ mkdir_p_label(new_mount, 0755); + + if ((stat(new_mount, &sb) < 0) || + sb.st_dev != new_root_stat.st_dev) { +@@ -97,11 +91,16 @@ int switch_root(const char *new_root) { + continue; + } + +- if (mount(i, new_mount, NULL, MS_MOVE, NULL) < 0) { +- log_error("Failed to move mount %s to %s, forcing unmount: %m", i, new_mount); ++ if (mount(i, new_mount, NULL, mountflags, NULL) < 0) { ++ if (mountflags & MS_MOVE) { ++ log_error("Failed to move mount %s to %s, forcing unmount: %m", i, new_mount); ++ ++ if (umount2(i, MNT_FORCE) < 0) ++ log_warning("Failed to unmount %s: %m", i); ++ } ++ if (mountflags & MS_BIND) ++ log_error("Failed to bind mount %s to %s: %m", i, new_mount); + +- if (umount2(i, MNT_FORCE) < 0) +- log_warning("Failed to unmount %s: %m", i); + } + } + +@@ -127,10 +126,10 @@ int switch_root(const char *new_root) { + * not possible however, and hence we simply overmount root */ + if (pivot_root(new_root, temporary_old_root) >= 0) { + +- /* Immediately get rid of the old root. Since we are +- * running off it we need to do this lazily. */ +- if (umount2("/mnt", MNT_DETACH) < 0) { +- log_error("Failed to umount old root dir /mnt: %m"); ++ /* Immediately get rid of the old root, if detach_oldroot is set. ++ * Since we are running off it we need to do this lazily. */ ++ if (detach_oldroot && umount2(oldroot, MNT_DETACH) < 0) { ++ log_error("Failed to umount old root dir %s: %m", oldroot); + return -errno; + } + +diff --git a/src/core/switch-root.h b/src/shared/switch-root.h +similarity index 88% +rename from src/core/switch-root.h +rename to src/shared/switch-root.h +index ab493b5fb1..adf893a922 100644 +--- a/src/core/switch-root.h ++++ b/src/shared/switch-root.h +@@ -21,4 +21,4 @@ + along with systemd; If not, see . + ***/ + +-int switch_root(const char *switch_root); ++int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags); diff --git a/0099-locale-fix-sending-PropertiesChanged-for-x11-keymap-.patch b/0099-locale-fix-sending-PropertiesChanged-for-x11-keymap-.patch new file mode 100644 index 0000000..2d09e57 --- /dev/null +++ b/0099-locale-fix-sending-PropertiesChanged-for-x11-keymap-.patch @@ -0,0 +1,25 @@ +From c168eb6785bacc2042687bf879259dfc27d5a523 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 15:22:26 +0200 +Subject: [PATCH] locale: fix sending PropertiesChanged for x11 keymap changed + +The sd_bus_emit_properties_changed() call for x11 keymap changes lacks +commas.. whoops. Fix it! Now localed emits PropertiesChanged signals +again. +--- + src/locale/localed.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index 508a00079e..4d22568787 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -1046,7 +1046,7 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", +- "X11Layout" "X11Model" "X11Variant" "X11Options", NULL); ++ "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); + + if (convert) { + r = x11_convert_to_vconsole(c, bus); diff --git a/0100-bus-don-t-skip-interfaces-in-bus_message_map_propert.patch b/0100-bus-don-t-skip-interfaces-in-bus_message_map_propert.patch new file mode 100644 index 0000000..4ea2795 --- /dev/null +++ b/0100-bus-don-t-skip-interfaces-in-bus_message_map_propert.patch @@ -0,0 +1,61 @@ +From 427c71629ea375e4ca1841a55902b40de21f2ab4 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 15:24:00 +0200 +Subject: [PATCH] bus: don't skip interfaces in + bus_message_map_properties_changed() + +Skipping interfaces randomly without the caller specifying it is nasty. +Avoid this and let the caller do that themselves. +--- + src/libsystemd-terminal/idev-keyboard.c | 15 +++++++++++---- + src/libsystemd/sd-bus/bus-util.c | 3 --- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c +index 03f54bb74f..ab9e4811b3 100644 +--- a/src/libsystemd-terminal/idev-keyboard.c ++++ b/src/libsystemd-terminal/idev-keyboard.c +@@ -317,11 +317,14 @@ static int kbdctx_locale_props_changed_fn(sd_bus *bus, + + kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all); + ++ /* skip interface name */ ++ r = sd_bus_message_skip(signal, "s"); ++ if (r < 0) ++ goto error; ++ + r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc); +- if (r < 0) { +- log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r)); +- return r; +- } ++ if (r < 0) ++ goto error; + + if (r > 0) { + r = kbdctx_query_locale(kc); +@@ -331,6 +334,10 @@ static int kbdctx_locale_props_changed_fn(sd_bus *bus, + + kbdctx_refresh_keymap(kc); + return 0; ++ ++error: ++ log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r)); ++ return r; + } + + static int kbdctx_setup_bus(kbdctx *kc) { +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index aed3889b12..a85d36180e 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1051,9 +1051,6 @@ int bus_message_map_properties_changed(sd_bus *bus, + assert(m); + assert(map); + +- /* skip interface, but allow callers to do that themselves */ +- sd_bus_message_skip(m, "s"); +- + r = bus_message_map_all_properties(bus, m, map, userdata); + if (r < 0) + return r; diff --git a/0101-networkctl-do-not-mix-dns-and-ntp-servers.patch b/0101-networkctl-do-not-mix-dns-and-ntp-servers.patch new file mode 100644 index 0000000..8260162 --- /dev/null +++ b/0101-networkctl-do-not-mix-dns-and-ntp-servers.patch @@ -0,0 +1,22 @@ +From ddb7f7fc07a31937989afad53edb87b50e2cad72 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 18 Aug 2014 17:22:26 -0400 +Subject: [PATCH] networkctl: do not mix dns and ntp servers + +--- + src/network/networkctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index 2a7a1daf0f..d6d2e1dd27 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -484,7 +484,7 @@ static int link_status(char **args, unsigned n) { + if (!strv_isempty(domains)) + dump_list(" Domain: ", domains); + +- sd_network_get_dns(&ntp); ++ sd_network_get_ntp(&ntp); + if (!strv_isempty(ntp)) + dump_list(" NTP: ", ntp); + diff --git a/0102-update-TODO.patch b/0102-update-TODO.patch new file mode 100644 index 0000000..1d2a1b2 --- /dev/null +++ b/0102-update-TODO.patch @@ -0,0 +1,22 @@ +From 202aea456dfb279cd34da7bfd1880f6ac0fd849f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 28 Aug 2014 20:23:52 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/TODO b/TODO +index a00c13dab2..59555e6cba 100644 +--- a/TODO ++++ b/TODO +@@ -24,6 +24,8 @@ External: + + Features: + ++* maybe add "systemctl edit" that copies unit files from /usr/lib/systemd/system to /etc/systemd/system and invokes vim on them ++ + * dbus: add new message hdr field for allowing interactive auth, write spec for it. update dbus spec to mandate that unknown flags *must* be ignored... + + * maybe introduce AssertXYZ= similar to ConditionXYZ= that causes a unit to fail (instead of skipping it) if some condition is not true... diff --git a/0103-hibernate-resume-refuse-to-run-outside-of-an-initrd.patch b/0103-hibernate-resume-refuse-to-run-outside-of-an-initrd.patch new file mode 100644 index 0000000..c89bc4d --- /dev/null +++ b/0103-hibernate-resume-refuse-to-run-outside-of-an-initrd.patch @@ -0,0 +1,24 @@ +From ac528e3e3b93981cc9692250556b113acce7eb17 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 28 Aug 2014 20:24:12 +0200 +Subject: [PATCH] hibernate-resume: refuse to run outside of an initrd + +--- + src/hibernate-resume/hibernate-resume.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c +index 8f68f81f9e..b234a0b49a 100644 +--- a/src/hibernate-resume/hibernate-resume.c ++++ b/src/hibernate-resume/hibernate-resume.c +@@ -46,6 +46,10 @@ int main(int argc, char *argv[]) { + + umask(0022); + ++ /* Refuse to run unless we are in an initrd() */ ++ if (!in_initrd()) ++ return EXIT_SUCCESS; ++ + device = argv[1]; + + if (stat(device, &st) < 0) { diff --git a/0104-sd-rtnl-log-if-kernel-buffer-is-overrun-as-we-curren.patch b/0104-sd-rtnl-log-if-kernel-buffer-is-overrun-as-we-curren.patch new file mode 100644 index 0000000..f6a1c14 --- /dev/null +++ b/0104-sd-rtnl-log-if-kernel-buffer-is-overrun-as-we-curren.patch @@ -0,0 +1,30 @@ +From 5968b1c304188e466759b8ba419fc10f150e5541 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 28 Aug 2014 15:59:13 +0200 +Subject: [PATCH] sd-rtnl: log if kernel buffer is overrun as we currently + can't handle that case + +--- + src/libsystemd/sd-rtnl/rtnl-message.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c +index 1f596ca10c..906a9de1c0 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-message.c ++++ b/src/libsystemd/sd-rtnl/rtnl-message.c +@@ -1132,10 +1132,13 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool + assert(iov); + + r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0)); +- if (r < 0) ++ if (r < 0) { + /* no data */ ++ if (errno == ENOBUFS) ++ log_debug("rtnl: kernel receive buffer overrun"); ++ + return (errno == EAGAIN) ? 0 : -errno; +- else if (r == 0) ++ } else if (r == 0) + /* connection was closed by the kernel */ + return -ECONNRESET; + diff --git a/0105-sd-event-allow-naming-event-sources.patch b/0105-sd-event-allow-naming-event-sources.patch new file mode 100644 index 0000000..2ed766e --- /dev/null +++ b/0105-sd-event-allow-naming-event-sources.patch @@ -0,0 +1,91 @@ +From f7f53e9e6ebb9f656d880f5e779fc174a1d983bf Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 28 Aug 2014 15:47:39 +0200 +Subject: [PATCH] sd-event: allow naming event sources + +--- + src/libsystemd/libsystemd.sym.m4 | 2 ++ + src/libsystemd/sd-event/sd-event.c | 29 +++++++++++++++++++++++++++++ + src/systemd/sd-event.h | 2 ++ + 3 files changed, 33 insertions(+) + +diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 +index 3fc9983f98..d1450fbb26 100644 +--- a/src/libsystemd/libsystemd.sym.m4 ++++ b/src/libsystemd/libsystemd.sym.m4 +@@ -382,6 +382,8 @@ global: + sd_event_get_watchdog; + sd_event_source_ref; + sd_event_source_unref; ++ sd_event_source_set_name; ++ sd_event_source_get_name; + sd_event_source_set_prepare; + sd_event_source_get_pending; + sd_event_source_get_priority; +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 32777e386b..a2935abd64 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -66,6 +66,8 @@ struct sd_event_source { + void *userdata; + sd_event_handler_t prepare; + ++ char *name; ++ + EventSourceType type:5; + int enabled:3; + bool pending:1; +@@ -685,6 +687,7 @@ static void source_free(sd_event_source *s) { + assert(s); + + source_disconnect(s); ++ free(s->name); + free(s); + } + +@@ -1223,6 +1226,32 @@ _public_ sd_event_source* sd_event_source_unref(sd_event_source *s) { + return NULL; + } + ++_public_ int sd_event_source_set_name(sd_event_source *s, const char *name) { ++ char *new_name = NULL; ++ ++ assert_return(s, -EINVAL); ++ ++ if (name) { ++ new_name = strdup(name); ++ if (!new_name) ++ return -ENOMEM; ++ } ++ ++ free(s->name); ++ s->name = new_name; ++ ++ return 0; ++} ++ ++_public_ int sd_event_source_get_name(sd_event_source *s, const char **name) { ++ assert_return(s, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ *name = s->name; ++ ++ return 0; ++} ++ + _public_ sd_event *sd_event_source_get_event(sd_event_source *s) { + assert_return(s, NULL); + +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index 8e013b33f6..0dbdcdf2a5 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -109,6 +109,8 @@ sd_event *sd_event_source_get_event(sd_event_source *s); + void* sd_event_source_get_userdata(sd_event_source *s); + void* sd_event_source_set_userdata(sd_event_source *s, void *userdata); + ++int sd_event_source_set_name(sd_event_source *s, const char *name); ++int sd_event_source_get_name(sd_event_source *s, const char **name); + int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback); + int sd_event_source_get_pending(sd_event_source *s); + int sd_event_source_get_priority(sd_event_source *s, int64_t *priority); diff --git a/0106-sd-event-use-event-source-name-rather-than-address-i.patch b/0106-sd-event-use-event-source-name-rather-than-address-i.patch new file mode 100644 index 0000000..93fa1a3 --- /dev/null +++ b/0106-sd-event-use-event-source-name-rather-than-address-i.patch @@ -0,0 +1,44 @@ +From 752bbf75b9b52c0faae29bb4b77a99c4bb0d298f Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 28 Aug 2014 15:48:07 +0200 +Subject: [PATCH] sd-event: use event source name rather than address in debug + messages + +--- + src/libsystemd/sd-event/sd-event.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index a2935abd64..c92e065c76 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2112,8 +2112,12 @@ static int source_dispatch(sd_event_source *s) { + + s->dispatching = false; + +- if (r < 0) +- log_debug("Event source %p returned error, disabling: %s", s, strerror(-r)); ++ if (r < 0) { ++ if (s->name) ++ log_debug("Event source '%s' returned error, disabling: %s", s->name, strerror(-r)); ++ else ++ log_debug("Event source %p returned error, disabling: %s", s, strerror(-r)); ++ } + + if (s->n_ref == 0) + source_free(s); +@@ -2146,8 +2150,12 @@ static int event_prepare(sd_event *e) { + r = s->prepare(s, s->userdata); + s->dispatching = false; + +- if (r < 0) +- log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r)); ++ if (r < 0) { ++ if (s->name) ++ log_debug("Prepare callback of event source '%s' returned error, disabling: %s", s->name, strerror(-r)); ++ else ++ log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r)); ++ } + + if (s->n_ref == 0) + source_free(s); diff --git a/0107-sd-event-name-event-sources-used-in-libraries.patch b/0107-sd-event-name-event-sources-used-in-libraries.patch new file mode 100644 index 0000000..14f5344 --- /dev/null +++ b/0107-sd-event-name-event-sources-used-in-libraries.patch @@ -0,0 +1,349 @@ +From 9021bb9f935c93b516b10c88db2a212a9e3a8140 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 28 Aug 2014 15:46:29 +0200 +Subject: [PATCH] sd-event: name event sources used in libraries + +This should help in debugging failing event sources. +--- + src/libsystemd-network/sd-dhcp-client.c | 35 ++++++++++++++++++++++++++++++++ + src/libsystemd-network/sd-dhcp6-client.c | 30 +++++++++++++++++++++++++++ + src/libsystemd-network/sd-icmp6-nd.c | 13 ++++++++++++ + src/libsystemd-network/sd-ipv4ll.c | 11 ++++++++++ + src/libsystemd/sd-bus/sd-bus.c | 16 +++++++++++++++ + src/libsystemd/sd-rtnl/sd-rtnl.c | 12 +++++++++++ + src/network/networkd-manager.c | 4 ++++ + 7 files changed, 121 insertions(+) + +diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c +index 8a9887d19f..7cf1b80d29 100644 +--- a/src/libsystemd-network/sd-dhcp-client.c ++++ b/src/libsystemd-network/sd-dhcp-client.c +@@ -700,6 +700,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, + if (r < 0) + goto error; + ++ r = sd_event_source_set_name(client->timeout_resend, ++ "dhcp4-resend-timer"); ++ if (r < 0) ++ goto error; ++ + switch (client->state) { + case DHCP_STATE_INIT: + r = client_send_discover(client); +@@ -773,6 +778,11 @@ static int client_initialize_io_events(sd_dhcp_client *client, + if (r < 0) + goto error; + ++ r = sd_event_source_set_name(client->receive_message, ++ "dhcp4-receive-message"); ++ if (r < 0) ++ goto error; ++ + error: + if (r < 0) + client_stop(client, r); +@@ -799,6 +809,11 @@ static int client_initialize_time_events(sd_dhcp_client *client) { + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + ++ r = sd_event_source_set_name(client->timeout_resend, ++ "dhcp4-resend-timer"); ++ if (r < 0) ++ goto error; ++ + error: + if (r < 0) + client_stop(client, r); +@@ -1107,6 +1122,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { + if (r < 0) + return r; + ++ r = sd_event_source_set_name(client->timeout_expire, ++ "dhcp4-lifetime"); ++ if (r < 0) ++ return r; ++ + log_dhcp_client(client, "lease expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, + lifetime_timeout - time_now, 0)); +@@ -1130,6 +1150,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { + if (r < 0) + return r; + ++ r = sd_event_source_set_name(client->timeout_t2, ++ "dhcp4-t2-timeout"); ++ if (r < 0) ++ return r; ++ + log_dhcp_client(client, "T2 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, + t2_timeout - time_now, 0)); +@@ -1152,6 +1177,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { + if (r < 0) + return r; + ++ r = sd_event_source_set_name(client->timeout_t1, ++ "dhcp4-t1-timer"); ++ if (r < 0) ++ return r; ++ + log_dhcp_client(client, "T1 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, + t1_timeout - time_now, 0)); +@@ -1192,6 +1222,11 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, + client->event_priority); + if (r < 0) + goto error; ++ ++ r = sd_event_source_set_name(client->timeout_resend, ++ "dhcp4-resend-timer"); ++ if (r < 0) ++ goto error; + } else if (r == -ENOMSG) + /* invalid message, let's ignore it */ + return 0; +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index f69c0ed8a6..342a231413 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -496,6 +496,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, + if (r < 0) + goto error; + ++ r = sd_event_source_set_name(client->timeout_resend, ++ "dhcp6-resend-timer"); ++ if (r < 0) ++ goto error; ++ + if (max_retransmit_duration && !client->timeout_resend_expire) { + + log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs", +@@ -514,6 +519,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, + client->event_priority); + if (r < 0) + goto error; ++ ++ r = sd_event_source_set_name(client->timeout_resend_expire, ++ "dhcp6-resend-expire-timer"); ++ if (r < 0) ++ goto error; + } + + error: +@@ -894,6 +904,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) + if (r < 0) + return r; + ++ r = sd_event_source_set_name(client->receive_message, ++ "dhcp6-receive-message"); ++ if (r < 0) ++ return r; ++ + client->state = DHCP6_STATE_SOLICITATION; + + break; +@@ -942,6 +957,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) + if (r < 0) + return r; + ++ r = sd_event_source_set_name(client->lease->ia.timeout_t1, ++ "dhcp6-t1-timeout"); ++ if (r < 0) ++ return r; ++ + timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); + + log_dhcp6_client(client, "T2 expires in %s", +@@ -962,6 +982,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) + if (r < 0) + return r; + ++ r = sd_event_source_set_name(client->lease->ia.timeout_t2, ++ "dhcp6-t2-timeout"); ++ if (r < 0) ++ return r; ++ + client->state = state; + + return 0; +@@ -980,6 +1005,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) + if (r < 0) + return r; + ++ r = sd_event_source_set_name(client->timeout_resend, ++ "dhcp6-resend-timeout"); ++ if (r < 0) ++ return r; ++ + return 0; + } + +diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c +index b264e793ee..243f06a85f 100644 +--- a/src/libsystemd-network/sd-icmp6-nd.c ++++ b/src/libsystemd-network/sd-icmp6-nd.c +@@ -277,6 +277,12 @@ static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, + icmp6_nd_notify(nd, r); + return 0; + } ++ ++ r = sd_event_source_set_name(nd->timeout, "icmp6-timeout"); ++ if (r < 0) { ++ icmp6_nd_notify(nd, r); ++ return 0; ++ } + } + + return 0; +@@ -322,13 +328,20 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) { + if (r < 0) + goto error; + ++ r = sd_event_source_set_name(nd->recv, "icmp6-receive-message"); ++ if (r < 0) ++ goto error; ++ + r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), + 0, 0, icmp6_router_solicitation_timeout, nd); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(nd->timeout, nd->event_priority); ++ if (r < 0) ++ goto error; + ++ r = sd_event_source_set_name(nd->timeout, "icmp6-timeout"); + error: + if (r < 0) + icmp6_nd_init(nd); +diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c +index b17987904a..3d15fc85ea 100644 +--- a/src/libsystemd-network/sd-ipv4ll.c ++++ b/src/libsystemd-network/sd-ipv4ll.c +@@ -352,6 +352,10 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void + r = sd_event_source_set_priority(ll->timer, ll->event_priority); + if (r < 0) + goto out; ++ ++ r = sd_event_source_set_name(ll->timer, "ipv4ll-timer"); ++ if (r < 0) ++ goto out; + } + + out: +@@ -560,6 +564,10 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { + if (r < 0) + goto out; + ++ r = sd_event_source_set_name(ll->timer, "ipv4ll-receive-message"); ++ if (r < 0) ++ goto out; ++ + r = sd_event_add_time(ll->event, + &ll->timer, + clock_boottime_or_monotonic(), +@@ -570,7 +578,10 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { + goto out; + + r = sd_event_source_set_priority(ll->timer, ll->event_priority); ++ if (r < 0) ++ goto out; + ++ r = sd_event_source_set_name(ll->timer, "ipv4ll-timer"); + out: + if (r < 0) + ipv4ll_stop(ll, IPV4LL_EVENT_STOP); +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 8caa404227..78e91b9654 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -3013,6 +3013,10 @@ static int attach_io_events(sd_bus *bus) { + return r; + + r = sd_event_source_set_priority(bus->input_io_event_source, bus->event_priority); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_source_set_name(bus->input_io_event_source, "bus-input"); + } else + r = sd_event_source_set_io_fd(bus->input_io_event_source, bus->input_fd); + +@@ -3028,6 +3032,10 @@ static int attach_io_events(sd_bus *bus) { + return r; + + r = sd_event_source_set_priority(bus->output_io_event_source, bus->event_priority); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_source_set_name(bus->input_io_event_source, "bus-output"); + } else + r = sd_event_source_set_io_fd(bus->output_io_event_source, bus->output_fd); + +@@ -3080,10 +3088,18 @@ _public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) { + if (r < 0) + goto fail; + ++ r = sd_event_source_set_name(bus->time_event_source, "bus-time"); ++ if (r < 0) ++ goto fail; ++ + r = sd_event_add_exit(bus->event, &bus->quit_event_source, quit_callback, bus); + if (r < 0) + goto fail; + ++ r = sd_event_source_set_name(bus->quit_event_source, "bus-exit"); ++ if (r < 0) ++ goto fail; ++ + r = attach_io_events(bus); + if (r < 0) + goto fail; +diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c +index c19bad1bc9..f883f2842c 100644 +--- a/src/libsystemd/sd-rtnl/sd-rtnl.c ++++ b/src/libsystemd/sd-rtnl/sd-rtnl.c +@@ -859,6 +859,10 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) { + if (r < 0) + goto fail; + ++ r = sd_event_source_set_name(rtnl->io_event_source, "rtnl-receive-message"); ++ if (r < 0) ++ goto fail; ++ + r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback); + if (r < 0) + goto fail; +@@ -871,10 +875,18 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) { + if (r < 0) + goto fail; + ++ r = sd_event_source_set_name(rtnl->time_event_source, "rtnl-timer"); ++ if (r < 0) ++ goto fail; ++ + r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl); + if (r < 0) + goto fail; + ++ r = sd_event_source_set_name(rtnl->exit_event_source, "rtnl-exit"); ++ if (r < 0) ++ goto fail; ++ + return 0; + + fail: +diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c +index f2fe5d5443..5a4f93a06b 100644 +--- a/src/network/networkd-manager.c ++++ b/src/network/networkd-manager.c +@@ -370,6 +370,10 @@ int manager_udev_listen(Manager *m) { + if (r < 0) + return r; + ++ r = sd_event_source_set_name(m->udev_event_source, "networkd-udev"); ++ if (r < 0) ++ return r; ++ + return 0; + } + diff --git a/0108-sd-event-simplify-sd_event_source_set_name.patch b/0108-sd-event-simplify-sd_event_source_set_name.patch new file mode 100644 index 0000000..c11678e --- /dev/null +++ b/0108-sd-event-simplify-sd_event_source_set_name.patch @@ -0,0 +1,37 @@ +From 32b13b2f58b916ea22626e89cdd8cdb70ca6b6c9 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 28 Aug 2014 22:44:28 +0200 +Subject: [PATCH] sd-event: simplify sd_event_source_set_name() + +free_and_strdup() does exactly the same as sd_event_source_set_name(), use +it! +--- + src/libsystemd/sd-event/sd-event.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index c92e065c76..985ff2829b 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -1227,20 +1227,9 @@ _public_ sd_event_source* sd_event_source_unref(sd_event_source *s) { + } + + _public_ int sd_event_source_set_name(sd_event_source *s, const char *name) { +- char *new_name = NULL; +- + assert_return(s, -EINVAL); + +- if (name) { +- new_name = strdup(name); +- if (!new_name) +- return -ENOMEM; +- } +- +- free(s->name); +- s->name = new_name; +- +- return 0; ++ return free_and_strdup(&s->name, name); + } + + _public_ int sd_event_source_get_name(sd_event_source *s, const char **name) { diff --git a/0109-systemd-firstboot.service-fix-man-page-section.patch b/0109-systemd-firstboot.service-fix-man-page-section.patch new file mode 100644 index 0000000..61c777e --- /dev/null +++ b/0109-systemd-firstboot.service-fix-man-page-section.patch @@ -0,0 +1,23 @@ +From 47542dc8b6f1a85de9968d028cacfb1065979e7c Mon Sep 17 00:00:00 2001 +From: Marius Tessmann +Date: Thu, 28 Aug 2014 22:01:44 +0200 +Subject: [PATCH] systemd-firstboot.service: fix man page section + +Found with systemd-analyze verify. +--- + units/systemd-firstboot.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/systemd-firstboot.service.in b/units/systemd-firstboot.service.in +index a8719a8c7f..6cdde5b82d 100644 +--- a/units/systemd-firstboot.service.in ++++ b/units/systemd-firstboot.service.in +@@ -7,7 +7,7 @@ + + [Unit] + Description=First Boot Wizard +-Documentation=man:systemd-firstboot(8) ++Documentation=man:systemd-firstboot(1) + DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service systemd-sysusers.service diff --git a/0110-systemd-firstboot-fix-typo-in-man-page.patch b/0110-systemd-firstboot-fix-typo-in-man-page.patch new file mode 100644 index 0000000..92caa0c --- /dev/null +++ b/0110-systemd-firstboot-fix-typo-in-man-page.patch @@ -0,0 +1,22 @@ +From c32e70aa8ea5431c881553c6c609cef5536c4e65 Mon Sep 17 00:00:00 2001 +From: Marius Tessmann +Date: Thu, 28 Aug 2014 22:01:45 +0200 +Subject: [PATCH] systemd-firstboot: fix typo in man page + +--- + man/systemd-firstboot.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml +index 5da0a75040..8d97302244 100644 +--- a/man/systemd-firstboot.xml ++++ b/man/systemd-firstboot.xml +@@ -101,7 +101,7 @@ + allows systemd-firstboot to operate + on mounted but not booted disk images and in early + boot. It is not recommended to use +- systemd-firsboot on the running ++ systemd-firstboot on the running + system while it is up. + + diff --git a/0111-systemd-journal-upload-fix-invalid-After.patch b/0111-systemd-journal-upload-fix-invalid-After.patch new file mode 100644 index 0000000..7fe27e3 --- /dev/null +++ b/0111-systemd-journal-upload-fix-invalid-After.patch @@ -0,0 +1,28 @@ +From fd5ab841e7582342b23c9c08ba24ce0cca266690 Mon Sep 17 00:00:00 2001 +From: Marius Tessmann +Date: Thu, 28 Aug 2014 22:01:46 +0200 +Subject: [PATCH] systemd-journal-upload: fix invalid After= + +After= belongs into [Unit], not [Install]. Found with systemd-analyze +verify. +--- + units/systemd-journal-upload.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/systemd-journal-upload.service.in b/units/systemd-journal-upload.service.in +index e79f962043..359ff10e25 100644 +--- a/units/systemd-journal-upload.service.in ++++ b/units/systemd-journal-upload.service.in +@@ -7,6 +7,7 @@ + + [Unit] + Description=Journal Remote Upload Service ++After=network.target + + [Service] + ExecStart=@rootlibexecdir@/systemd-journal-upload \ +@@ -18,4 +19,3 @@ WatchdogSec=20min + + [Install] + WantedBy=multi-user.target +-After=network.target diff --git a/0112-Fix-a-few-typos-in-log-messages.patch b/0112-Fix-a-few-typos-in-log-messages.patch new file mode 100644 index 0000000..2002883 --- /dev/null +++ b/0112-Fix-a-few-typos-in-log-messages.patch @@ -0,0 +1,81 @@ +From 6ff8806e1d20a4d3cbc4b360326ea3786768f0ca Mon Sep 17 00:00:00 2001 +From: Ruben Kerkhof +Date: Fri, 29 Aug 2014 13:28:04 +0200 +Subject: [PATCH] Fix a few typos in log messages + +--- + src/libsystemd-network/sd-dhcp-client.c | 12 ++++++------ + src/libsystemd/sd-rtnl/sd-rtnl.c | 2 +- + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c +index 7cf1b80d29..2f94c16078 100644 +--- a/src/libsystemd-network/sd-dhcp-client.c ++++ b/src/libsystemd-network/sd-dhcp-client.c +@@ -919,7 +919,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, + + r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); + if (r != DHCP_OFFER) { +- log_dhcp_client(client, "receieved message was not an OFFER, ignoring"); ++ log_dhcp_client(client, "received message was not an OFFER, ignoring"); + return -ENOMSG; + } + +@@ -930,7 +930,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, + if (lease->address == INADDR_ANY || + lease->server_address == INADDR_ANY || + lease->lifetime == 0) { +- log_dhcp_client(client, "receieved lease lacks address, server " ++ log_dhcp_client(client, "received lease lacks address, server " + "address or lease lifetime, ignoring"); + return -ENOMSG; + } +@@ -938,7 +938,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, + if (lease->subnet_mask == INADDR_ANY) { + r = dhcp_lease_set_default_subnet_mask(lease); + if (r < 0) { +- log_dhcp_client(client, "receieved lease lacks subnet " ++ log_dhcp_client(client, "received lease lacks subnet " + "mask, and a fallback one can not be " + "generated, ignoring"); + return -ENOMSG; +@@ -983,7 +983,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, + } + + if (r != DHCP_ACK) { +- log_dhcp_client(client, "receieved message was not an ACK, ignoring"); ++ log_dhcp_client(client, "received message was not an ACK, ignoring"); + return -ENOMSG; + } + +@@ -994,7 +994,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, + if (lease->address == INADDR_ANY || + lease->server_address == INADDR_ANY || + lease->lifetime == 0) { +- log_dhcp_client(client, "receieved lease lacks address, server " ++ log_dhcp_client(client, "received lease lacks address, server " + "address or lease lifetime, ignoring"); + return -ENOMSG; + } +@@ -1002,7 +1002,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, + if (lease->subnet_mask == INADDR_ANY) { + r = dhcp_lease_set_default_subnet_mask(lease); + if (r < 0) { +- log_dhcp_client(client, "receieved lease lacks subnet " ++ log_dhcp_client(client, "received lease lacks subnet " + "mask, and a fallback one can not be " + "generated, ignoring"); + return -ENOMSG; +diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c +index f883f2842c..a3f314b95b 100644 +--- a/src/libsystemd/sd-rtnl/sd-rtnl.c ++++ b/src/libsystemd/sd-rtnl/sd-rtnl.c +@@ -680,7 +680,7 @@ int sd_rtnl_call(sd_rtnl *rtnl, + if (r < 0) + return r; + if (r > 0) +- /* receieved message, so try to process straight away */ ++ /* received message, so try to process straight away */ + continue; + + if (timeout > 0) { diff --git a/0113-timesyncd-check-if-stratum-is-valid.patch b/0113-timesyncd-check-if-stratum-is-valid.patch new file mode 100644 index 0000000..17ac17c --- /dev/null +++ b/0113-timesyncd-check-if-stratum-is-valid.patch @@ -0,0 +1,23 @@ +From 07610e108e2d3f046da683a3a69c4d5cccd2cf8e Mon Sep 17 00:00:00 2001 +From: Miroslav Lichvar +Date: Wed, 27 Aug 2014 16:47:17 +0200 +Subject: [PATCH] timesyncd: check if stratum is valid + +--- + src/timesync/timesyncd-manager.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index d80c72ff5c..60f39c638d 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -574,7 +574,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + return manager_connect(m); + } + +- if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC) { ++ if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC || ++ ntpmsg.stratum == 0 || ntpmsg.stratum >= 16) { + log_debug("Server is not synchronized. Disconnecting."); + return manager_connect(m); + } diff --git a/0114-timesyncd-fix-calculation-of-transmit-time.patch b/0114-timesyncd-fix-calculation-of-transmit-time.patch new file mode 100644 index 0000000..4e817db --- /dev/null +++ b/0114-timesyncd-fix-calculation-of-transmit-time.patch @@ -0,0 +1,33 @@ +From 73c76e6330d31e1d04454fd7408dd56b4eedca9f Mon Sep 17 00:00:00 2001 +From: Miroslav Lichvar +Date: Wed, 27 Aug 2014 16:47:18 +0200 +Subject: [PATCH] timesyncd: fix calculation of transmit time + +The kernel timestamp (recv_time) is made earlier than current time +(now_ts), use the timestamp captured before sending packet directly. +--- + src/timesync/timesyncd-manager.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 60f39c638d..333960669c 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -500,7 +500,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + .msg_namelen = sizeof(server_addr), + }; + struct cmsghdr *cmsg; +- struct timespec now_ts; + struct timeval *recv_time; + ssize_t len; + double origin, receive, trans, dest; +@@ -613,8 +612,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + * The round-trip delay, d, and system clock offset, t, are defined as: + * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2" + */ +- assert_se(clock_gettime(clock_boottime_or_monotonic(), &now_ts) >= 0); +- origin = tv_to_d(recv_time) - (ts_to_d(&now_ts) - ts_to_d(&m->trans_time_mon)) + OFFSET_1900_1970; ++ origin = ts_to_d(&m->trans_time) + OFFSET_1900_1970; + receive = ntp_ts_to_d(&ntpmsg.recv_time); + trans = ntp_ts_to_d(&ntpmsg.trans_time); + dest = tv_to_d(recv_time) + OFFSET_1900_1970; diff --git a/0115-timesyncd-get-kernel-timestamp-in-nanoseconds.patch b/0115-timesyncd-get-kernel-timestamp-in-nanoseconds.patch new file mode 100644 index 0000000..0096750 --- /dev/null +++ b/0115-timesyncd-get-kernel-timestamp-in-nanoseconds.patch @@ -0,0 +1,62 @@ +From 487a36821ea214a73e1d0dcbd6d84123b50d1135 Mon Sep 17 00:00:00 2001 +From: Miroslav Lichvar +Date: Wed, 27 Aug 2014 16:47:19 +0200 +Subject: [PATCH] timesyncd: get kernel timestamp in nanoseconds + +--- + src/timesync/timesyncd-manager.c | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 333960669c..2b0580cf01 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -136,10 +136,6 @@ static double ts_to_d(const struct timespec *ts) { + return ts->tv_sec + (1.0e-9 * ts->tv_nsec); + } + +-static double tv_to_d(const struct timeval *tv) { +- return tv->tv_sec + (1.0e-6 * tv->tv_usec); +-} +- + static double square(double d) { + return d * d; + } +@@ -500,7 +496,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + .msg_namelen = sizeof(server_addr), + }; + struct cmsghdr *cmsg; +- struct timeval *recv_time; ++ struct timespec *recv_time; + ssize_t len; + double origin, receive, trans, dest; + double delay, offset; +@@ -543,8 +539,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + continue; + + switch (cmsg->cmsg_type) { +- case SCM_TIMESTAMP: +- recv_time = (struct timeval *) CMSG_DATA(cmsg); ++ case SCM_TIMESTAMPNS: ++ recv_time = (struct timespec *) CMSG_DATA(cmsg); + break; + } + } +@@ -615,7 +611,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + origin = ts_to_d(&m->trans_time) + OFFSET_1900_1970; + receive = ntp_ts_to_d(&ntpmsg.recv_time); + trans = ntp_ts_to_d(&ntpmsg.trans_time); +- dest = tv_to_d(recv_time) + OFFSET_1900_1970; ++ dest = ts_to_d(recv_time) + OFFSET_1900_1970; + + offset = ((receive - origin) + (trans - dest)) / 2; + delay = (dest - origin) - (trans - receive); +@@ -697,7 +693,7 @@ static int manager_listen_setup(Manager *m) { + if (r < 0) + return -errno; + +- r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)); ++ r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMPNS, &on, sizeof(on)); + if (r < 0) + return -errno; + diff --git a/0116-timesyncd-check-root-distance.patch b/0116-timesyncd-check-root-distance.patch new file mode 100644 index 0000000..4d1816d --- /dev/null +++ b/0116-timesyncd-check-root-distance.patch @@ -0,0 +1,77 @@ +From 3af0442c52090f34ae7a1c8e6b6587c540c06896 Mon Sep 17 00:00:00 2001 +From: Miroslav Lichvar +Date: Wed, 27 Aug 2014 16:47:20 +0200 +Subject: [PATCH] timesyncd: check root distance + +NTPv4 servers don't reply with unsynchronized status when they lost +synchronization, they only keep increasing the root dispersion and it's +up to the client to decide at which point they no longer consider it +synchronized. + +Ignore replies with root distance over 5 seconds. +--- + src/timesync/timesyncd-manager.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 2b0580cf01..9b8b7d3eb6 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -89,6 +89,9 @@ + #define NTP_FIELD_MODE(f) ((f) & 7) + #define NTP_FIELD(l, v, m) (((l) << 6) | ((v) << 3) | (m)) + ++/* Maximum acceptable root distance in seconds. */ ++#define NTP_MAX_ROOT_DISTANCE 5.0 ++ + /* + * "NTP timestamps are represented as a 64-bit unsigned fixed-point number, + * in seconds relative to 0h on 1 January 1900." +@@ -128,6 +131,10 @@ struct ntp_msg { + static int manager_arm_timer(Manager *m, usec_t next); + static int manager_clock_watch_setup(Manager *m); + ++static double ntp_ts_short_to_d(const struct ntp_ts_short *ts) { ++ return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0); ++} ++ + static double ntp_ts_to_d(const struct ntp_ts *ts) { + return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX); + } +@@ -500,6 +507,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + ssize_t len; + double origin, receive, trans, dest; + double delay, offset; ++ double root_distance; + bool spike; + int leap_sec; + int r; +@@ -585,6 +593,12 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + return manager_connect(m); + } + ++ root_distance = ntp_ts_short_to_d(&ntpmsg.root_delay) / 2 + ntp_ts_short_to_d(&ntpmsg.root_dispersion); ++ if (root_distance > NTP_MAX_ROOT_DISTANCE) { ++ log_debug("Server has too large root distance. Disconnecting."); ++ return manager_connect(m); ++ } ++ + /* valid packet */ + m->pending = false; + m->retry_interval = 0; +@@ -626,6 +640,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + " mode : %u\n" + " stratum : %u\n" + " precision : %.6f sec (%d)\n" ++ " root distance: %.6f sec\n" + " reference : %.4s\n" + " origin : %.3f\n" + " receive : %.3f\n" +@@ -641,6 +656,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + NTP_FIELD_MODE(ntpmsg.field), + ntpmsg.stratum, + exp2(ntpmsg.precision), ntpmsg.precision, ++ root_distance, + ntpmsg.stratum == 1 ? ntpmsg.refid : "n/a", + origin - OFFSET_1900_1970, + receive - OFFSET_1900_1970, diff --git a/0117-Update-Russian-translation.patch b/0117-Update-Russian-translation.patch new file mode 100644 index 0000000..d251dc6 --- /dev/null +++ b/0117-Update-Russian-translation.patch @@ -0,0 +1,58 @@ +From f2e104d3e0c43e4efd7c1952065bd4b79eefa427 Mon Sep 17 00:00:00 2001 +From: Sergey Ptashnick <0comffdiz@inbox.ru> +Date: Fri, 29 Aug 2014 19:48:47 +0400 +Subject: [PATCH] Update Russian translation + +By analogy with commit 1977376274. +--- + po/ru.po | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/po/ru.po b/po/ru.po +index 1ad4efb2e3..de283f7ff6 100644 +--- a/po/ru.po ++++ b/po/ru.po +@@ -1,13 +1,13 @@ + # translation of ru.po to Rissian + # Julia Dronova , 2013. +-# Sergey Ptashnick <0comffdiz@inbox.ru>, 2013. ++# Sergey Ptashnick <0comffdiz@inbox.ru>, 2013-2014. + # + msgid "" + msgstr "" + "Project-Id-Version: systemd\n" + "Report-Msgid-Bugs-To: 0comffdiz@inbox.ru\n" + "POT-Creation-Date: 2013-03-24 19:22+0300\n" +-"PO-Revision-Date: 2013-11-18 02:18+0400\n" ++"PO-Revision-Date: 2014-08-29 19:29+0400\n" + "Last-Translator: Sergey Ptashnick <0comffdiz@inbox.ru>\n" + "Language: ru\n" + "MIME-Version: 1.0\n" +@@ -293,3 +293,27 @@ msgstr "Привилегированный доступ к системному + #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 + msgid "Authentication is required to access the system and service manager." + msgstr "Для привилегированного доступа к системному менеджеру необходимо пройти аутентификацию." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5 ++msgid "Manage system services or units" ++msgstr "Управление системными службами и юнитами" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6 ++msgid "Authentication is required to manage system services or units." ++msgstr "Для управления системными службами и юнитами, необходимо пройти аутентификацию." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7 ++msgid "Manage system service or unit files" ++msgstr "Управление файлами конфигурации системных служб и юнитов" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8 ++msgid "Authentication is required to manage system service or unit files." ++msgstr "Для управления файлами конфигурации системных служб и юнитов, необходимо пройти аутентификацию." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9 ++msgid "Reload the systemd state" ++msgstr "Перечитать конфигурацию systemd" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10 ++msgid "Authentication is required to reload the systemd state." ++msgstr "Чтобы заставить systemd перечитать конфигурацию, необходимо пройти аутентификацию." diff --git a/0118-completion-filter-templates-from-restartable-units.patch b/0118-completion-filter-templates-from-restartable-units.patch new file mode 100644 index 0000000..d9bd47c --- /dev/null +++ b/0118-completion-filter-templates-from-restartable-units.patch @@ -0,0 +1,27 @@ +From ec15977a3cd82eff6c94bb13db72195f7cd512e8 Mon Sep 17 00:00:00 2001 +From: Dave Reisner +Date: Fri, 29 Aug 2014 20:35:15 -0400 +Subject: [PATCH] completion: filter templates from restartable units + +Since c6a373a2634854, we might encounter unit templates via the +'list-units' verb. These aren't restartable (and we throw errors), so +make sure they're filtered out of the completion options. + +fixes downstream bug: https://bugs.archlinux.org/task/41719 +--- + 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 64b15df462..015001815f 100644 +--- a/shell-completion/bash/systemctl.in ++++ b/shell-completion/bash/systemctl.in +@@ -182,7 +182,7 @@ _systemctl () { + comps=$( __filter_units_by_property $mode CanStart yes \ + $( __get_all_units $mode \ + | while read -r line; do \ +- [[ "$line" =~ \.(device|snapshot|socket|timer)$ ]] || echo " $line"; \ ++ [[ "$line" =~ @\.|\.(device|snapshot|socket|timer)$ ]] || echo " $line"; \ + done )) + compopt -o filenames + diff --git a/0119-udev-remove-userspace-firmware-loading-support.patch b/0119-udev-remove-userspace-firmware-loading-support.patch new file mode 100644 index 0000000..25d1fe6 --- /dev/null +++ b/0119-udev-remove-userspace-firmware-loading-support.patch @@ -0,0 +1,358 @@ +From be2ea723b1d023b3d385d3b791ee4607cbfb20ca Mon Sep 17 00:00:00 2001 +From: Kay Sievers +Date: Sat, 30 Aug 2014 11:34:20 +0200 +Subject: [PATCH] udev: remove userspace firmware loading support + +--- + Makefile.am | 12 --- + README | 9 +-- + TODO | 1 - + configure.ac | 20 ----- + src/udev/udev-builtin-firmware.c | 154 --------------------------------------- + src/udev/udev-builtin.c | 3 - + src/udev/udev.h | 6 -- + src/udev/udevd.c | 13 ---- + 8 files changed, 4 insertions(+), 214 deletions(-) + delete mode 100644 src/udev/udev-builtin-firmware.c + +diff --git a/Makefile.am b/Makefile.am +index 1facb8da43..b37ed41554 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3284,18 +3284,6 @@ libudev_core_la_LIBADD = \ + $(BLKID_LIBS) \ + $(KMOD_LIBS) + +-libudev_core_la_CPPFLAGS = \ +- $(AM_CPPFLAGS) \ +- -DFIRMWARE_PATH="$(FIRMWARE_PATH)" +- +-if ENABLE_FIRMWARE +-libudev_core_la_SOURCES += \ +- src/udev/udev-builtin-firmware.c +- +-dist_udevrules_DATA += \ +- rules/50-firmware.rules +-endif +- + if HAVE_KMOD + libudev_core_la_SOURCES += \ + src/udev/udev-builtin-kmod.c +diff --git a/README b/README +index d47ea45671..e0edd41f17 100644 +--- a/README ++++ b/README +@@ -37,8 +37,7 @@ LICENSE: + - except src/udev/* which is (currently still) GPLv2, GPLv2+ + + REQUIREMENTS: +- Linux kernel >= 3.0 +- Linux kernel >= 3.3 for loop device partition support features with nspawn ++ Linux kernel >= 3.7 + Linux kernel >= 3.8 for Smack support + + Kernel Config Options: +@@ -53,14 +52,14 @@ REQUIREMENTS: + CONFIG_PROC_FS + CONFIG_FHANDLE (libudev, mount and bind mount handling) + +- Udev will fail to work with the legacy layout: ++ udev will fail to work with the legacy sysfs layout: + CONFIG_SYSFS_DEPRECATED=n + + Legacy hotplug slows down the system and confuses udev: + CONFIG_UEVENT_HELPER_PATH="" + +- Userspace firmware loading is deprecated, will go away, and +- sometimes causes problems: ++ Userspace firmware loading is not supported and should ++ be disabled in the kernel: + CONFIG_FW_LOADER_USER_HELPER=n + + Some udev rules and virtualization detection relies on it: +diff --git a/TODO b/TODO +index 59555e6cba..221b39f1a9 100644 +--- a/TODO ++++ b/TODO +@@ -547,7 +547,6 @@ Features: + * ExecOnFailure=/usr/bin/foo + + * udev: +- - remove src/udev/udev-builtin-firmware.c (CONFIG_FW_LOADER_USER_HELPER=n) + - move to LGPL + - kill scsi_id + - add trigger --subsystem-match=usb/usb_device device +diff --git a/configure.ac b/configure.ac +index a25ad3f2e2..543828c405 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1154,25 +1154,6 @@ fi + AM_CONDITIONAL(HAVE_MYHOSTNAME, [test "$have_myhostname" = "yes"]) + + # ------------------------------------------------------------------------------ +-AC_ARG_WITH(firmware-path, +- AS_HELP_STRING([--with-firmware-path=DIR[[[:DIR[...]]]]], +- [Firmware search path (default="")]), +- [], [with_firmware_path=""]) +-OLD_IFS=$IFS +-IFS=: +-for i in $with_firmware_path; do +- if test "x${FIRMWARE_PATH}" = "x"; then +- FIRMWARE_PATH="\\\"${i}/\\\"" +- else +- FIRMWARE_PATH="${FIRMWARE_PATH}, \\\"${i}/\\\"" +- fi +-done +-IFS=$OLD_IFS +-AC_SUBST(FIRMWARE_PATH) +-AS_IF([test "x${FIRMWARE_PATH}" != "x"], [ AC_DEFINE(HAVE_FIRMWARE, 1, [Define if FIRMWARE is available]) ]) +-AM_CONDITIONAL(ENABLE_FIRMWARE, [test "x${FIRMWARE_PATH}" != "x"]) +- +-# ------------------------------------------------------------------------------ + AC_ARG_ENABLE([gudev], + AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]), + [], [enable_gudev=yes]) +@@ -1409,7 +1390,6 @@ AC_MSG_RESULT([ + Build Python: ${PYTHON} + Installation Python: ${PYTHON_BINARY} + sphinx binary: ${SPHINX_BUILD} +- firmware path: ${FIRMWARE_PATH} + PAM modules dir: ${with_pamlibdir} + PAM configuration dir: ${with_pamconfdir} + D-Bus policy dir: ${with_dbuspolicydir} +diff --git a/src/udev/udev-builtin-firmware.c b/src/udev/udev-builtin-firmware.c +deleted file mode 100644 +index bd8c2fb966..0000000000 +--- a/src/udev/udev-builtin-firmware.c ++++ /dev/null +@@ -1,154 +0,0 @@ +-/* +- * firmware - Kernel firmware loader +- * +- * Copyright (C) 2009 Piter Punk +- * Copyright (C) 2009-2011 Kay Sievers +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation; either version 2 of the +- * License, or (at your option) any later version. +- * +- * This program 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 +- * General Public License for more details:* +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "udev.h" +- +-static bool set_loading(struct udev *udev, char *loadpath, const char *state) { +- FILE *ldfile; +- +- ldfile = fopen(loadpath, "we"); +- if (ldfile == NULL) { +- log_error("error: can not open '%s'", loadpath); +- return false; +- }; +- fprintf(ldfile, "%s\n", state); +- fclose(ldfile); +- return true; +-} +- +-static bool copy_firmware(struct udev *udev, const char *source, const char *target, size_t size) { +- char *buf; +- FILE *fsource = NULL, *ftarget = NULL; +- bool ret = false; +- +- buf = malloc(size); +- if (buf == NULL) { +- log_error("No memory available to load firmware file"); +- return false; +- } +- +- log_debug("writing '%s' (%zi) to '%s'", source, size, target); +- +- fsource = fopen(source, "re"); +- if (fsource == NULL) +- goto exit; +- ftarget = fopen(target, "we"); +- if (ftarget == NULL) +- goto exit; +- if (fread(buf, size, 1, fsource) != 1) +- goto exit; +- if (fwrite(buf, size, 1, ftarget) == 1) +- ret = true; +-exit: +- if (ftarget != NULL) +- fclose(ftarget); +- if (fsource != NULL) +- fclose(fsource); +- free(buf); +- return ret; +-} +- +-static int builtin_firmware(struct udev_device *dev, int argc, char *argv[], bool test) { +- struct udev *udev = udev_device_get_udev(dev); +- static const char *searchpath[] = { FIRMWARE_PATH }; +- char loadpath[UTIL_PATH_SIZE]; +- char datapath[UTIL_PATH_SIZE]; +- char fwpath[UTIL_PATH_SIZE]; +- const char *firmware; +- FILE *fwfile = NULL; +- struct utsname kernel; +- struct stat statbuf; +- unsigned int i; +- int rc = EXIT_SUCCESS; +- +- firmware = udev_device_get_property_value(dev, "FIRMWARE"); +- if (firmware == NULL) { +- log_error("firmware parameter missing"); +- rc = EXIT_FAILURE; +- goto exit; +- } +- +- /* lookup firmware file */ +- uname(&kernel); +- for (i = 0; i < ELEMENTSOF(searchpath); i++) { +- strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL); +- fwfile = fopen(fwpath, "re"); +- if (fwfile != NULL) +- break; +- +- strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL); +- fwfile = fopen(fwpath, "re"); +- if (fwfile != NULL) +- break; +- } +- +- strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL); +- +- if (fwfile == NULL) { +- log_debug("did not find firmware file '%s'", firmware); +- rc = EXIT_FAILURE; +- /* +- * Do not cancel the request in the initrd, the real root might have +- * the firmware file and the 'coldplug' run in the real root will find +- * this pending request and fulfill or cancel it. +- * */ +- if (!in_initrd()) +- set_loading(udev, loadpath, "-1"); +- goto exit; +- } +- +- if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) { +- if (!in_initrd()) +- set_loading(udev, loadpath, "-1"); +- rc = EXIT_FAILURE; +- goto exit; +- } +- +- if (!set_loading(udev, loadpath, "1")) +- goto exit; +- +- strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL); +- if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) { +- log_error("error sending firmware '%s' to device", firmware); +- set_loading(udev, loadpath, "-1"); +- rc = EXIT_FAILURE; +- goto exit; +- }; +- +- set_loading(udev, loadpath, "0"); +-exit: +- if (fwfile) +- fclose(fwfile); +- return rc; +-} +- +-const struct udev_builtin udev_builtin_firmware = { +- .name = "firmware", +- .cmd = builtin_firmware, +- .help = "kernel firmware loader", +- .run_once = true, +-}; +diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c +index 05a272646b..3bcbd6e828 100644 +--- a/src/udev/udev-builtin.c ++++ b/src/udev/udev-builtin.c +@@ -34,9 +34,6 @@ static const struct udev_builtin *builtins[] = { + [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid, + #endif + [UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs, +-#ifdef HAVE_FIRMWARE +- [UDEV_BUILTIN_FIRMWARE] = &udev_builtin_firmware, +-#endif + [UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb, + [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id, + [UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard, +diff --git a/src/udev/udev.h b/src/udev/udev.h +index 4aca70bef4..faa8f566c2 100644 +--- a/src/udev/udev.h ++++ b/src/udev/udev.h +@@ -141,9 +141,6 @@ enum udev_builtin_cmd { + UDEV_BUILTIN_BLKID, + #endif + UDEV_BUILTIN_BTRFS, +-#ifdef HAVE_FIRMWARE +- UDEV_BUILTIN_FIRMWARE, +-#endif + UDEV_BUILTIN_HWDB, + UDEV_BUILTIN_INPUT_ID, + UDEV_BUILTIN_KEYBOARD, +@@ -172,9 +169,6 @@ struct udev_builtin { + extern const struct udev_builtin udev_builtin_blkid; + #endif + extern const struct udev_builtin udev_builtin_btrfs; +-#ifdef HAVE_FIRMWARE +-extern const struct udev_builtin udev_builtin_firmware; +-#endif + extern const struct udev_builtin udev_builtin_hwdb; + extern const struct udev_builtin udev_builtin_input_id; + extern const struct udev_builtin udev_builtin_keyboard; +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index f882cfb3ad..9c2b0d5223 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -100,9 +100,6 @@ struct event { + dev_t devnum; + int ifindex; + bool is_block; +-#ifdef HAVE_FIRMWARE +- bool nodelay; +-#endif + }; + + static inline struct event *node_to_event(struct udev_list_node *node) { +@@ -458,10 +455,6 @@ static int event_queue_insert(struct udev_device *dev) { + event->devnum = udev_device_get_devnum(dev); + event->is_block = streq("block", udev_device_get_subsystem(dev)); + event->ifindex = udev_device_get_ifindex(dev); +-#ifdef HAVE_FIRMWARE +- if (streq(udev_device_get_subsystem(dev), "firmware")) +- event->nodelay = true; +-#endif + + log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev), + udev_device_get_action(dev), udev_device_get_subsystem(dev)); +@@ -538,12 +531,6 @@ static bool is_devpath_busy(struct event *event) { + return true; + } + +-#ifdef HAVE_FIRMWARE +- /* allow to bypass the dependency tracking */ +- if (event->nodelay) +- continue; +-#endif +- + /* parent device event found */ + if (event->devpath[common] == '/') { + event->delaying_seqnum = loop_event->seqnum; diff --git a/0120-udev-bump-event-timeout-to-60-seconds.patch b/0120-udev-bump-event-timeout-to-60-seconds.patch new file mode 100644 index 0000000..d29afa0 --- /dev/null +++ b/0120-udev-bump-event-timeout-to-60-seconds.patch @@ -0,0 +1,36 @@ +From 2e92633dbae52f5ac9b7b2e068935990d475d2cd Mon Sep 17 00:00:00 2001 +From: Kay Sievers +Date: Sat, 30 Aug 2014 11:36:32 +0200 +Subject: [PATCH] udev: bump event timeout to 60 seconds + +--- + src/udev/udevadm-test.c | 2 +- + src/udev/udevd.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c +index 8486049814..809adb6d9a 100644 +--- a/src/udev/udevadm-test.c ++++ b/src/udev/udevadm-test.c +@@ -136,7 +136,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) { + goto out; + } + +- udev_event_execute_rules(event, 30 * USEC_PER_SEC, rules, &sigmask_orig); ++ udev_event_execute_rules(event, 60 * USEC_PER_SEC, rules, &sigmask_orig); + + udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) + printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 9c2b0d5223..e72c5b231e 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -73,7 +73,7 @@ static bool reload; + static int children; + static int children_max; + static int exec_delay; +-static usec_t event_timeout_usec = 30 * USEC_PER_SEC; ++static usec_t event_timeout_usec = 60 * USEC_PER_SEC; + static sigset_t sigmask_orig; + static UDEV_LIST(event_list); + static UDEV_LIST(worker_list); diff --git a/0121-libudev-fix-symbol-version-for-udev_queue_flush-and-.patch b/0121-libudev-fix-symbol-version-for-udev_queue_flush-and-.patch new file mode 100644 index 0000000..f9f5788 --- /dev/null +++ b/0121-libudev-fix-symbol-version-for-udev_queue_flush-and-.patch @@ -0,0 +1,35 @@ +From 015419c0dfd96bef9401c868137711ca78cce652 Mon Sep 17 00:00:00 2001 +From: Michael Biebl +Date: Sat, 30 Aug 2014 02:01:51 +0200 +Subject: [PATCH] libudev: fix symbol version for udev_queue_flush() and + udev_queue_get_fd() + +Those symbols were introduced in commit +14cb733684d3c3f50d088a3a370ddf8e8894dfa4 and released in v215. +--- + src/libudev/libudev.sym | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/libudev/libudev.sym b/src/libudev/libudev.sym +index 95cd1c7b9e..76726fca77 100644 +--- a/src/libudev/libudev.sym ++++ b/src/libudev/libudev.sym +@@ -82,8 +82,6 @@ global: + udev_queue_get_udev; + udev_queue_get_udev_is_active; + udev_queue_get_udev_seqnum; +- udev_queue_get_fd; +- udev_queue_flush; + udev_queue_new; + udev_queue_ref; + udev_queue_unref; +@@ -114,3 +112,9 @@ LIBUDEV_199 { + global: + udev_device_set_sysattr_value; + } LIBUDEV_196; ++ ++LIBUDEV_215 { ++global: ++ udev_queue_flush; ++ udev_queue_get_fd; ++} LIBUDEV_199; diff --git a/0122-Update-french-translation.patch b/0122-Update-french-translation.patch new file mode 100644 index 0000000..abe5f97 --- /dev/null +++ b/0122-Update-french-translation.patch @@ -0,0 +1,52 @@ +From b12942e67ecbea0b852d4ab8df1d34b04e9853f8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sylvain=20Plantef=C3=A8ve?= +Date: Sat, 30 Aug 2014 16:25:59 +0200 +Subject: [PATCH] Update french translation + +--- + po/fr.po | 28 +++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/po/fr.po b/po/fr.po +index ed8a68657d..7240cc57af 100644 +--- a/po/fr.po ++++ b/po/fr.po +@@ -8,7 +8,7 @@ msgstr "" + "Project-Id-Version: systemd\n" + "Report-Msgid-Bugs-To: \n" + "POT-Creation-Date: 2013-11-14 17:49+0100\n" +-"PO-Revision-Date: 2013-11-14 17:57+0100\n" ++"PO-Revision-Date: 2014-04-29 09:17+0300\n" + "Last-Translator: Sylvain Plantefève \n" + "Language-Team: French\n" + "Language: fr\n" +@@ -395,3 +395,29 @@ msgid "Authentication is required to access the system and service manager." + msgstr "" + "Authentification requise pour accéder au gestionnaire du système et des " + "services." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5 ++msgid "Manage system services or units" ++msgstr "Gérer les services système ou les unités" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6 ++msgid "Authentication is required to manage system services or units." ++msgstr "" ++"Authentification requise pour gérer les services système ou les unités." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7 ++msgid "Manage system service or unit files" ++msgstr "Gérer le service système ou ses fichiers unités" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8 ++msgid "Authentication is required to manage system service or unit files." ++msgstr "" ++"Authentification requise pour gérer le service système ou ses fichiers unités." ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9 ++msgid "Reload the systemd state" ++msgstr "Recharger l'état de systemd" ++ ++#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10 ++msgid "Authentication is required to reload the systemd state." ++msgstr "Authentification requise pour recharger l'état de systemd" diff --git a/0123-Fix-a-few-more-typos.patch b/0123-Fix-a-few-more-typos.patch new file mode 100644 index 0000000..bea9b63 --- /dev/null +++ b/0123-Fix-a-few-more-typos.patch @@ -0,0 +1,324 @@ +From 06b643e7f5a3b79005dd57497897ab7255fe3659 Mon Sep 17 00:00:00 2001 +From: Ruben Kerkhof +Date: Sat, 30 Aug 2014 17:13:16 +0200 +Subject: [PATCH] Fix a few more typos + +--- + CODING_STYLE | 2 +- + NEWS | 2 +- + man/file-hierarchy.xml | 2 +- + man/kernel-command-line.xml | 2 +- + man/sd_bus_creds_get_pid.xml | 2 +- + man/sd_bus_creds_new_from_pid.xml | 4 ++-- + man/sd_bus_error.xml | 2 +- + man/sd_bus_message_append_basic.xml | 4 ++-- + man/systemd-hibernate-resume-generator.xml | 2 +- + man/systemd-nspawn.xml | 2 +- + man/systemd.exec.xml | 2 +- + man/systemd.socket.xml | 2 +- + src/core/unit.c | 2 +- + src/journal/test-compress-benchmark.c | 2 +- + src/libsystemd-network/sd-icmp6-nd.c | 2 +- + src/libsystemd-terminal/term-page.c | 4 ++-- + src/libsystemd-terminal/term-screen.c | 4 ++-- + src/libsystemd-terminal/test-term-page.c | 2 +- + src/libsystemd/sd-bus/kdbus.h | 2 +- + src/shared/architecture.h | 2 +- + 20 files changed, 24 insertions(+), 24 deletions(-) + +diff --git a/CODING_STYLE b/CODING_STYLE +index a3fc26c1e1..05b5ecf89f 100644 +--- a/CODING_STYLE ++++ b/CODING_STYLE +@@ -155,7 +155,7 @@ + function or a "non-logging" function. "Logging" functions do logging + on their own, "non-logging" function never log on their own and + expect their callers to log. All functions in "library" code, +- i.e. in src/shared/ and suchlike must be "non-logging". Everytime a ++ i.e. in src/shared/ and suchlike must be "non-logging". Every time a + "logging" function calls a "non-logging" function, it should log + about the resulting errors. If a "logging" function calls another + "logging" function, then it should not generate log messages, so +diff --git a/NEWS b/NEWS +index 2fca2cdc93..f52ee027a1 100644 +--- a/NEWS ++++ b/NEWS +@@ -1613,7 +1613,7 @@ CHANGES WITH 208: + kernel, and on seats that are not seat0. + + * A new kernel command line option luks.options= is understood +- now which allows specifiying LUKS options for usage for LUKS ++ now which allows specifying LUKS options for usage for LUKS + encrypted partitions specified with luks.uuid=. + + * tmpfiles.d(5) snippets may now use specifier expansion in +diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml +index 523846b646..9d96cff007 100644 +--- a/man/file-hierarchy.xml ++++ b/man/file-hierarchy.xml +@@ -914,7 +914,7 @@ + + + ~/.local/lib/package +- Private, static vendor resources of the package, compatible wih any architecture, or any other kind of read-only vendor data. ++ Private, static vendor resources of the package, compatible with any architecture, or any other kind of read-only vendor data. + + + ~/.local/lib/arch-id/package +diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml +index d872e6d5b9..3263b77cea 100644 +--- a/man/kernel-command-line.xml ++++ b/man/kernel-command-line.xml +@@ -358,7 +358,7 @@ + Enables resume from hibernation + using the specified device. + All fstab5-like +- pathes are supported. For details, see ++ paths are supported. For details, see + systemd-hibernate-resume-generator8. + + +diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml +index 5a848576f3..40ed81ecb0 100644 +--- a/man/sd_bus_creds_get_pid.xml ++++ b/man/sd_bus_creds_get_pid.xml +@@ -405,7 +405,7 @@ along with systemd; If not, see . + + -ENXIO + +- An error occured in parsing cgroup paths. ++ An error occurred in parsing cgroup paths. + libsystemd might be out of sync with + the running systemd version. + +diff --git a/man/sd_bus_creds_new_from_pid.xml b/man/sd_bus_creds_new_from_pid.xml +index 406769b21d..bc94c44095 100644 +--- a/man/sd_bus_creds_new_from_pid.xml ++++ b/man/sd_bus_creds_new_from_pid.xml +@@ -149,7 +149,7 @@ along with systemd; If not, see . + and other functions which correspond directly to the constants + listed above. + +- A mask of fields which were actually sucessfully set ++ A mask of fields which were actually successfully set + (acquired from /proc, etc.) can be retrieved + with sd_bus_creds_get_mask(). If the + credentials object was created with +@@ -162,7 +162,7 @@ along with systemd; If not, see . + object will not be destroyed until + sd_bus_creds_unref has been called as many + times plus once more. Once the reference count has dropped to zero, +- c cannot be used anymore, so futher ++ c cannot be used anymore, so further + calls to sd_bus_creds_ref(c) or + sd_bus_creds_unref(c) are illegal. + +diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml +index 3317eadc37..7f4160753e 100644 +--- a/man/sd_bus_error.xml ++++ b/man/sd_bus_error.xml +@@ -252,7 +252,7 @@ along with systemd; If not, see . + D-Bus error names are available as constants + SD_BUS_ERROR_FAILED, etc., listed above. If + name is NULL, it is +- assumed that no error occured, and 0 is returned. This means that ++ assumed that no error occurred, and 0 is returned. This means that + this function may be conveniently used in a + return statement. + +diff --git a/man/sd_bus_message_append_basic.xml b/man/sd_bus_message_append_basic.xml +index da92020053..7c5f1e9ddc 100644 +--- a/man/sd_bus_message_append_basic.xml ++++ b/man/sd_bus_message_append_basic.xml +@@ -95,7 +95,7 @@ along with systemd; If not, see . + + y + SD_BUS_TYPE_BYTE +- unsigned interger ++ unsigned integer + 1 byte + + +@@ -200,7 +200,7 @@ along with systemd; If not, see . + valid Unicode string encoded as UTF-8. In case of the two latter + types, the additional requirements for a D-Bus object path or + type signature should be satisfied. Those requirements should be +- verified by the recepient of the message. ++ verified by the recipient of the message. + + + +diff --git a/man/systemd-hibernate-resume-generator.xml b/man/systemd-hibernate-resume-generator.xml +index 1a4b99ced4..e010c23df4 100644 +--- a/man/systemd-hibernate-resume-generator.xml ++++ b/man/systemd-hibernate-resume-generator.xml +@@ -71,7 +71,7 @@ + resume= + + Takes a path to the resume +- device. Both persistent block device pathes like ++ device. Both persistent block device paths like + /dev/disk/by-foo/bar and + fstab5-style + specifiers like FOO=bar +diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml +index aea50559f0..820a79bc28 100644 +--- a/man/systemd-nspawn.xml ++++ b/man/systemd-nspawn.xml +@@ -668,7 +668,7 @@ + as tmpfs instance + into it (the system thus starts up + with read-only OS resources and +- configuration, but prestine state, any ++ configuration, but pristine state, any + changes to the latter are lost on + shutdown). When the mode parameter is + specified as no +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index af103ff14c..707d582b4f 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -1059,7 +1059,7 @@ + namespace. Note that + means that file + systems mounted on the host might stay +- mounted continously in the unit's ++ mounted continuously in the unit's + namespace, and thus keep the device + busy. Note that the file system + namespace related options +diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml +index 238029a251..8394fa81aa 100644 +--- a/man/systemd.socket.xml ++++ b/man/systemd.socket.xml +@@ -513,7 +513,7 @@ + + + KeepAliveProbes= +- Takes interger as argument. It's the number of unacknowledged probes to ++ Takes integer as argument. It's the number of unacknowledged probes to + send before considering the connection dead and notifying the application layer. + This controls the TCP_KEEPCNT socket option (see + socket7 +diff --git a/src/core/unit.c b/src/core/unit.c +index 56102b360d..b5c3182940 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3425,7 +3425,7 @@ int unit_setup_exec_runtime(Unit *u) { + offset = UNIT_VTABLE(u)->exec_runtime_offset; + assert(offset > 0); + +- /* Check if ther already is an ExecRuntime for this unit? */ ++ /* Check if there already is an ExecRuntime for this unit? */ + rt = (ExecRuntime**) ((uint8_t*) u + offset); + if (*rt) + return 0; +diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c +index 8975e29b17..b3bc3ec2fe 100644 +--- a/src/journal/test-compress-benchmark.c ++++ b/src/journal/test-compress-benchmark.c +@@ -61,7 +61,7 @@ static void test_compress_decompress(const char* label, + int r; + + r = compress(text, i, buf, &j); +- /* assume compresion must be succesful except for small inputs */ ++ /* assume compression must be successful except for small inputs */ + assert(r == 0 || (i < 2048 && r == -ENOBUFS)); + /* check for overwrites */ + assert(buf[i] == 0); +diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c +index 243f06a85f..bbb4531ddb 100644 +--- a/src/libsystemd-network/sd-icmp6-nd.c ++++ b/src/libsystemd-network/sd-icmp6-nd.c +@@ -212,7 +212,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, + if (ra.nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) + event = ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED; + +- log_icmp6_nd(nd, "Received Router Advertisment flags %s/%s", ++ log_icmp6_nd(nd, "Received Router Advertisement flags %s/%s", + (ra.nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)? "MANAGED": + "none", + (ra.nd_ra_flags_reserved & ND_RA_FLAG_OTHER)? "OTHER": +diff --git a/src/libsystemd-terminal/term-page.c b/src/libsystemd-terminal/term-page.c +index 7ae90e2cda..ae73cdf627 100644 +--- a/src/libsystemd-terminal/term-page.c ++++ b/src/libsystemd-terminal/term-page.c +@@ -42,7 +42,7 @@ + * support Unicode combining-characters, therefore this gets more complicated. + * Characters themselves are represented by a "term_char_t" object. It + * should be treated as a normal integer and passed by value. The +- * sorrounding struct is just to hide the internals. A term-char can contain a ++ * surrounding struct is just to hide the internals. A term-char can contain a + * base character together with up to 2 combining-chars in a single integer. + * Only if you need more combining-chars (very unlikely!) a term-char is a + * pointer to an allocated storage. This requires you to always free term-char +@@ -1012,7 +1012,7 @@ void term_line_append_combchar(term_line *line, unsigned int pos_x, uint32_t ucs + * @age: current age for all modifications + * @keep_protected: true if protected cells should be kept + * +- * This is the standard erase operation. It clears all cells in the targetted ++ * This is the standard erase operation. It clears all cells in the targeted + * area and re-initializes them. Cells to the right are not shifted left, you + * must use DELETE to achieve that. Cells outside the visible area are skipped. + * +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index a19c684d2a..67f9056d57 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -455,7 +455,7 @@ static uint32_t screen_map(term_screen *screen, uint32_t val) { + + /* + * Command Handlers +- * This is the inofficial documentation of all the TERM_CMD_* definitions. Each ++ * This is the unofficial documentation of all the TERM_CMD_* definitions. Each + * handled command has a separate function with an extensive comment on the + * semantics of the command. + * Note that many semantics are unknown and need to be verified. This is mostly +@@ -1040,7 +1040,7 @@ static int screen_DECELR(term_screen *screen, const term_seq *seq) { + /* + * DECELR - enable-locator-reporting + * This changes the locator-reporting mode. @args[0] specifies the mode +- * to set, 0 disables locator-reporting, 1 enables it continously, 2 ++ * to set, 0 disables locator-reporting, 1 enables it continuously, 2 + * enables it for a single report. @args[1] specifies the + * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets + * pixel-precision. +diff --git a/src/libsystemd-terminal/test-term-page.c b/src/libsystemd-terminal/test-term-page.c +index bba83ee405..9e338776e8 100644 +--- a/src/libsystemd-terminal/test-term-page.c ++++ b/src/libsystemd-terminal/test-term-page.c +@@ -263,7 +263,7 @@ static void test_term_char_allocating(void) { + * in the range 'A'-'Z', 'a'-'z'. All those are combined and used as term_char_t + * on this cell. Any numbers in the description are combined and are used as + * cell-age. +- * The occurance of a '*'-symbol marks the cell as bold, '/' marks it as italic. ++ * The occurrence of a '*'-symbol marks the cell as bold, '/' marks it as italic. + * You can use those characters multiple times, but only the first one has an + * effect. + * For further symbols, see parse_attr(). +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index 3751f9ca24..65f76e9cf4 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -486,7 +486,7 @@ enum kdbus_policy_type { + * policy entries for a name. The provided name + * is not activated and not registered with the + * name database, it only allows unprivileged +- * connections to aquire a name, talk or discover ++ * connections to acquire a name, talk or discover + * a service + * @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor + * bus traffic +diff --git a/src/shared/architecture.h b/src/shared/architecture.h +index 71c79b1542..353d49bedf 100644 +--- a/src/shared/architecture.h ++++ b/src/shared/architecture.h +@@ -28,7 +28,7 @@ + /* A cleaned up architecture definition. We don't want to get lost in + * processor features, models, generations or even ABIs. Hence we + * focus on general family, and distuignish word width and +- * endianess. */ ++ * endianness. */ + + typedef enum Architecture { + ARCHITECTURE_X86 = 0, diff --git a/0124-sd-ipv4ll-name-the-correct-source.patch b/0124-sd-ipv4ll-name-the-correct-source.patch new file mode 100644 index 0000000..5ce3785 --- /dev/null +++ b/0124-sd-ipv4ll-name-the-correct-source.patch @@ -0,0 +1,22 @@ +From f697185e5b45287b6a62592129e726d8a636d3ff Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 29 Aug 2014 13:08:16 +0200 +Subject: [PATCH] sd-ipv4ll: name the correct source + +--- + src/libsystemd-network/sd-ipv4ll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c +index 3d15fc85ea..8b243319b6 100644 +--- a/src/libsystemd-network/sd-ipv4ll.c ++++ b/src/libsystemd-network/sd-ipv4ll.c +@@ -564,7 +564,7 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { + if (r < 0) + goto out; + +- r = sd_event_source_set_name(ll->timer, "ipv4ll-receive-message"); ++ r = sd_event_source_set_name(ll->receive_message, "ipv4ll-receive-message"); + if (r < 0) + goto out; + diff --git a/0125-journal-compress-use-LZ4_compress_continue.patch b/0125-journal-compress-use-LZ4_compress_continue.patch new file mode 100644 index 0000000..94521b7 --- /dev/null +++ b/0125-journal-compress-use-LZ4_compress_continue.patch @@ -0,0 +1,35 @@ +From b4232628f3d4b00c967310d56c0e95715c9d05cd Mon Sep 17 00:00:00 2001 +From: Evangelos Foutras +Date: Sat, 30 Aug 2014 10:13:43 +0300 +Subject: [PATCH] journal/compress: use LZ4_compress_continue() + +We can't use LZ4_compress_limitedOutput_continue() because in the +worst-case scenario the compressed output can be slightly bigger than +the input block. This generally affects very few blocks and is no reason +to abort the compression process. + +I ran into this when I noticed that Chromium core dumps weren't being +compressed. After switching to LZ4_compress_continue() a ~330MB Chromium +core dump gets compressed to ~17M. +--- + src/journal/compress.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/journal/compress.c b/src/journal/compress.c +index 52a4c100b3..c4c715be2f 100644 +--- a/src/journal/compress.c ++++ b/src/journal/compress.c +@@ -460,10 +460,10 @@ int compress_stream_lz4(int fdf, int fdt, off_t max_bytes) { + + total_in += n; + +- r = LZ4_compress_limitedOutput_continue(&lz4_data, buf, out, n, n); ++ r = LZ4_compress_continue(&lz4_data, buf, out, n); + if (r == 0) { +- log_debug("Compressed size exceeds original, aborting compression."); +- return -ENOBUFS; ++ log_error("LZ4 compression failed."); ++ return -EBADMSG; + } + + header = htole32(r); diff --git a/0126-test-compress-also-test-with-incompressible-inputs.patch b/0126-test-compress-also-test-with-incompressible-inputs.patch new file mode 100644 index 0000000..4ef7e01 --- /dev/null +++ b/0126-test-compress-also-test-with-incompressible-inputs.patch @@ -0,0 +1,163 @@ +From c552d602ae784c0261ceeb46ace30e6189f38bb2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 30 Aug 2014 14:47:36 -0400 +Subject: [PATCH] test-compress: also test with incompressible inputs + +--- + src/journal/test-compress.c | 91 ++++++++++++++++++++++++++++++++------------- + 1 file changed, 65 insertions(+), 26 deletions(-) + +diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c +index 026d630ac2..78b3203bef 100644 +--- a/src/journal/test-compress.c ++++ b/src/journal/test-compress.c +@@ -48,25 +48,31 @@ typedef int (decompress_stream_t)(int fdf, int fdt, off_t max_size); + + static void test_compress_decompress(int compression, + compress_blob_t compress, +- decompress_blob_t decompress) { +- char text[] = "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF" +- "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"; ++ decompress_blob_t decompress, ++ const char *data, ++ size_t data_len, ++ bool may_fail) { + char compressed[512]; + size_t csize = 512; + size_t usize = 0; + _cleanup_free_ char *decompressed = NULL; + int r; + +- log_info("/* testing %s blob compression/decompression */", +- object_compressed_to_string(compression)); +- +- r = compress(text, sizeof(text), compressed, &csize); +- assert(r == 0); +- r = decompress(compressed, csize, +- (void **) &decompressed, &usize, &csize, 0); +- assert(r == 0); +- assert_se(decompressed); +- assert_se(streq(decompressed, text)); ++ log_info("/* testing %s %s blob compression/decompression */", ++ object_compressed_to_string(compression), data); ++ ++ r = compress(data, data_len, compressed, &csize); ++ if (r == -ENOBUFS) { ++ log_info("compression failed: %s", strerror(-r)); ++ assert(may_fail); ++ } else { ++ assert(r == 0); ++ r = decompress(compressed, csize, ++ (void **) &decompressed, &usize, &csize, 0); ++ assert(r == 0); ++ assert_se(decompressed); ++ assert_se(memcmp(decompressed, data, data_len) == 0); ++ } + + r = decompress("garbage", 7, + (void **) &decompressed, &usize, &csize, 0); +@@ -86,29 +92,38 @@ static void test_compress_decompress(int compression, + + static void test_decompress_startswith(int compression, + compress_blob_t compress, +- decompress_sw_t decompress_sw) { ++ decompress_sw_t decompress_sw, ++ const char *data, ++ size_t data_len, ++ bool may_fail) { + +- char text[] = "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF" +- "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"; + char compressed[512]; + size_t csize = 512; + size_t usize = 0; + _cleanup_free_ char *decompressed = NULL; ++ int r; + +- log_info("/* testing decompress_startswith with %s */", +- object_compressed_to_string(compression)); ++ log_info("/* testing decompress_startswith with %s on %s text*/", ++ object_compressed_to_string(compression), data); ++ ++ r = compress(data, data_len, compressed, &csize); ++ if (r == -ENOBUFS) { ++ log_info("compression failed: %s", strerror(-r)); ++ assert(may_fail); ++ return; ++ } ++ assert(r == 0); + +- assert_se(compress(text, sizeof(text), compressed, &csize) == 0); + assert_se(decompress_sw(compressed, + csize, + (void **) &decompressed, + &usize, +- "foofoofoofoo", 12, ' ') > 0); ++ data, strlen(data), '\0') > 0); + assert_se(decompress_sw(compressed, + csize, + (void **) &decompressed, + &usize, +- "foofoofoofoo", 12, 'w') == 0); ++ data, strlen(data), 'w') == 0); + assert_se(decompress_sw(compressed, + csize, + (void **) &decompressed, +@@ -118,7 +133,7 @@ static void test_decompress_startswith(int compression, + csize, + (void **) &decompressed, + &usize, +- "foofoofoofoo", 12, ' ') > 0); ++ data, strlen(data), '\0') > 0); + } + + static void test_compress_stream(int compression, +@@ -181,20 +196,44 @@ static void test_compress_stream(int compression, + } + + int main(int argc, char *argv[]) { ++ const char text[] = ++ "text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF" ++ "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"; ++ ++ char data[512] = "random\0"; + + log_set_max_level(LOG_DEBUG); + ++ random_bytes(data + 7, sizeof(data) - 7); ++ + #ifdef HAVE_XZ +- test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz); +- test_decompress_startswith(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz); ++ test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz, ++ text, sizeof(text), false); ++ test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz, ++ data, sizeof(data), true); ++ test_decompress_startswith(OBJECT_COMPRESSED_XZ, ++ compress_blob_xz, decompress_startswith_xz, ++ text, sizeof(text), false); ++ test_decompress_startswith(OBJECT_COMPRESSED_XZ, ++ compress_blob_xz, decompress_startswith_xz, ++ data, sizeof(data), true); + test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat", + compress_stream_xz, decompress_stream_xz, argv[0]); + #else + log_info("/* XZ test skipped */"); + #endif ++ + #ifdef HAVE_LZ4 +- test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4); +- test_decompress_startswith(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4); ++ test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4, ++ text, sizeof(text), false); ++ test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4, ++ data, sizeof(data), true); ++ test_decompress_startswith(OBJECT_COMPRESSED_LZ4, ++ compress_blob_lz4, decompress_startswith_lz4, ++ text, sizeof(text), false); ++ test_decompress_startswith(OBJECT_COMPRESSED_LZ4, ++ compress_blob_lz4, decompress_startswith_lz4, ++ data, sizeof(data), true); + + /* Produced stream is not compatible with lz4 binary, skip lz4cat check. */ + test_compress_stream(OBJECT_COMPRESSED_LZ4, NULL, diff --git a/0127-systemd-fix-error-message.patch b/0127-systemd-fix-error-message.patch new file mode 100644 index 0000000..1d4df1a --- /dev/null +++ b/0127-systemd-fix-error-message.patch @@ -0,0 +1,31 @@ +From 6ad3b2b62cbe34cc02ee98deb5f48047f5e42d26 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 30 Aug 2014 17:22:42 -0400 +Subject: [PATCH] systemd: fix error message + +--- + src/core/dbus-manager.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 008cf6b4cd..e792fe7e28 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1241,7 +1241,7 @@ static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userda + return r; + + if (m->running_as != SYSTEMD_SYSTEM) +- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers."); ++ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager."); + + r = sd_bus_message_read(message, "ss", &root, &init); + if (r < 0) +@@ -1252,7 +1252,7 @@ static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userda + + /* Safety check */ + if (isempty(init)) { +- if (! path_is_os_tree(root)) ++ if (!path_is_os_tree(root)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. os-release file is missing.", root); + } else { + _cleanup_free_ char *p = NULL; diff --git a/0128-cgroup-util-shorten-cg_path_get_session.patch b/0128-cgroup-util-shorten-cg_path_get_session.patch new file mode 100644 index 0000000..822bc06 --- /dev/null +++ b/0128-cgroup-util-shorten-cg_path_get_session.patch @@ -0,0 +1,60 @@ +From a13ee4c792cb5738c3dd13b2a4bb1a828e7994fd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 29 Aug 2014 07:48:33 -0500 +Subject: [PATCH] cgroup-util: shorten cg_path_get_session + +--- + src/shared/cgroup-util.c | 12 ++++-------- + src/test/test-cgroup-util.c | 3 ++- + 2 files changed, 6 insertions(+), 9 deletions(-) + +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index e8cb9c73ac..00eac64236 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -1306,9 +1306,8 @@ int cg_pid_get_machine_name(pid_t pid, char **machine) { + } + + int cg_path_get_session(const char *path, char **session) { +- const char *e, *n, *x; ++ const char *e, *n, *x, *y; + char *s; +- size_t l; + + assert(path); + +@@ -1325,17 +1324,14 @@ int cg_path_get_session(const char *path, char **session) { + x = startswith(s, "session-"); + if (!x) + return -ENOENT; +- if (!endswith(x, ".scope")) +- return -ENOENT; +- +- l = strlen(x); +- if (l <= 6) ++ y = endswith(x, ".scope"); ++ if (!y || x == y) + return -ENOENT; + + if (session) { + char *r; + +- r = strndup(x, l - 6); ++ r = strndup(x, y - x); + if (!r) + return -ENOMEM; + +diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c +index fda8bcc5c5..68c526ae82 100644 +--- a/src/test/test-cgroup-util.c ++++ b/src/test/test-cgroup-util.c +@@ -106,7 +106,8 @@ static void check_p_g_s(const char *path, int code, const char *result) { + static void test_path_get_session(void) { + check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2"); + check_p_g_s("/session-3.scope", 0, "3"); +- check_p_g_s("", -ENOENT, 0); ++ check_p_g_s("/session-.scope", -ENOENT, NULL); ++ check_p_g_s("", -ENOENT, NULL); + } + + static void check_p_g_o_u(const char *path, int code, uid_t result) { diff --git a/0129-test-dhcp6-client-Fix-option-length.patch b/0129-test-dhcp6-client-Fix-option-length.patch new file mode 100644 index 0000000..f8a1175 --- /dev/null +++ b/0129-test-dhcp6-client-Fix-option-length.patch @@ -0,0 +1,40 @@ +From d182960ae974a0074010a058d0d909846a2f3f79 Mon Sep 17 00:00:00 2001 +From: Patrik Flykt +Date: Fri, 29 Aug 2014 09:20:46 +0300 +Subject: [PATCH] test-dhcp6-client: Fix option length + +The whole DHCPv6 test message length was incorrectly used as the length +of DHCPv6 options causing the following bad memory access: + +$ build/test-dhcp6-client +Assertion 'interface_index >= -1' failed at ../src/libsystemd-network/sd-dhcp6-client.c:129, function sd_dhcp6_client_set_index(). Ignoring. +================================================================= +==29135==ERROR: AddressSanitizer: global-buffer-overflow on address 0x7fe204aa9148 at pc 0x7fe204a5958f bp 0x7fff3e47d470 sp 0x7fff3e47d460 +READ of size 1 at 0x7fe204aa9148 thread T0 + #0 0x7fe204a5958e in option_parse_hdr ../src/libsystemd-network/dhcp6-option.c:145 + #1 0x7fe204a59884 in dhcp6_option_parse ../src/libsystemd-network/dhcp6-option.c:165 + #2 0x7fe204a4eb9c in test_advertise_option ../src/libsystemd-network/test-dhcp6-client.c:227 + #3 0x7fe204a51c58 in main ../src/libsystemd-network/test-dhcp6-client.c:584 + #4 0x7fe2031590df in __libc_start_main (/lib64/libc.so.6+0x200df) + #5 0x7fe204a4cc5b (/home/test/systemd/build/test-dhcp6-client+0x25c5b) + +0x7fe204aa9148 is located 2 bytes to the right of global variable 'msg_advertise' from '../src/libsystemd-network/test-dhcp6-client.c' (0x7fe204aa9080) of size 198 +0x7fe204aa9148 is located 56 bytes to the left of global variable 'msg_reply' from '../src/libsystemd-network/test-dhcp6-client.c' (0x7fe204aa9180) of size 173 +SUMMARY: AddressSanitizer: global-buffer-overflow ../src/libsystemd-network/dhcp6-option.c:145 option_parse_hdr +--- + src/libsystemd-network/test-dhcp6-client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c +index 96c68e1feb..259db33bcd 100644 +--- a/src/libsystemd-network/test-dhcp6-client.c ++++ b/src/libsystemd-network/test-dhcp6-client.c +@@ -207,7 +207,7 @@ static int test_advertise_option(sd_event *e) { + DHCP6Message *advertise = (DHCP6Message *)msg_advertise; + uint8_t *optval, *opt = &msg_advertise[sizeof(DHCP6Message)]; + uint16_t optcode; +- size_t optlen, len = sizeof(msg_advertise); ++ size_t optlen, len = sizeof(msg_advertise) - sizeof(DHCP6Message); + be32_t val; + uint8_t preference = 255; + struct in6_addr addr; diff --git a/0130-sd-dhcp6-client-properly-calculate-buffer-size-when-.patch b/0130-sd-dhcp6-client-properly-calculate-buffer-size-when-.patch new file mode 100644 index 0000000..7dfc890 --- /dev/null +++ b/0130-sd-dhcp6-client-properly-calculate-buffer-size-when-.patch @@ -0,0 +1,47 @@ +From 44481a8b537839cd9ffead4d261491641f5b5260 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 30 Aug 2014 18:31:21 -0400 +Subject: [PATCH] sd-dhcp6-client: properly calculate buffer size when parsing + options + +Also make pointer calculations more explicit so they are +easier to understand. +--- + src/libsystemd-network/sd-dhcp6-client.c | 5 ++++- + src/libsystemd-network/test-dhcp6-client.c | 2 +- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index 342a231413..6860c66858 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -583,12 +583,15 @@ static int client_parse_message(sd_dhcp6_client *client, + DHCP6Message *message, size_t len, + sd_dhcp6_lease *lease) { + int r; +- uint8_t *optval, *option = (uint8_t *)(message + 1), *id = NULL; ++ uint8_t *optval, *option, *id = NULL; + uint16_t optcode, status; + size_t optlen, id_len; + bool clientid = false; + be32_t iaid_lease; + ++ option = (uint8_t *)message + sizeof(DHCP6Message); ++ len -= sizeof(DHCP6Message); ++ + while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, + &optval)) >= 0) { + switch (optcode) { +diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c +index 259db33bcd..d102a796b4 100644 +--- a/src/libsystemd-network/test-dhcp6-client.c ++++ b/src/libsystemd-network/test-dhcp6-client.c +@@ -205,7 +205,7 @@ static uint8_t msg_reply[173] = { + static int test_advertise_option(sd_event *e) { + _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; + DHCP6Message *advertise = (DHCP6Message *)msg_advertise; +- uint8_t *optval, *opt = &msg_advertise[sizeof(DHCP6Message)]; ++ uint8_t *optval, *opt = msg_advertise + sizeof(DHCP6Message); + uint16_t optcode; + size_t optlen, len = sizeof(msg_advertise) - sizeof(DHCP6Message); + be32_t val; diff --git a/0131-timesyncd-manager-don-t-clear-current_server_name-if.patch b/0131-timesyncd-manager-don-t-clear-current_server_name-if.patch new file mode 100644 index 0000000..20d1740 --- /dev/null +++ b/0131-timesyncd-manager-don-t-clear-current_server_name-if.patch @@ -0,0 +1,30 @@ +From 20f8d3cf1be4ad76234ffb85eeae7f9892ee72cd Mon Sep 17 00:00:00 2001 +From: Steven Noonan +Date: Sat, 30 Aug 2014 05:58:06 -0700 +Subject: [PATCH] timesyncd-manager: don't clear current_server_name if + ServerAddress is NULL + +https://bugs.freedesktop.org/show_bug.cgi?id=83091 + +[zj: add comment] +--- + src/timesync/timesyncd-manager.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 9b8b7d3eb6..696dd10e69 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -766,8 +766,11 @@ void manager_set_server_address(Manager *m, ServerAddress *a) { + if (m->current_server_address == a) + return; + +- m->current_server_name = a ? a->name : NULL; + m->current_server_address = a; ++ /* If a is NULL, we are just clearing the address, without ++ * changing the name. Keep the existing name in that case. */ ++ if (a) ++ m->current_server_name = a->name; + + manager_disconnect(m); + diff --git a/0132-units-make-emergency.service-conflict-with-rescue.se.patch b/0132-units-make-emergency.service-conflict-with-rescue.se.patch new file mode 100644 index 0000000..e9c992a --- /dev/null +++ b/0132-units-make-emergency.service-conflict-with-rescue.se.patch @@ -0,0 +1,26 @@ +From 87502e5868a8dbe2fda9a8e66a37ed6996646ef8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 30 Aug 2014 22:33:40 -0400 +Subject: [PATCH] units: make emergency.service conflict with rescue.service + +They both use StandardInput=tty-force so they cannot be run +concurrently. + +https://bugs.freedesktop.org/show_bug.cgi?id=82778 +https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=757072 +--- + units/emergency.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/emergency.service.in b/units/emergency.service.in +index 91fc1bbf51..224a434f72 100644 +--- a/units/emergency.service.in ++++ b/units/emergency.service.in +@@ -10,6 +10,7 @@ Description=Emergency Shell + Documentation=man:sulogin(8) + DefaultDependencies=no + Conflicts=shutdown.target ++Conflicts=rescue.service + Before=shutdown.target + + [Service] diff --git a/0133-units-m4-is-not-needed-for-rescue.service.patch b/0133-units-m4-is-not-needed-for-rescue.service.patch new file mode 100644 index 0000000..edb4016 --- /dev/null +++ b/0133-units-m4-is-not-needed-for-rescue.service.patch @@ -0,0 +1,49 @@ +From 9c0804278b42261b4dce20ea0ea79bcbad291639 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 30 Aug 2014 23:59:37 -0400 +Subject: [PATCH] units: m4 is not needed for rescue.service + +--- + Makefile.am | 3 +-- + units/.gitignore | 1 - + units/{rescue.service.m4.in => rescue.service.in} | 0 + 3 files changed, 1 insertion(+), 3 deletions(-) + rename units/{rescue.service.m4.in => rescue.service.in} (100%) + +diff --git a/Makefile.am b/Makefile.am +index b37ed41554..1991fd0e3b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -550,7 +550,7 @@ EXTRA_DIST += \ + units/console-shell.service.m4.in \ + units/console-getty.service.m4.in \ + units/container-getty@.service.m4.in \ +- units/rescue.service.m4.in \ ++ units/rescue.service.in \ + units/systemd-initctl.service.in \ + units/systemd-shutdownd.service.in \ + units/systemd-remount-fs.service.in \ +@@ -585,7 +585,6 @@ CLEANFILES += \ + units/console-shell.service.m4 \ + units/console-getty.service.m4 \ + units/container-getty@.service.m4 \ +- units/rescue.service.m4 \ + units/user@.service.m4 + + if HAVE_SYSV_COMPAT +diff --git a/units/.gitignore b/units/.gitignore +index c60f357416..ab1d97da54 100644 +--- a/units/.gitignore ++++ b/units/.gitignore +@@ -16,7 +16,6 @@ + /quotaon.service + /rc-local.service + /rescue.service +-/rescue.service.m4 + /serial-getty@.service + /systemd-ask-password-console.service + /systemd-ask-password-wall.service +diff --git a/units/rescue.service.m4.in b/units/rescue.service.in +similarity index 100% +rename from units/rescue.service.m4.in +rename to units/rescue.service.in diff --git a/0134-units-update-rescue.service-and-emergency.service.patch b/0134-units-update-rescue.service-and-emergency.service.patch new file mode 100644 index 0000000..7f4060e --- /dev/null +++ b/0134-units-update-rescue.service-and-emergency.service.patch @@ -0,0 +1,38 @@ +From 42377d6bb771c31bff931f83163972fdcb224d0c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 30 Aug 2014 22:34:56 -0400 +Subject: [PATCH] units: update rescue.service and emergency.service + +^D works in emergency.service too. One needs to log in when in rescue +mode too. +--- + units/emergency.service.in | 2 +- + units/rescue.service.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/units/emergency.service.in b/units/emergency.service.in +index 224a434f72..18973e78fa 100644 +--- a/units/emergency.service.in ++++ b/units/emergency.service.in +@@ -17,7 +17,7 @@ Before=shutdown.target + Environment=HOME=/root + WorkingDirectory=/root + ExecStartPre=-/bin/plymouth quit +-ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" to try again\\nto boot into default mode.' ++ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" or ^D to\\ntry again to boot into default mode.' + ExecStart=-/bin/sh -c "/sbin/sulogin; @SYSTEMCTL@ --fail --no-block default" + Type=idle + StandardInput=tty-force +diff --git a/units/rescue.service.in b/units/rescue.service.in +index ef5436960f..fc93f1e160 100644 +--- a/units/rescue.service.in ++++ b/units/rescue.service.in +@@ -17,7 +17,7 @@ Before=shutdown.target + Environment=HOME=/root + WorkingDirectory=/root + ExecStartPre=-/bin/plymouth quit +-ExecStartPre=-/bin/echo -e 'Welcome to rescue mode! Type "systemctl default" or ^D to enter default mode.\\nType "journalctl -xb" to view system logs. Type "systemctl reboot" to reboot.' ++ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" or ^D to\\nboot into default mode.' + ExecStart=-/bin/sh -c "/sbin/sulogin; @SYSTEMCTL@ --fail --no-block default" + Type=idle + StandardInput=tty-force diff --git a/0135-Quote-unit-names-in-suggested-systemctl-commandlines.patch b/0135-Quote-unit-names-in-suggested-systemctl-commandlines.patch new file mode 100644 index 0000000..1bca67c --- /dev/null +++ b/0135-Quote-unit-names-in-suggested-systemctl-commandlines.patch @@ -0,0 +1,65 @@ +From 8e07fc41f86d41e68c5663b2a3c620a0adedcc11 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 31 Aug 2014 00:42:27 -0400 +Subject: [PATCH] Quote unit names in suggested systemctl commandlines + +The fact that unit names have to be quoted can be a bit surprising. +Show quotes in the hint commandline, but only after checking that this +is necessary, since quotes are visually heavy and usually not needed. + +https://bugs.freedesktop.org/show_bug.cgi?id=82832 +--- + src/core/job.c | 11 +++++++++-- + src/systemctl/systemctl.c | 14 ++++++++++++-- + 2 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 5e4987f4e2..ef5dbce1a3 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -632,11 +632,18 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { + unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format); + break; + +- case JOB_FAILED: ++ case JOB_FAILED: { ++ bool quotes; ++ ++ quotes = chars_intersect(u->id, SHELL_NEED_QUOTES); ++ + 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, false, NULL, "See 'systemctl status %s' for details.", u->id); ++ manager_status_printf(u->manager, false, NULL, ++ "See \"systemctl status %s%s%s\" for details.", ++ quotes ? "'" : "", u->id, quotes ? "'" : ""); + break; ++ } + + case JOB_DEPENDENCY: + manager_flip_auto_status(u->manager, true); +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 65348193b7..de43c879a7 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -2351,8 +2351,18 @@ static int check_wait_response(WaitData *d) { + log_error("Job for %s canceled.", strna(d->name)); + else if (streq(d->result, "dependency")) + log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d->name)); +- else if (!streq(d->result, "done") && !streq(d->result, "skipped")) +- log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d->name), strna(d->name)); ++ else if (!streq(d->result, "done") && !streq(d->result, "skipped")) { ++ if (d->name) { ++ bool quotes; ++ ++ quotes = chars_intersect(d->name, SHELL_NEED_QUOTES); ++ ++ log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xn\" for details.", ++ d->name, ++ quotes ? "'" : "", d->name, quotes ? "'" : ""); ++ } else ++ log_error("Job failed. See \"journalctl -xn\" for details."); ++ } + } + + if (streq(d->result, "timeout")) diff --git a/0136-journalctl-Allow-to-disable-line-cap-with-lines-all.patch b/0136-journalctl-Allow-to-disable-line-cap-with-lines-all.patch new file mode 100644 index 0000000..abb77fd --- /dev/null +++ b/0136-journalctl-Allow-to-disable-line-cap-with-lines-all.patch @@ -0,0 +1,122 @@ +From 48382487666af141bb4385ceb5fb73c4147f6141 Mon Sep 17 00:00:00 2001 +From: Jan Janssen +Date: Sun, 31 Aug 2014 11:12:22 +0200 +Subject: [PATCH] journalctl: Allow to disable line cap with --lines=all + +--- + man/journalctl.xml | 13 +++++++------ + src/journal/journalctl.c | 42 +++++++++++++++++++++++------------------- + 2 files changed, 30 insertions(+), 25 deletions(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index d4e031619a..acd75a6370 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -189,9 +189,9 @@ + that the pager will not buffer logs of + unbounded size. This may be overridden + with an explicit +- with some other numeric value on the +- command line. Note that this option is +- only supported for the ++ with some other numeric value while ++ will disable this cap. ++ Note that this option is only supported for the + less1 + pager. + +@@ -204,9 +204,10 @@ + journal events and limit the number of + events shown. If + is used, +- this option is implied. The argument, +- a positive integer, is optional, and +- defaults to 10. ++ this option is implied. The argument is ++ a positive integer or all ++ to disable line limiting. The default value is ++ 10 if no argument is given. + + + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index f3680d1ce2..d00a815ba9 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -68,7 +68,7 @@ static bool arg_follow = false; + static bool arg_full = true; + static bool arg_all = false; + static bool arg_no_pager = false; +-static int arg_lines = -1; ++static int arg_lines = -2; + static bool arg_no_tail = false; + static bool arg_quiet = false; + static bool arg_merge = false; +@@ -327,7 +327,7 @@ static int parse_argv(int argc, char *argv[]) { + case 'e': + arg_pager_end = true; + +- if (arg_lines < 0) ++ if (arg_lines < -1) + arg_lines = 1000; + + break; +@@ -366,29 +366,33 @@ static int parse_argv(int argc, char *argv[]) { + + case 'n': + if (optarg) { +- r = safe_atoi(optarg, &arg_lines); +- if (r < 0 || arg_lines < 0) { +- log_error("Failed to parse lines '%s'", optarg); +- return -EINVAL; ++ if (streq(optarg, "all")) ++ arg_lines = -1; ++ else { ++ r = safe_atoi(optarg, &arg_lines); ++ if (r < 0 || arg_lines < 0) { ++ log_error("Failed to parse lines '%s'", optarg); ++ return -EINVAL; ++ } + } + } else { +- int n; ++ arg_lines = 10; + + /* Hmm, no argument? Maybe the next + * word on the command line is + * supposed to be the argument? Let's + * see if there is one, and is +- * parsable as a positive +- * integer... */ +- +- if (optind < argc && +- safe_atoi(argv[optind], &n) >= 0 && +- n >= 0) { +- +- arg_lines = n; +- optind++; +- } else +- arg_lines = 10; ++ * parsable. */ ++ if (optind < argc) { ++ int n; ++ if (streq(argv[optind], "all")) { ++ arg_lines = -1; ++ optind++; ++ } else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) { ++ arg_lines = n; ++ optind++; ++ } ++ } + } + + break; +@@ -642,7 +646,7 @@ static int parse_argv(int argc, char *argv[]) { + assert_not_reached("Unhandled option"); + } + +- if (arg_follow && !arg_no_tail && arg_lines < 0) ++ if (arg_follow && !arg_no_tail && arg_lines < -1) + arg_lines = 10; + + if (!!arg_directory + !!arg_file + !!arg_machine > 1) { diff --git a/0137-missing-add-IFF_MULTI_QUEUE.patch b/0137-missing-add-IFF_MULTI_QUEUE.patch new file mode 100644 index 0000000..8d7eda4 --- /dev/null +++ b/0137-missing-add-IFF_MULTI_QUEUE.patch @@ -0,0 +1,27 @@ +From 04d180c8a8641c209eb19d1210b5d4e36f0ae05b Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sun, 31 Aug 2014 18:50:23 +0200 +Subject: [PATCH] missing: add IFF_MULTI_QUEUE + +This was added in 3.8, but we should building with 3.7 headers. + +Reported by Samuli Suominen . +--- + src/shared/missing.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index c80ed2ad99..023c680ec6 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -558,6 +558,10 @@ static inline int setns(int fd, int nstype) { + #define IPV6_UNICAST_IF 76 + #endif + ++#ifndef IFF_MULTI_QUEUE ++#define IFF_MULTI_QUEUE 0x100 ++#endif ++ + #ifndef IFF_LOWER_UP + #define IFF_LOWER_UP 0x10000 + #endif diff --git a/0138-test-network-fix-off-by-one-error-in-test.patch b/0138-test-network-fix-off-by-one-error-in-test.patch new file mode 100644 index 0000000..203ddb7 --- /dev/null +++ b/0138-test-network-fix-off-by-one-error-in-test.patch @@ -0,0 +1,26 @@ +From 5bb14c8651b017983bb9cbd1444969c7a1bda14e Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sun, 31 Aug 2014 19:22:33 +0200 +Subject: [PATCH] test-network: fix off-by-one error in test + +--- + src/network/test-network.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/network/test-network.c b/src/network/test-network.c +index 3dc051dd92..ea9f938649 100644 +--- a/src/network/test-network.c ++++ b/src/network/test-network.c +@@ -96,9 +96,9 @@ static void test_deserialize_dhcp_routes(void) { + assert_se(routes[0].gw_addr.s_addr == inet_addr("192.168.0.1")); + assert_se(routes[0].dst_prefixlen == 16); + +- assert_se(routes[2].dst_addr.s_addr == inet_addr("0.0.0.0")); +- assert_se(routes[2].gw_addr.s_addr == inet_addr("10.0.1.1")); +- assert_se(routes[2].dst_prefixlen == 0); ++ assert_se(routes[1].dst_addr.s_addr == inet_addr("0.0.0.0")); ++ assert_se(routes[1].gw_addr.s_addr == inet_addr("10.0.1.1")); ++ assert_se(routes[1].dst_prefixlen == 0); + } + + { diff --git a/0139-journal-remote-fix-check-if-realloc-failed.patch b/0139-journal-remote-fix-check-if-realloc-failed.patch new file mode 100644 index 0000000..5e8a7c0 --- /dev/null +++ b/0139-journal-remote-fix-check-if-realloc-failed.patch @@ -0,0 +1,22 @@ +From e4c38cc36e287d46a56a98066cc368ee6fdd1968 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sun, 31 Aug 2014 22:54:40 +0200 +Subject: [PATCH] journal-remote: fix check if realloc failed + +--- + src/journal-remote/journal-remote-parse.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c +index dfb87d49af..e7eb1516fb 100644 +--- a/src/journal-remote/journal-remote-parse.c ++++ b/src/journal-remote/journal-remote-parse.c +@@ -478,7 +478,7 @@ int process_source(RemoteSource *source, bool compress, bool seal) { + char *tmp; + + tmp = realloc(source->buf, target); +- if (tmp) ++ if (!tmp) + log_warning("Failed to reallocate buffer to (smaller) size %zu", + target); + else { diff --git a/0140-config-parser-fix-mem-leak.patch b/0140-config-parser-fix-mem-leak.patch new file mode 100644 index 0000000..2fe8bc0 --- /dev/null +++ b/0140-config-parser-fix-mem-leak.patch @@ -0,0 +1,21 @@ +From 9e60277835e61597011358afcdbfb3dd712ce128 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sun, 31 Aug 2014 23:13:12 +0200 +Subject: [PATCH] config-parser: fix mem leak + +--- + src/shared/conf-parser.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c +index 439cfc58fc..ee6de653e1 100644 +--- a/src/shared/conf-parser.c ++++ b/src/shared/conf-parser.c +@@ -710,6 +710,7 @@ int config_parse_strv(const char *unit, + + if (!utf8_is_valid(n)) { + log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); ++ free(n); + continue; + } + diff --git a/0141-login-fix-mem-leak.patch b/0141-login-fix-mem-leak.patch new file mode 100644 index 0000000..702b2ec --- /dev/null +++ b/0141-login-fix-mem-leak.patch @@ -0,0 +1,25 @@ +From 13f493dc9ace9861c1f27c4d37e8cd6d52fe6a32 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sun, 31 Aug 2014 23:34:01 +0200 +Subject: [PATCH] login: fix mem leak + +--- + src/login/logind-session.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 0c6e425603..58453b516f 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -1114,8 +1114,10 @@ int session_set_controller(Session *s, const char *sender, bool force) { + * If logind crashes/restarts, we restore the controller during restart + * or reset the VT in case it crashed/exited, too. */ + r = session_prepare_vt(s); +- if (r < 0) ++ if (r < 0) { ++ free(t); + return r; ++ } + + session_swap_controller(s, t); + diff --git a/0142-login-simplify-controller-handling.patch b/0142-login-simplify-controller-handling.patch new file mode 100644 index 0000000..fa4b2d8 --- /dev/null +++ b/0142-login-simplify-controller-handling.patch @@ -0,0 +1,115 @@ +From b12e56156e5f363ebb8dc4ea5c10f5fd0665dc9d Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 1 Sep 2014 14:04:44 +0200 +Subject: [PATCH] login: simplify controller handling + +Simplify the way we handler session-controllers and fix several +shortcomings: + * send ReleaseDevice() signals on forced session takeover + * fix mem-leaks for busnames in case VT preparation fails (non-critical) + * avoid passing pre-allocated names to helpers +--- + src/login/logind-session.c | 55 +++++++++++++++++++++++----------------------- + 1 file changed, 28 insertions(+), 27 deletions(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 58453b516f..10a43a4a30 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -1059,32 +1059,30 @@ bool session_is_controller(Session *s, const char *sender) { + return streq_ptr(s->controller, sender); + } + +-static void session_swap_controller(Session *s, char *name) { ++static void session_release_controller(Session *s, bool notify) { ++ _cleanup_free_ char *name = NULL; + SessionDevice *sd; +- char *c; + +- if (s->controller) { +- c = s->controller; +- s->controller = NULL; +- manager_drop_busname(s->manager, c); +- free(c); ++ if (!s->controller) ++ return; + +- /* Drop all devices as they're now unused. Do that after the +- * controller is released to avoid sending out useles +- * dbus signals. */ +- while ((sd = hashmap_first(s->devices))) +- session_device_free(sd); ++ name = s->controller; + +- if (!name) +- session_restore_vt(s); +- } ++ /* By resetting the controller before releasing the devices, we won't ++ * send notification signals. This avoids sending useless notifications ++ * if the controller is released on disconnects. */ ++ if (!notify) ++ s->controller = NULL; + +- s->controller = name; +- session_save(s); ++ while ((sd = hashmap_first(s->devices))) ++ session_device_free(sd); ++ ++ s->controller = NULL; ++ manager_drop_busname(s->manager, name); + } + + int session_set_controller(Session *s, const char *sender, bool force) { +- char *t; ++ _cleanup_free_ char *name = NULL; + int r; + + assert(s); +@@ -1095,15 +1093,13 @@ int session_set_controller(Session *s, const char *sender, bool force) { + if (s->controller && !force) + return -EBUSY; + +- t = strdup(sender); +- if (!t) ++ name = strdup(sender); ++ if (!name) + return -ENOMEM; + +- r = manager_watch_busname(s->manager, sender); +- if (r) { +- free(t); ++ r = manager_watch_busname(s->manager, name); ++ if (r) + return r; +- } + + /* When setting a session controller, we forcibly mute the VT and set + * it into graphics-mode. Applications can override that by changing +@@ -1115,11 +1111,14 @@ int session_set_controller(Session *s, const char *sender, bool force) { + * or reset the VT in case it crashed/exited, too. */ + r = session_prepare_vt(s); + if (r < 0) { +- free(t); ++ manager_drop_busname(s->manager, name); + return r; + } + +- session_swap_controller(s, t); ++ session_release_controller(s, true); ++ s->controller = name; ++ name = NULL; ++ session_save(s); + + return 0; + } +@@ -1130,7 +1129,9 @@ void session_drop_controller(Session *s) { + if (!s->controller) + return; + +- session_swap_controller(s, NULL); ++ session_release_controller(s, false); ++ session_save(s); ++ session_restore_vt(s); + } + + static const char* const session_state_table[_SESSION_STATE_MAX] = { diff --git a/0143-rules-remove-firmware-loading-rules.patch b/0143-rules-remove-firmware-loading-rules.patch new file mode 100644 index 0000000..9c0aa4e --- /dev/null +++ b/0143-rules-remove-firmware-loading-rules.patch @@ -0,0 +1,24 @@ +From 70e7d754ddb356fb1a2942b262f8cee9650e2a19 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 1 Sep 2014 12:55:23 -0400 +Subject: [PATCH] rules: remove firmware loading rules + +blueness> poettering, was there a reason for not removing + 50-firmware.rules when you nuked userland firmware + loading? + +Followup for v216-119-gbe2ea723b1. +--- + rules/50-firmware.rules | 3 --- + 1 file changed, 3 deletions(-) + delete mode 100644 rules/50-firmware.rules + +diff --git a/rules/50-firmware.rules b/rules/50-firmware.rules +deleted file mode 100644 +index f0ae684518..0000000000 +--- a/rules/50-firmware.rules ++++ /dev/null +@@ -1,3 +0,0 @@ +-# do not edit this file, it will be overwritten on update +- +-SUBSYSTEM=="firmware", ACTION=="add", RUN{builtin}="firmware" diff --git a/0144-sd-rtnl-don-t-assign-to-unused-variable.patch b/0144-sd-rtnl-don-t-assign-to-unused-variable.patch new file mode 100644 index 0000000..e1a880f --- /dev/null +++ b/0144-sd-rtnl-don-t-assign-to-unused-variable.patch @@ -0,0 +1,22 @@ +From cedc611207b6a14cdbaf1d73e12b62ee55cc53de Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 1 Sep 2014 22:59:52 +0200 +Subject: [PATCH] sd-rtnl: don't assign to unused variable + +Reported by Thomas H.P. Andersen . +--- + src/libsystemd/sd-rtnl/rtnl-message.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c +index 906a9de1c0..30e33584c4 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-message.c ++++ b/src/libsystemd/sd-rtnl/rtnl-message.c +@@ -531,7 +531,6 @@ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, + /* if no data was passed, make sure we still initialize the padding + note that we can have data_length > 0 (used by some containers) */ + padding = RTA_DATA(rta); +- data_length = 0; + } + + /* make sure also the padding at the end of the message is initialized */ diff --git a/0145-timesyncd-wait-before-reconnecting-to-first-server.patch b/0145-timesyncd-wait-before-reconnecting-to-first-server.patch new file mode 100644 index 0000000..dffbd67 --- /dev/null +++ b/0145-timesyncd-wait-before-reconnecting-to-first-server.patch @@ -0,0 +1,83 @@ +From 63463bf091949e0178b749016828ec400c106582 Mon Sep 17 00:00:00 2001 +From: Miroslav Lichvar +Date: Wed, 27 Aug 2014 16:47:24 +0200 +Subject: [PATCH] timesyncd: wait before reconnecting to first server + +When all servers are exhausted, wait for one poll interval before trying +to connect again to the first server in the list. Also, keep increasing +the polling interval to make sure a client not getting any valid replies +will not send requests to any server more frequently than is allowed by +the maximum polling interval. +--- + src/timesync/timesyncd-manager.c | 24 +++++++++++++++++++++++- + src/timesync/timesyncd-manager.h | 1 + + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 696dd10e69..b7b39ef822 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -875,6 +875,7 @@ int manager_connect(Manager *m) { + manager_set_server_name(m, m->current_server_name->names_next); + else { + ServerName *f; ++ bool restart = true; + + /* Our current server name list is exhausted, + * let's find the next one to iterate. First +@@ -891,6 +892,8 @@ int manager_connect(Manager *m) { + f = m->link_servers; + if (!f) + f = m->system_servers; ++ else ++ restart = false; + } + + if (!f) +@@ -902,6 +905,25 @@ int manager_connect(Manager *m) { + return 0; + } + ++ if (restart && !m->exhausted_servers && m->poll_interval_usec) { ++ log_debug("Waiting after exhausting servers."); ++ r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + m->poll_interval_usec, 0, manager_retry_connect, m); ++ if (r < 0) { ++ log_error("Failed to create retry timer: %s", strerror(-r)); ++ return r; ++ } ++ ++ m->exhausted_servers = true; ++ ++ /* Increase the polling interval */ ++ if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC) ++ m->poll_interval_usec *= 2; ++ ++ return 0; ++ } ++ ++ m->exhausted_servers = false; ++ + manager_set_server_name(m, f); + } + +@@ -1042,7 +1064,7 @@ static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t re + online = network_is_online(); + + /* check if the client is currently connected */ +- connected = m->server_socket >= 0 || m->resolve_query; ++ connected = m->server_socket >= 0 || m->resolve_query || m->exhausted_servers; + + if (connected && !online) { + log_info("No network connectivity, watching for changes."); +diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h +index 2345bf8f36..bb3e50915e 100644 +--- a/src/timesync/timesyncd-manager.h ++++ b/src/timesync/timesyncd-manager.h +@@ -41,6 +41,7 @@ struct Manager { + LIST_HEAD(ServerName, fallback_servers); + + RateLimit ratelimit; ++ bool exhausted_servers; + + /* network */ + sd_event_source *network_event_source; diff --git a/0146-timesyncd-remove-retry_timer-logic-which-is-covered-.patch b/0146-timesyncd-remove-retry_timer-logic-which-is-covered-.patch new file mode 100644 index 0000000..6586010 --- /dev/null +++ b/0146-timesyncd-remove-retry_timer-logic-which-is-covered-.patch @@ -0,0 +1,55 @@ +From 665c6a9eab46b0b253af6566ca9fc70c866b3fcd Mon Sep 17 00:00:00 2001 +From: Kay Sievers +Date: Tue, 2 Sep 2014 14:27:00 +0200 +Subject: [PATCH] timesyncd: remove retry_timer logic which is covered by the + server timeout + +--- + src/timesync/timesyncd-manager.c | 14 -------------- + src/timesync/timesyncd-manager.h | 1 - + 2 files changed, 15 deletions(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index b7b39ef822..19a28f37e2 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -206,19 +206,6 @@ static int manager_send_request(Manager *m) { + return manager_connect(m); + } + +- /* re-arm timer with increasing timeout, in case the packets never arrive back */ +- if (m->retry_interval > 0) { +- if (m->retry_interval < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC) +- m->retry_interval *= 2; +- } else +- m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; +- +- r = manager_arm_timer(m, m->retry_interval); +- if (r < 0) { +- log_error("Failed to rearm timer: %s", strerror(-r)); +- return r; +- } +- + r = sd_event_add_time( + m->event, + &m->event_timeout, +@@ -601,7 +588,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + + /* valid packet */ + m->pending = false; +- m->retry_interval = 0; + + /* announce leap seconds */ + if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC) +diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h +index bb3e50915e..0ac0e179c1 100644 +--- a/src/timesync/timesyncd-manager.h ++++ b/src/timesync/timesyncd-manager.h +@@ -59,7 +59,6 @@ struct Manager { + /* last sent packet */ + struct timespec trans_time_mon; + struct timespec trans_time; +- usec_t retry_interval; + bool pending; + + /* poll timer */ diff --git a/0147-timesyncd-allow-two-missed-replies-before-reselectin.patch b/0147-timesyncd-allow-two-missed-replies-before-reselectin.patch new file mode 100644 index 0000000..7790163 --- /dev/null +++ b/0147-timesyncd-allow-two-missed-replies-before-reselectin.patch @@ -0,0 +1,84 @@ +From e8206972be6a7ebeb198cd0d400bc7a94a6a5fc5 Mon Sep 17 00:00:00 2001 +From: Miroslav Lichvar +Date: Tue, 2 Sep 2014 14:29:51 +0200 +Subject: [PATCH] timesyncd: allow two missed replies before reselecting server + +After receiving a reply from the server, allow two missed replies before +switching to another server to avoid unnecessary clock hopping when +packets are getting lost in the network. +--- + src/timesync/timesyncd-manager.c | 27 ++++++++++++++++++--------- + src/timesync/timesyncd-manager.h | 1 + + 2 files changed, 19 insertions(+), 9 deletions(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 19a28f37e2..a66852d7d2 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -92,6 +92,9 @@ + /* Maximum acceptable root distance in seconds. */ + #define NTP_MAX_ROOT_DISTANCE 5.0 + ++/* Maximum number of missed replies before selecting another source. */ ++#define NTP_MAX_MISSED_REPLIES 2 ++ + /* + * "NTP timestamps are represented as a 64-bit unsigned fixed-point number, + * in seconds relative to 0h on 1 January 1900." +@@ -206,15 +209,18 @@ static int manager_send_request(Manager *m) { + return manager_connect(m); + } + +- r = sd_event_add_time( +- m->event, +- &m->event_timeout, +- clock_boottime_or_monotonic(), +- now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0, +- manager_timeout, m); +- if (r < 0) { +- log_error("Failed to arm timeout timer: %s", strerror(-r)); +- return r; ++ m->missed_replies++; ++ if (m->missed_replies > NTP_MAX_MISSED_REPLIES) { ++ r = sd_event_add_time( ++ m->event, ++ &m->event_timeout, ++ clock_boottime_or_monotonic(), ++ now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0, ++ manager_timeout, m); ++ if (r < 0) { ++ log_error("Failed to arm timeout timer: %s", strerror(-r)); ++ return r; ++ } + } + + return 0; +@@ -549,6 +555,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + return 0; + } + ++ m->missed_replies = 0; ++ + /* check our "time cookie" (we just stored nanoseconds in the fraction field) */ + if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 || + be32toh(ntpmsg.origin_time.frac) != m->trans_time.tv_nsec) { +@@ -712,6 +720,7 @@ static int manager_begin(Manager *m) { + assert_return(m->current_server_name, -EHOSTUNREACH); + assert_return(m->current_server_address, -EHOSTUNREACH); + ++ m->missed_replies = NTP_MAX_MISSED_REPLIES; + m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; + + server_address_pretty(m->current_server_address, &pretty); +diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h +index 0ac0e179c1..8296d41295 100644 +--- a/src/timesync/timesyncd-manager.h ++++ b/src/timesync/timesyncd-manager.h +@@ -53,6 +53,7 @@ struct Manager { + ServerName *current_server_name; + ServerAddress *current_server_address; + int server_socket; ++ int missed_replies; + uint64_t packet_count; + sd_event_source *event_timeout; + diff --git a/0148-timesyncd-don-t-reset-polling-interval-when-reselect.patch b/0148-timesyncd-don-t-reset-polling-interval-when-reselect.patch new file mode 100644 index 0000000..bca140e --- /dev/null +++ b/0148-timesyncd-don-t-reset-polling-interval-when-reselect.patch @@ -0,0 +1,25 @@ +From 80cd2606b91ce2735a0609c6f964917cf12685aa Mon Sep 17 00:00:00 2001 +From: Kay Sievers +Date: Tue, 2 Sep 2014 14:33:59 +0200 +Subject: [PATCH] timesyncd: don't reset polling interval when reselecting + server + +Original patch from: Miroslav Lichvar +--- + src/timesync/timesyncd-manager.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index a66852d7d2..3261bc1fb1 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -721,7 +721,8 @@ static int manager_begin(Manager *m) { + assert_return(m->current_server_address, -EHOSTUNREACH); + + m->missed_replies = NTP_MAX_MISSED_REPLIES; +- m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; ++ if (m->poll_interval_usec == 0) ++ m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; + + server_address_pretty(m->current_server_address, &pretty); + log_info("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string); diff --git a/0149-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch b/0149-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch new file mode 100644 index 0000000..7757413 --- /dev/null +++ b/0149-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch @@ -0,0 +1,61 @@ +From ab4df227d466e881e4279821b5fc1563f0e7e933 Mon Sep 17 00:00:00 2001 +From: Kay Sievers +Date: Tue, 2 Sep 2014 15:28:56 +0200 +Subject: [PATCH] Revert "timesyncd: remove retry_timer logic which is covered + by the server timeout" + +This reverts commit 665c6a9eab46b0b253af6566ca9fc70c866b3fcd. + +On Tue, Sep 2, 2014 at 3:17 PM, Miroslav Lichvar wrote: +> +> With the other patch allowing missed replies included it's now getting +> stuck as there is no timer to send the 2nd and 3rd request. +--- + src/timesync/timesyncd-manager.c | 14 ++++++++++++++ + src/timesync/timesyncd-manager.h | 1 + + 2 files changed, 15 insertions(+) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 3261bc1fb1..a5678ccaed 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -209,6 +209,19 @@ static int manager_send_request(Manager *m) { + return manager_connect(m); + } + ++ /* re-arm timer with increasing timeout, in case the packets never arrive back */ ++ if (m->retry_interval > 0) { ++ if (m->retry_interval < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC) ++ m->retry_interval *= 2; ++ } else ++ m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; ++ ++ r = manager_arm_timer(m, m->retry_interval); ++ if (r < 0) { ++ log_error("Failed to rearm timer: %s", strerror(-r)); ++ return r; ++ } ++ + m->missed_replies++; + if (m->missed_replies > NTP_MAX_MISSED_REPLIES) { + r = sd_event_add_time( +@@ -596,6 +609,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + + /* valid packet */ + m->pending = false; ++ m->retry_interval = 0; + + /* announce leap seconds */ + if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC) +diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h +index 8296d41295..c7efdc5dfb 100644 +--- a/src/timesync/timesyncd-manager.h ++++ b/src/timesync/timesyncd-manager.h +@@ -60,6 +60,7 @@ struct Manager { + /* last sent packet */ + struct timespec trans_time_mon; + struct timespec trans_time; ++ usec_t retry_interval; + bool pending; + + /* poll timer */ diff --git a/0150-man-fix-file-extension-in-udev-rules-example.patch b/0150-man-fix-file-extension-in-udev-rules-example.patch new file mode 100644 index 0000000..1ee44a4 --- /dev/null +++ b/0150-man-fix-file-extension-in-udev-rules-example.patch @@ -0,0 +1,23 @@ +From a7a0912a36307567043e1939f6065ff54fa8fd66 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 2 Sep 2014 19:37:04 -0400 +Subject: [PATCH] man: fix file extension in udev rules example + +https://bugzilla.redhat.com/show_bug.cgi?id=634736 +--- + man/sysctl.d.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml +index dd73f92236..5529fc98bf 100644 +--- a/man/sysctl.d.xml ++++ b/man/sysctl.d.xml +@@ -155,7 +155,7 @@ + + + Disable packet filter on bridged packets (method one) +- /etc/udev/rules.d/99-bridge.conf: ++ /etc/udev/rules.d/99-bridge.rules: + + + ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge" diff --git a/0151-base_filesystem_create-do-not-try-to-create-root-if-.patch b/0151-base_filesystem_create-do-not-try-to-create-root-if-.patch new file mode 100644 index 0000000..e78d301 --- /dev/null +++ b/0151-base_filesystem_create-do-not-try-to-create-root-if-.patch @@ -0,0 +1,39 @@ +From 6f4f8056d3f972c1e6ee7f5fc40ed283fd93152a Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Wed, 3 Sep 2014 13:22:40 +0200 +Subject: [PATCH] base_filesystem_create: do not try to create "/root" if it + exists + +The check, if the directory/file already exists is only executed, if +there is a symlink target specified. In case of "/root", there is none, +so it is unconditionally tried to create the directory. + +In case of a readonly filesystem, errno != EEXIST, but errno == EROFS, +so base_filesystem_create() and switch_root does not succeed. + +This patch checks for existance not only in the symlink case. +--- + src/shared/base-filesystem.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c +index addd26ca39..ba8b829ab3 100644 +--- a/src/shared/base-filesystem.c ++++ b/src/shared/base-filesystem.c +@@ -62,13 +62,13 @@ int base_filesystem_create(const char *root) { + return -errno; + + for (i = 0; i < ELEMENTSOF(table); i ++) { ++ if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) ++ continue; ++ + if (table[i].target) { + const char *target = NULL; + const char *s; + +- if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) +- continue; +- + /* check if one of the targets exists */ + NULSTR_FOREACH(s, table[i].target) { + if (faccessat(fd, s, F_OK, AT_SYMLINK_NOFOLLOW) < 0) diff --git a/0152-initrd-parse-etc.service-ignore-return-code-of-daemo.patch b/0152-initrd-parse-etc.service-ignore-return-code-of-daemo.patch new file mode 100644 index 0000000..ffcc634 --- /dev/null +++ b/0152-initrd-parse-etc.service-ignore-return-code-of-daemo.patch @@ -0,0 +1,25 @@ +From f3b8fbb1da6519e14985ea444f8304673d20ad3f Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Wed, 3 Sep 2014 13:28:31 +0200 +Subject: [PATCH] initrd-parse-etc.service: ignore return code of daemon-reload + +It seems the return code of systemctl daemon-reload can be !=0 in some +circumstances, which causes a failure of the unit and breaks booting in +the initrd. +--- + units/initrd-parse-etc.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/initrd-parse-etc.service.in b/units/initrd-parse-etc.service.in +index c0b25430bc..42c059bbd2 100644 +--- a/units/initrd-parse-etc.service.in ++++ b/units/initrd-parse-etc.service.in +@@ -16,7 +16,7 @@ ConditionPathExists=/etc/initrd-release + + [Service] + Type=oneshot +-ExecStartPre=@rootbindir@/systemctl daemon-reload ++ExecStartPre=-@rootbindir@/systemctl daemon-reload + # we have to retrigger initrd-fs.target after daemon-reload + ExecStart=-@rootbindir@/systemctl --no-block start initrd-fs.target + ExecStart=@rootbindir@/systemctl --no-block start initrd-cleanup.service diff --git a/0153-update-TODO.patch b/0153-update-TODO.patch new file mode 100644 index 0000000..1620548 --- /dev/null +++ b/0153-update-TODO.patch @@ -0,0 +1,27 @@ +From 64e84dbb14463afe63418357e64a17ad5b04040b Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 3 Sep 2014 13:59:59 +0200 +Subject: [PATCH] update TODO + +Yum was creating /var/run/yum.pid and hence this directory +was created before filesystem package could create the symlink +/var/run -> /run. +This should be now fixed in yum. +--- + TODO | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/TODO b/TODO +index 221b39f1a9..299b938c44 100644 +--- a/TODO ++++ b/TODO +@@ -11,9 +11,6 @@ Bugfixes: + * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point. + + External: +-* Fedora: when installing fedora with yum --installroot /var/run is a directory, not a symlink +- https://bugzilla.redhat.com/show_bug.cgi?id=975864 +- + * Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros. + + * Fedora: post FPC ticket to move add %tmpfiles_create to the packaging guidelines diff --git a/0154-base-file-system-always-generate-error-messages-loca.patch b/0154-base-file-system-always-generate-error-messages-loca.patch new file mode 100644 index 0000000..08616f0 --- /dev/null +++ b/0154-base-file-system-always-generate-error-messages-loca.patch @@ -0,0 +1,39 @@ +From 6dc2852c643df4aa2580d42fc2d268bea0c5f57b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 3 Sep 2014 19:00:21 +0200 +Subject: [PATCH] base-file-system: always generate error messages locally + +Functions either should generate error messages for everything they do +themselves, or for nothing and let the caller do it. But they certainly +shouldn't generate errors for some messages but not for others. Since +the function in this case is one that generates messages on its own, it +really should do that for everything, not just for some things, hence. +--- + src/shared/base-filesystem.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c +index ba8b829ab3..4c65a495d3 100644 +--- a/src/shared/base-filesystem.c ++++ b/src/shared/base-filesystem.c +@@ -58,16 +58,17 @@ int base_filesystem_create(const char *root) { + int r; + + fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); +- if (fd < 0) ++ if (fd < 0) { ++ log_error("Failed to open root file system: %m"); + return -errno; ++ } + + for (i = 0; i < ELEMENTSOF(table); i ++) { + if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + continue; + + if (table[i].target) { +- const char *target = NULL; +- const char *s; ++ const char *target = NULL, *s; + + /* check if one of the targets exists */ + NULSTR_FOREACH(s, table[i].target) { diff --git a/0155-update-TODO.patch b/0155-update-TODO.patch new file mode 100644 index 0000000..b270d60 --- /dev/null +++ b/0155-update-TODO.patch @@ -0,0 +1,28 @@ +From 533bb267f13e2f7b4d7b78de30e821dc81c82335 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 3 Sep 2014 18:59:17 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/TODO b/TODO +index 299b938c44..208a4ce890 100644 +--- a/TODO ++++ b/TODO +@@ -21,6 +21,14 @@ External: + + Features: + ++* introduce machines.target to order after all nspawn instances ++ ++* systemd-nspawn@.service should fail if some nspawn arg is invalid, with Type=notify ++ ++* "machinectl list" should probably show columns for OS version and IP addresses ++ ++* systemctl: if it fails, show log output? ++ + * maybe add "systemctl edit" that copies unit files from /usr/lib/systemd/system to /etc/systemd/system and invokes vim on them + + * dbus: add new message hdr field for allowing interactive auth, write spec for it. update dbus spec to mandate that unknown flags *must* be ignored... diff --git a/0156-man-two-fixes-reported-on-irc-by-wget.patch b/0156-man-two-fixes-reported-on-irc-by-wget.patch new file mode 100644 index 0000000..44808a0 --- /dev/null +++ b/0156-man-two-fixes-reported-on-irc-by-wget.patch @@ -0,0 +1,36 @@ +From 2915a7bdc5c6db2298041cd39fa992cf252cd8a0 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 3 Sep 2014 19:31:22 +0200 +Subject: [PATCH] man: two fixes, reported on irc by 'wget' + +--- + man/systemd.unit.xml | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index c8d9300d95..a1fcfd8781 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -1256,9 +1256,10 @@ + + [Install] Section Options + +- Unit file may include a [Install] section, which +- carries installation information for the unit. This +- section is not interpreted by ++ Unit file may include an ++ [Install] section, which carries ++ installation information for the unit. This section is ++ not interpreted by + systemd1 + during runtime. It is used exclusively by the + enable and +@@ -1270,7 +1271,7 @@ + + Alias= + +- A space-seperated list ++ A space-separated list + of additional names this unit shall be + installed under. The names listed here + must have the same suffix (i.e. type) diff --git a/0157-build-sys-configure-option-to-disable-hibernation.patch b/0157-build-sys-configure-option-to-disable-hibernation.patch new file mode 100644 index 0000000..5a41836 --- /dev/null +++ b/0157-build-sys-configure-option-to-disable-hibernation.patch @@ -0,0 +1,152 @@ +From 4df5c00b6e5de8733f3bb33ee7980fad1a498789 Mon Sep 17 00:00:00 2001 +From: Umut Tezduyar Lindskog +Date: Tue, 2 Sep 2014 12:31:49 +0200 +Subject: [PATCH] build-sys: configure option to disable hibernation + +--- + Makefile.am | 52 ++++++++++++++++++++++++++++++++-------------------- + configure.ac | 6 ++++++ + 2 files changed, 38 insertions(+), 20 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 1991fd0e3b..58e5ce6c54 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -378,15 +378,13 @@ rootlibexec_PROGRAMS = \ + systemd-sleep \ + systemd-bus-proxyd \ + systemd-socket-proxyd \ +- systemd-update-done \ +- systemd-hibernate-resume ++ systemd-update-done + + systemgenerator_PROGRAMS = \ + systemd-getty-generator \ + systemd-fstab-generator \ + systemd-system-update-generator \ +- systemd-debug-generator \ +- systemd-hibernate-resume-generator ++ systemd-debug-generator + + dist_bashcompletion_DATA = \ + shell-completion/bash/busctl \ +@@ -453,7 +451,6 @@ dist_systemunit_DATA = \ + units/network-online.target \ + units/nss-lookup.target \ + units/nss-user-lookup.target \ +- units/hibernate.target \ + units/hybrid-sleep.target \ + units/poweroff.target \ + units/reboot.target \ +@@ -511,7 +508,6 @@ nodist_systemunit_DATA = \ + units/emergency.service \ + units/rescue.service \ + units/user@.service \ +- units/systemd-hibernate.service \ + units/systemd-hybrid-sleep.service \ + units/systemd-suspend.service \ + units/systemd-halt.service \ +@@ -530,8 +526,7 @@ nodist_systemunit_DATA = \ + units/initrd-udevadm-cleanup-db.service \ + units/initrd-switch-root.service \ + units/systemd-nspawn@.service \ +- units/systemd-update-done.service \ +- units/systemd-hibernate-resume@.service ++ units/systemd-update-done.service + + dist_userunit_DATA = \ + units/user/basic.target \ +@@ -569,7 +564,6 @@ EXTRA_DIST += \ + units/systemd-fsck-root.service.in \ + units/user@.service.in \ + units/debug-shell.service.in \ +- units/systemd-hibernate.service.in \ + units/systemd-hybrid-sleep.service.in \ + units/systemd-suspend.service.in \ + units/quotaon.service.in \ +@@ -578,8 +572,7 @@ EXTRA_DIST += \ + units/initrd-udevadm-cleanup-db.service.in \ + units/initrd-switch-root.service.in \ + units/systemd-nspawn@.service.in \ +- units/systemd-update-done.service.in \ +- units/systemd-hibernate-resume@.service.in ++ units/systemd-update-done.service.in + + CLEANFILES += \ + units/console-shell.service.m4 \ +@@ -2112,14 +2105,6 @@ systemd_delta_LDADD = \ + libsystemd-shared.la + + # ------------------------------------------------------------------------------ +-systemd_hibernate_resume_SOURCES = \ +- src/hibernate-resume/hibernate-resume.c +- +-systemd_hibernate_resume_LDADD = \ +- libsystemd-internal.la \ +- libsystemd-shared.la +- +-# ------------------------------------------------------------------------------ + systemd_getty_generator_SOURCES = \ + src/getty-generator/getty-generator.c + +@@ -2153,6 +2138,20 @@ systemd_system_update_generator_LDADD = \ + libsystemd-shared.la + + # ------------------------------------------------------------------------------ ++if ENABLE_HIBERNATE ++systemgenerator_PROGRAMS += \ ++ systemd-hibernate-resume-generator ++ ++rootlibexec_PROGRAMS += \ ++ systemd-hibernate-resume ++ ++systemd_hibernate_resume_SOURCES = \ ++ src/hibernate-resume/hibernate-resume.c ++ ++systemd_hibernate_resume_LDADD = \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la ++ + systemd_hibernate_resume_generator_SOURCES = \ + src/resume-generator/resume-generator.c + +@@ -2160,8 +2159,21 @@ systemd_hibernate_resume_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +-if ENABLE_EFI ++EXTRA_DIST += \ ++ units/systemd-hibernate.service.in \ ++ units/systemd-hibernate-resume@.service.in ++ ++dist_systemunit_DATA += \ ++ units/hibernate.target ++ ++nodist_systemunit_DATA += \ ++ units/systemd-hibernate.service \ ++ units/systemd-hibernate-resume@.service ++ ++endif ++ + # ------------------------------------------------------------------------------ ++if ENABLE_EFI + systemgenerator_PROGRAMS += \ + systemd-efi-boot-generator + +diff --git a/configure.ac b/configure.ac +index 543828c405..99c01d2487 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1168,6 +1168,12 @@ AS_IF([test "x$enable_manpages" != xno], [have_manpages=yes]) + AM_CONDITIONAL(ENABLE_MANPAGES, [test "x$have_manpages" = "xyes"]) + + # ------------------------------------------------------------------------------ ++AC_ARG_ENABLE(hibernate, ++ [AC_HELP_STRING([--disable-hibernate], [disable hibernation support])], ++ enable_hibernate=$enableval, enable_hibernate=yes) ++AM_CONDITIONAL(ENABLE_HIBERNATE, [test x$enable_hibernate = xyes]) ++ ++# ------------------------------------------------------------------------------ + AC_ARG_ENABLE(ldconfig, + [AC_HELP_STRING([--disable-ldconfig], [disable ldconfig])], + enable_ldconfig=$enableval, enable_ldconfig=yes) diff --git a/0158-localed-double-free-in-error-path-and-modernization.patch b/0158-localed-double-free-in-error-path-and-modernization.patch new file mode 100644 index 0000000..a901968 --- /dev/null +++ b/0158-localed-double-free-in-error-path-and-modernization.patch @@ -0,0 +1,230 @@ +From 28efac0d37ceb5093a804da6a00c620034c5484f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 10:28:24 -0400 +Subject: [PATCH] localed: double free in error path and modernization + +Very unlikely to trigger, but in principle strv_free +could be called twice: once explictly, and once from cleanup. +--- + src/locale/localed.c | 66 +++++++++++++++++----------------------------------- + 1 file changed, 21 insertions(+), 45 deletions(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index 4d22568787..c9f7105bb3 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -208,7 +208,7 @@ static int vconsole_read_data(Context *c) { + } + + static int x11_read_data(Context *c) { +- FILE *f; ++ _cleanup_fclose_ FILE *f; + char line[LINE_MAX]; + bool in_section = false; + int r; +@@ -229,13 +229,11 @@ static int x11_read_data(Context *c) { + continue; + + if (in_section && first_word(l, "Option")) { +- char **a; ++ _cleanup_strv_free_ char **a = NULL; + + r = strv_split_quoted(&a, l); +- if (r < 0) { +- fclose(f); ++ if (r < 0) + return r; +- } + + if (strv_length(a) == 3) { + if (streq(a[1], "XkbLayout")) { +@@ -253,27 +251,20 @@ static int x11_read_data(Context *c) { + } + } + +- strv_free(a); +- + } else if (!in_section && first_word(l, "Section")) { +- char **a; ++ _cleanup_strv_free_ char **a = NULL; + + r = strv_split_quoted(&a, l); +- if (r < 0) { +- fclose(f); ++ if (r < 0) + return -ENOMEM; +- } + + if (strv_length(a) == 2 && streq(a[1], "InputClass")) + in_section = true; + +- strv_free(a); + } else if (in_section && first_word(l, "EndSection")) + in_section = false; + } + +- fclose(f); +- + return 0; + } + +@@ -289,14 +280,15 @@ static int context_read_data(Context *c) { + + static int locale_write_data(Context *c) { + int r, p; +- char **l = NULL; ++ _cleanup_strv_free_ char **l = NULL; + + r = load_env_file(NULL, "/etc/locale.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + for (p = 0; p < _LOCALE_MAX; p++) { +- char *t, **u; ++ _cleanup_free_ char *t = NULL; ++ char **u; + + assert(names[p]); + +@@ -305,34 +297,25 @@ static int locale_write_data(Context *c) { + continue; + } + +- if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) { +- strv_free(l); ++ if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) + return -ENOMEM; +- } + + u = strv_env_set(l, t); +- free(t); +- strv_free(l); +- + if (!u) + return -ENOMEM; + ++ strv_free(l); + l = u; + } + + if (strv_isempty(l)) { +- strv_free(l); +- + if (unlink("/etc/locale.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + +- r = write_env_file_label("/etc/locale.conf", l); +- strv_free(l); +- +- return r; ++ return write_env_file_label("/etc/locale.conf", l); + } + + static int locale_update_system_manager(Context *c, sd_bus *bus) { +@@ -403,38 +386,36 @@ static int vconsole_write_data(Context *c) { + if (isempty(c->vc_keymap)) + l = strv_env_unset(l, "KEYMAP"); + else { +- char *s, **u; ++ _cleanup_free_ char *s = NULL; ++ char **u; + + s = strappend("KEYMAP=", c->vc_keymap); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); +- free(s); +- strv_free(l); +- + if (!u) + return -ENOMEM; + ++ strv_free(l); + l = u; + } + + if (isempty(c->vc_keymap_toggle)) + l = strv_env_unset(l, "KEYMAP_TOGGLE"); + else { +- char *s, **u; ++ _cleanup_free_ char *s = NULL; ++ char **u; + + s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); +- free(s); +- strv_free(l); +- + if (!u) + return -ENOMEM; + ++ strv_free(l); + l = u; + } + +@@ -445,8 +426,7 @@ static int vconsole_write_data(Context *c) { + return 0; + } + +- r = write_env_file_label("/etc/vconsole.conf", l); +- return r; ++ return write_env_file_label("/etc/vconsole.conf", l); + } + + static int write_data_x11(Context *c) { +@@ -868,13 +848,12 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + } + + /* Check whether a variable is unset */ +- if (!modified) { ++ if (!modified) + for (p = 0; p < _LOCALE_MAX; p++) + if (!isempty(c->locale[p]) && !passed[p]) { + modified = true; + break; + } +- } + + if (modified) { + r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-locale", interactive, &c->polkit_registry, error); +@@ -883,7 +862,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + +- STRV_FOREACH(i, l) { ++ STRV_FOREACH(i, l) + for (p = 0; p < _LOCALE_MAX; p++) { + size_t k; + +@@ -900,7 +879,6 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + break; + } + } +- } + + for (p = 0; p < _LOCALE_MAX; p++) { + if (passed[p]) +@@ -1112,7 +1090,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { + } + + int main(int argc, char *argv[]) { +- Context context = {}; ++ _cleanup_(context_free) Context context = {}; + _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_bus_close_unref_ sd_bus *bus = NULL; + int r; +@@ -1155,7 +1133,5 @@ int main(int argc, char *argv[]) { + } + + finish: +- context_free(&context); +- + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + } diff --git a/0159-localed-remove-free_and_copy.patch b/0159-localed-remove-free_and_copy.patch new file mode 100644 index 0000000..4785282 --- /dev/null +++ b/0159-localed-remove-free_and_copy.patch @@ -0,0 +1,188 @@ +From af76d302c1e26f916494202f1b3663f15710bdcd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 22:53:23 -0400 +Subject: [PATCH] localed: remove free_and_copy + +It was mostly a duplicate of free_and_strdup(). +--- + src/locale/localed.c | 67 +++++++++++++++++++--------------------------------- + src/shared/util.c | 18 -------------- + src/shared/util.h | 2 -- + 3 files changed, 24 insertions(+), 63 deletions(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index c9f7105bb3..ac8477ad39 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -92,20 +92,8 @@ typedef struct Context { + Hashmap *polkit_registry; + } Context; + +-static int free_and_copy(char **s, const char *v) { +- int r; +- char *t; +- +- assert(s); +- +- r = strdup_or_null(isempty(v) ? NULL : v, &t); +- if (r < 0) +- return r; +- +- free(*s); +- *s = t; +- +- return 0; ++static const char* nonempty(const char *s) { ++ return isempty(s) ? NULL : s; + } + + static void free_and_replace(char **s, char *v) { +@@ -144,10 +132,8 @@ static void locale_simplify(Context *c) { + int p; + + for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++) +- if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) { +- free(c->locale[p]); +- c->locale[p] = NULL; +- } ++ if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) ++ free_and_replace(&c->locale[p], NULL); + } + + static int locale_read_data(Context *c) { +@@ -179,7 +165,8 @@ static int locale_read_data(Context *c) { + for (p = 0; p < _LOCALE_MAX; p++) { + assert(names[p]); + +- r = free_and_copy(&c->locale[p], getenv(names[p])); ++ r = free_and_strdup(&c->locale[p], ++ nonempty(getenv(names[p]))); + if (r < 0) + return r; + } +@@ -503,8 +490,8 @@ static int vconsole_reload(sd_bus *bus) { + return r; + } + +-static char *strnulldash(const char *s) { +- return s == NULL || *s == 0 || (s[0] == '-' && s[1] == 0) ? NULL : (char*) s; ++static const char* strnulldash(const char *s) { ++ return isempty(s) || streq(s, "-") ? NULL : s; + } + + static int read_next_mapping(FILE *f, unsigned *n, char ***a) { +@@ -588,10 +575,10 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { + !streq_ptr(c->x11_variant, strnulldash(a[3])) || + !streq_ptr(c->x11_options, strnulldash(a[4]))) { + +- if (free_and_copy(&c->x11_layout, strnulldash(a[1])) < 0 || +- free_and_copy(&c->x11_model, strnulldash(a[2])) < 0 || +- free_and_copy(&c->x11_variant, strnulldash(a[3])) < 0 || +- free_and_copy(&c->x11_options, strnulldash(a[4])) < 0) ++ if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 || ++ free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 || ++ free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 || ++ free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0) + return -ENOMEM; + + modified = true; +@@ -713,10 +700,9 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { + if (matching > best_matching) { + best_matching = matching; + +- free(*new_keymap); +- *new_keymap = strdup(a[0]); +- if (!*new_keymap) +- return -ENOMEM; ++ r = free_and_strdup(new_keymap, a[0]); ++ if (r < 0) ++ return r; + } + } + +@@ -868,14 +854,9 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + + k = strlen(names[p]); + if (startswith(*i, names[p]) && (*i)[k] == '=') { +- char *t; +- +- t = strdup(*i + k + 1); +- if (!t) +- return -ENOMEM; +- +- free(c->locale[p]); +- c->locale[p] = t; ++ r = free_and_strdup(&c->locale[p], *i + k + 1); ++ if (r < 0) ++ return r; + break; + } + } +@@ -937,8 +918,8 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + +- if (free_and_copy(&c->vc_keymap, keymap) < 0 || +- free_and_copy(&c->vc_keymap_toggle, keymap_toggle) < 0) ++ if (free_and_strdup(&c->vc_keymap, keymap) < 0 || ++ free_and_strdup(&c->vc_keymap_toggle, keymap_toggle) < 0) + return -ENOMEM; + + r = vconsole_write_data(c); +@@ -1007,10 +988,10 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + +- if (free_and_copy(&c->x11_layout, layout) < 0 || +- free_and_copy(&c->x11_model, model) < 0 || +- free_and_copy(&c->x11_variant, variant) < 0 || +- free_and_copy(&c->x11_options, options) < 0) ++ if (free_and_strdup(&c->x11_layout, layout) < 0 || ++ free_and_strdup(&c->x11_model, model) < 0 || ++ free_and_strdup(&c->x11_variant, variant) < 0 || ++ free_and_strdup(&c->x11_options, options) < 0) + return -ENOMEM; + + r = write_data_x11(c); +diff --git a/src/shared/util.c b/src/shared/util.c +index cf9d487b82..502b3675b1 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -4981,24 +4981,6 @@ bool kexec_loaded(void) { + return loaded; + } + +-int strdup_or_null(const char *a, char **b) { +- char *c; +- +- assert(b); +- +- if (!a) { +- *b = NULL; +- return 0; +- } +- +- c = strdup(a); +- if (!c) +- return -ENOMEM; +- +- *b = c; +- return 0; +-} +- + int prot_from_flags(int flags) { + + switch (flags & O_ACCMODE) { +diff --git a/src/shared/util.h b/src/shared/util.h +index 3401280d09..08d556fc92 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -583,8 +583,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret); + + int file_is_priv_sticky(const char *p); + +-int strdup_or_null(const char *a, char **b); +- + #define NULSTR_FOREACH(i, l) \ + for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) + diff --git a/0160-localed-log-locale-keymap-changes-in-detail.patch b/0160-localed-log-locale-keymap-changes-in-detail.patch new file mode 100644 index 0000000..8f14814 --- /dev/null +++ b/0160-localed-log-locale-keymap-changes-in-detail.patch @@ -0,0 +1,206 @@ +From 502f961425f9dea1a85239766a3189695194da63 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 22:55:16 -0400 +Subject: [PATCH] localed: log locale/keymap changes in detail + +Converting X11 to legacy keymaps and back is a fucking mess. Let's +make it at least possible to request detailed logs of what is being +changed and why (LOG_DEBUG level). + +At LOG_INFO level, we would log the requested change of X11 or console +keymap, but not the resulting change after conversion to console or X11. +Make sure that every change of configuration on disk has a matching +line in the logs. +--- + src/locale/localed.c | 76 +++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 60 insertions(+), 16 deletions(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index ac8477ad39..777da623f6 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -265,10 +265,12 @@ static int context_read_data(Context *c) { + return r < 0 ? r : q < 0 ? q : p; + } + +-static int locale_write_data(Context *c) { ++static int locale_write_data(Context *c, char ***settings) { + int r, p; + _cleanup_strv_free_ char **l = NULL; + ++ /* Set values will be returned as strv in *settings on success. */ ++ + r = load_env_file(NULL, "/etc/locale.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; +@@ -302,7 +304,13 @@ static int locale_write_data(Context *c) { + return 0; + } + +- return write_env_file_label("/etc/locale.conf", l); ++ r = write_env_file_label("/etc/locale.conf", l); ++ if (r < 0) ++ return r; ++ ++ *settings = l; ++ l = NULL; ++ return 0; + } + + static int locale_update_system_manager(Context *c, sd_bus *bus) { +@@ -595,11 +603,18 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { + if (r < 0) + log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); + ++ log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", ++ strempty(c->x11_layout), ++ strempty(c->x11_model), ++ strempty(c->x11_variant), ++ strempty(c->x11_options)); ++ + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); +- } ++ } else ++ log_debug("X11 keyboard layout was not modified."); + + return 0; + } +@@ -617,13 +632,18 @@ static int find_converted_keymap(Context *c, char **new_keymap) { + + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + _cleanup_free_ char *p = NULL, *pz = NULL; ++ bool uncompressed; + + p = strjoin(dir, "xkb/", n, ".map", NULL); + pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); + if (!p || !pz) + return -ENOMEM; + +- if (access(p, F_OK) == 0 || access(pz, F_OK) == 0) { ++ uncompressed = access(p, F_OK) == 0; ++ if (uncompressed || access(pz, F_OK) == 0) { ++ log_debug("Found converted keymap %s at %s", ++ n, uncompressed ? p : pz); ++ + *new_keymap = n; + n = NULL; + return 1; +@@ -697,12 +717,17 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { + } + + /* The best matching entry so far, then let's save that */ +- if (matching > best_matching) { +- best_matching = matching; ++ if (matching >= MAX(best_matching, 1u)) { ++ log_debug("Found legacy keymap %s with score %u", ++ a[0], matching); + +- r = free_and_strdup(new_keymap, a[0]); +- if (r < 0) +- return r; ++ if (matching > best_matching) { ++ best_matching = matching; ++ ++ r = free_and_strdup(new_keymap, a[0]); ++ if (r < 0) ++ return r; ++ } + } + } + +@@ -747,13 +772,17 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { + if (r < 0) + log_error("Failed to set virtual console keymap: %s", strerror(-r)); + ++ log_info("Changed virtual console keymap to '%s' toggle '%s'", ++ strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); ++ + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "VConsoleKeymap", "VConsoleKeymapToggle", NULL); + + return vconsole_reload(bus); +- } ++ } else ++ log_debug("Virtual console keymap was not modified."); + + return 0; + } +@@ -808,7 +837,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + if (r < 0) + return r; + +- /* Check whether a variable changed and if so valid */ ++ /* Check whether a variable changed and if it is valid */ + STRV_FOREACH(i, l) { + bool valid = false; + +@@ -842,6 +871,8 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + } + + if (modified) { ++ _cleanup_strv_free_ char **settings = NULL; ++ + r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-locale", interactive, &c->polkit_registry, error); + if (r < 0) + return r; +@@ -870,7 +901,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + + locale_simplify(c); + +- r = locale_write_data(c); ++ r = locale_write_data(c, &settings); + if (r < 0) { + log_error("Failed to set locale: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set locale: %s", strerror(-r)); +@@ -878,13 +909,21 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_ + + locale_update_system_manager(c, bus); + +- log_info("Changed locale information."); ++ if (settings) { ++ _cleanup_free_ char *line; ++ ++ line = strv_join(settings, ", "); ++ log_info("Changed locale to %s.", strnull(line)); ++ } else ++ log_info("Changed locale to unset."); + + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "Locale", NULL); +- } ++ } else ++ log_debug("Locale settings were not modified."); ++ + + return sd_bus_reply_method_return(m, NULL); + } +@@ -928,7 +967,8 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata + return sd_bus_error_set_errnof(error, r, "Failed to set virtual console keymap: %s", strerror(-r)); + } + +- log_info("Changed virtual console keymap to '%s'", strempty(c->vc_keymap)); ++ log_info("Changed virtual console keymap to '%s' toggle '%s'", ++ strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); + + r = vconsole_reload(bus); + if (r < 0) +@@ -1000,7 +1040,11 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat + return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %s", strerror(-r)); + } + +- log_info("Changed X11 keyboard layout to '%s'", strempty(c->x11_layout)); ++ log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", ++ strempty(c->x11_layout), ++ strempty(c->x11_model), ++ strempty(c->x11_variant), ++ strempty(c->x11_options)); + + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", diff --git a/0161-localed-introduce-helper-function-to-simplify-matchi.patch b/0161-localed-introduce-helper-function-to-simplify-matchi.patch new file mode 100644 index 0000000..6b76852 --- /dev/null +++ b/0161-localed-introduce-helper-function-to-simplify-matchi.patch @@ -0,0 +1,57 @@ +From 81fd105a5f9762fa2f2e42bc949876e32b3a126f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 22:55:52 -0400 +Subject: [PATCH] localed: introduce helper function to simplify matching + +--- + src/locale/localed.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index 777da623f6..f3e1589a45 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -101,6 +101,12 @@ static void free_and_replace(char **s, char *v) { + *s = v; + } + ++static bool startswith_comma(const char *s, const char *prefix) { ++ const char *t; ++ ++ return s && (t = startswith(s, prefix)) && (*t == ','); ++} ++ + static void context_free_x11(Context *c) { + free_and_replace(&c->x11_layout, NULL); + free_and_replace(&c->x11_model, NULL); +@@ -679,26 +685,18 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { + /* If we got an exact match, this is best */ + matching = 10; + else { +- size_t x; +- +- x = strcspn(c->x11_layout, ","); +- + /* We have multiple X layouts, look for an + * entry that matches our key with everything + * but the first layout stripped off. */ +- if (x > 0 && +- strlen(a[1]) == x && +- strneq(c->x11_layout, a[1], x)) ++ if (startswith_comma(c->x11_layout, a[1])) + matching = 5; + else { +- size_t w; ++ char *x; + + /* If that didn't work, strip off the + * other layouts from the entry, too */ +- w = strcspn(a[1], ","); +- +- if (x > 0 && x == w && +- memcmp(c->x11_layout, a[1], x) == 0) ++ x = strndupa(a[1], strcspn(a[1], ",")); ++ if (startswith_comma(c->x11_layout, x)) + matching = 1; + } + } diff --git a/0162-localed-check-for-partially-matching-converted-keyma.patch b/0162-localed-check-for-partially-matching-converted-keyma.patch new file mode 100644 index 0000000..55f4198 --- /dev/null +++ b/0162-localed-check-for-partially-matching-converted-keyma.patch @@ -0,0 +1,104 @@ +From 78bd12a05a9252cf573da28394b23e2b891cbba8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 22:55:54 -0400 +Subject: [PATCH] localed: check for partially matching converted keymaps + +If a user specifies multiple X11 keymaps, with a (at least the first +one) nonempty variant, and we don't match the whole combo, use +a converted keymap which includes the variant in preference to +the default, variantless, keymap. + +E.g.: We would convert X11 config "layout=fr variant=mac" to "fr-mac", +but "layout=fr,us variant=mac," to "fr", because we don't have a +converted keymap which would match "fr,us", and we don't have a legacy +mapping for "fr,us". This is unexpected, and if we cannot match both, +it is still better to match the primary mapping and use "fr-mac". +--- + src/locale/localed.c | 34 ++++++++++++++++++++++++++-------- + 1 file changed, 26 insertions(+), 8 deletions(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index f3e1589a45..2252080f2e 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -606,8 +606,10 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { + int r; + + r = write_data_x11(c); +- if (r < 0) ++ if (r < 0) { + log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); ++ return r; ++ } + + log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", + strempty(c->x11_layout), +@@ -625,14 +627,14 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { + return 0; + } + +-static int find_converted_keymap(Context *c, char **new_keymap) { ++static int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { + const char *dir; + _cleanup_free_ char *n; + +- if (c->x11_variant) +- n = strjoin(c->x11_layout, "-", c->x11_variant, NULL); ++ if (x11_variant) ++ n = strjoin(x11_layout, "-", x11_variant, NULL); + else +- n = strdup(c->x11_layout); ++ n = strdup(x11_layout); + if (!n) + return -ENOMEM; + +@@ -663,7 +665,7 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { + _cleanup_fclose_ FILE *f; + unsigned n = 0; + unsigned best_matching = 0; +- ++ int r; + + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + if (!f) +@@ -672,7 +674,6 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { + for (;;) { + _cleanup_strv_free_ char **a = NULL; + unsigned matching = 0; +- int r; + + r = read_next_mapping(f, &n, &a); + if (r < 0) +@@ -729,6 +730,23 @@ static int find_legacy_keymap(Context *c, char **new_keymap) { + } + } + ++ if (best_matching < 10 && c->x11_layout) { ++ /* The best match is only the first part of the X11 ++ * keymap. Check if we have a converted map which ++ * matches just the first layout. ++ */ ++ char *l, *v = NULL, *converted; ++ ++ l = strndupa(c->x11_layout, strcspn(c->x11_layout, ",")); ++ if (c->x11_variant) ++ v = strndupa(c->x11_variant, strcspn(c->x11_variant, ",")); ++ r = find_converted_keymap(l, v, &converted); ++ if (r < 0) ++ return r; ++ if (r > 0) ++ free_and_replace(new_keymap, converted); ++ } ++ + return 0; + } + +@@ -748,7 +766,7 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { + } else { + char *new_keymap = NULL; + +- r = find_converted_keymap(c, &new_keymap); ++ r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap); + if (r < 0) + return r; + else if (r == 0) { diff --git a/0163-systemd-fix-argument-ordering-in-UnsetAndSetEnvironm.patch b/0163-systemd-fix-argument-ordering-in-UnsetAndSetEnvironm.patch new file mode 100644 index 0000000..806ce99 --- /dev/null +++ b/0163-systemd-fix-argument-ordering-in-UnsetAndSetEnvironm.patch @@ -0,0 +1,37 @@ +From eb6c7d20756b60a7c79a373fd27a682a31b5647a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 22:22:38 -0400 +Subject: [PATCH] systemd: fix argument ordering in UnsetAndSetEnvironment + +Fixup for v208-615-g718db96199. +--- + src/core/dbus-manager.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index e792fe7e28..2fe9d193f6 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1357,18 +1357,18 @@ static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message + if (r < 0) + return r; + +- r = sd_bus_message_read_strv(message, &plus); ++ r = sd_bus_message_read_strv(message, &minus); + if (r < 0) + return r; + +- r = sd_bus_message_read_strv(message, &minus); ++ r = sd_bus_message_read_strv(message, &plus); + if (r < 0) + return r; + +- if (!strv_env_is_valid(plus)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); + if (!strv_env_name_or_assignment_is_valid(minus)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments"); ++ if (!strv_env_is_valid(plus)) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); + + r = manager_environment_add(m, minus, plus); + if (r < 0) diff --git a/0164-man-fix-typo.patch b/0164-man-fix-typo.patch new file mode 100644 index 0000000..2d6a39f --- /dev/null +++ b/0164-man-fix-typo.patch @@ -0,0 +1,22 @@ +From 7a465961c19036eba2c08223e769ad9e85a766a8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 22:07:29 -0400 +Subject: [PATCH] man: fix typo + +--- + man/systemd-bus-proxyd.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml +index 91a6fe3685..f9400f034d 100644 +--- a/man/systemd-bus-proxyd.xml ++++ b/man/systemd-bus-proxyd.xml +@@ -80,7 +80,7 @@ along with systemd; If not, see . + + + Connect to the bus specified by +- ADDRESS. Multiple colon-seperated ++ ADDRESS. Multiple colon-separated + addresses can be specified, in which case + systemd-bus-proxyd will attempt to + connect to them in turn. diff --git a/0165-Update-TODO.patch b/0165-Update-TODO.patch new file mode 100644 index 0000000..7bf6704 --- /dev/null +++ b/0165-Update-TODO.patch @@ -0,0 +1,25 @@ +From 83a1ff25e5228b0a5b2cc942fd4f964d10bb73b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 3 Sep 2014 22:12:51 -0400 +Subject: [PATCH] Update TODO + +--- + TODO | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/TODO b/TODO +index 208a4ce890..f0f2bcb12d 100644 +--- a/TODO ++++ b/TODO +@@ -19,6 +19,11 @@ External: + + * Fedora: remove /etc/resolv.conf tmpfiles hack + ++* wiki: update journal format documentation for lz4 additions ++ ++* When lz4 gets an API for lz4 command output, make use of it to ++ compress coredumps in a way compatible with /usr/bin/lz4. ++ + Features: + + * introduce machines.target to order after all nspawn instances diff --git a/0166-networkd-move-carrier-gained-lost-handling-from-link.patch b/0166-networkd-move-carrier-gained-lost-handling-from-link.patch new file mode 100644 index 0000000..c42aa1d --- /dev/null +++ b/0166-networkd-move-carrier-gained-lost-handling-from-link.patch @@ -0,0 +1,162 @@ +From a61bb41c29c370a7e64285525ec35baac8944149 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 4 Sep 2014 14:05:54 +0200 +Subject: [PATCH] networkd: move carrier gained/lost handling from + link_update_flags() to link_update() + +This allows us also to simplify link_has_carrier() a bit. +--- + src/network/networkd-link.c | 74 ++++++++++++++++++++++----------------------- + src/network/networkd-link.h | 2 +- + 2 files changed, 38 insertions(+), 38 deletions(-) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index dff3270f2a..57e719478a 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -863,15 +863,15 @@ static int link_acquire_conf(Link *link) { + return 0; + } + +-bool link_has_carrier(unsigned flags, uint8_t operstate) { ++bool link_has_carrier(Link *link) { + /* see Documentation/networking/operstates.txt in the kernel sources */ + +- if (operstate == IF_OPER_UP) ++ if (link->kernel_operstate == IF_OPER_UP) + return true; + +- if (operstate == IF_OPER_UNKNOWN) ++ if (link->kernel_operstate == IF_OPER_UNKNOWN) + /* operstate may not be implemented, so fall back to flags */ +- if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT)) ++ if ((link->flags & IFF_LOWER_UP) && !(link->flags & IFF_DORMANT)) + return true; + + return false; +@@ -885,7 +885,6 @@ bool link_has_carrier(unsigned flags, uint8_t operstate) { + static int link_update_flags(Link *link, sd_rtnl_message *m) { + unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags; + uint8_t operstate; +- bool carrier_gained = false, carrier_lost = false; + int r; + + assert(link); +@@ -949,40 +948,11 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) { + unknown_flags_removed); + } + +- carrier_gained = !link_has_carrier(link->flags, link->kernel_operstate) && +- link_has_carrier(flags, operstate); +- carrier_lost = link_has_carrier(link->flags, link->kernel_operstate) && +- !link_has_carrier(flags, operstate); +- + link->flags = flags; + link->kernel_operstate = operstate; + + link_save(link); + +- if (link->state == LINK_STATE_FAILED || +- link->state == LINK_STATE_UNMANAGED) +- return 0; +- +- if (carrier_gained) { +- log_info_link(link, "gained carrier"); +- +- if (link->network) { +- r = link_acquire_conf(link); +- if (r < 0) { +- link_enter_failed(link); +- return r; +- } +- } +- } else if (carrier_lost) { +- log_info_link(link, "lost carrier"); +- +- r = link_stop_clients(link); +- if (r < 0) { +- link_enter_failed(link); +- return r; +- } +- } +- + return 0; + } + +@@ -1244,7 +1214,7 @@ static int link_configure(Link *link) { + return r; + } + +- if (link_has_carrier(link->flags, link->kernel_operstate)) { ++ if (link_has_carrier(link)) { + r = link_acquire_conf(link); + if (r < 0) + return r; +@@ -1554,6 +1524,7 @@ int link_update(Link *link, sd_rtnl_message *m) { + struct ether_addr mac; + const char *ifname; + uint32_t mtu; ++ bool had_carrier, carrier_gained, carrier_lost; + int r; + + assert(link); +@@ -1650,7 +1621,36 @@ int link_update(Link *link, sd_rtnl_message *m) { + } + } + +- return link_update_flags(link, m); ++ had_carrier = link_has_carrier(link); ++ ++ r = link_update_flags(link, m); ++ if (r < 0) ++ return r; ++ ++ carrier_gained = !had_carrier && link_has_carrier(link); ++ carrier_lost = had_carrier && !link_has_carrier(link); ++ ++ if (carrier_gained) { ++ log_info_link(link, "gained carrier"); ++ ++ if (link->network) { ++ r = link_acquire_conf(link); ++ if (r < 0) { ++ link_enter_failed(link); ++ return r; ++ } ++ } ++ } else if (carrier_lost) { ++ log_info_link(link, "lost carrier"); ++ ++ r = link_stop_clients(link); ++ if (r < 0) { ++ link_enter_failed(link); ++ return r; ++ } ++ } ++ ++ return 0; + } + + static void link_update_operstate(Link *link) { +@@ -1659,7 +1659,7 @@ static void link_update_operstate(Link *link) { + + if (link->kernel_operstate == IF_OPER_DORMANT) + link->operstate = LINK_OPERSTATE_DORMANT; +- else if (link_has_carrier(link->flags, link->kernel_operstate)) { ++ else if (link_has_carrier(link)) { + Address *address; + uint8_t scope = RT_SCOPE_NOWHERE; + +diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h +index 0f73ec7f9b..7acf404f87 100644 +--- a/src/network/networkd-link.h ++++ b/src/network/networkd-link.h +@@ -113,7 +113,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use + + int link_save(Link *link); + +-bool link_has_carrier(unsigned flags, uint8_t operstate); ++bool link_has_carrier(Link *link); + + int link_set_mtu(Link *link, uint32_t mtu); + int link_set_hostname(Link *link, const char *hostname); diff --git a/0167-networkd-link-save-link-flags-when-the-link-is-added.patch b/0167-networkd-link-save-link-flags-when-the-link-is-added.patch new file mode 100644 index 0000000..f0118fc --- /dev/null +++ b/0167-networkd-link-save-link-flags-when-the-link-is-added.patch @@ -0,0 +1,197 @@ +From 51d18171529dcdad1366e422e42d538434af0ff6 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 4 Sep 2014 14:10:43 +0200 +Subject: [PATCH] networkd: link - save link flags when the link is added + +Don't wait for the link to be fully synchronised. +--- + src/network/networkd-link.c | 162 +++++++++++++++++++++++--------------------- + 1 file changed, 83 insertions(+), 79 deletions(-) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 57e719478a..1b7b1898c4 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -35,6 +35,85 @@ + + #include "dhcp-lease-internal.h" + ++#define FLAG_STRING(string, flag, old, new) \ ++ (((old ^ new) & flag) \ ++ ? ((old & flag) ? (" -" string) : (" +" string)) \ ++ : "") ++ ++static int link_update_flags(Link *link, sd_rtnl_message *m) { ++ unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags; ++ uint8_t operstate; ++ int r; ++ ++ assert(link); ++ ++ r = sd_rtnl_message_link_get_flags(m, &flags); ++ if (r < 0) { ++ log_warning_link(link, "Could not get link flags"); ++ return r; ++ } ++ ++ r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate); ++ if (r < 0) ++ /* if we got a message without operstate, take it to mean ++ the state was unchanged */ ++ operstate = link->kernel_operstate; ++ ++ if ((link->flags == flags) && (link->kernel_operstate == operstate)) ++ return 0; ++ ++ if (link->flags != flags) { ++ log_debug_link(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", ++ FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags), ++ FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags), ++ FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags), ++ FLAG_STRING("UP", IFF_UP, link->flags, flags), ++ FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags), ++ FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags), ++ FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags), ++ FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags), ++ FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags), ++ FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags), ++ FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags), ++ FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags), ++ FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags), ++ FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags), ++ FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags), ++ FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags), ++ FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags), ++ FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags), ++ FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags)); ++ ++ unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP | ++ IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING | ++ IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT | ++ IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL | ++ IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP | ++ IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO); ++ unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags); ++ unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags); ++ ++ /* link flags are currently at most 18 bits, let's align to ++ * printing 20 */ ++ if (unknown_flags_added) ++ log_debug_link(link, ++ "unknown link flags gained: %#.5x (ignoring)", ++ unknown_flags_added); ++ ++ if (unknown_flags_removed) ++ log_debug_link(link, ++ "unknown link flags lost: %#.5x (ignoring)", ++ unknown_flags_removed); ++ } ++ ++ link->flags = flags; ++ link->kernel_operstate = operstate; ++ ++ link_save(link); ++ ++ return 0; ++} ++ + static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) { + _cleanup_link_unref_ Link *link = NULL; + uint16_t type; +@@ -95,6 +174,10 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) { + if (r < 0) + return r; + ++ r = link_update_flags(link, message); ++ if (r < 0) ++ return r; ++ + *ret = link; + link = NULL; + +@@ -877,85 +960,6 @@ bool link_has_carrier(Link *link) { + return false; + } + +-#define FLAG_STRING(string, flag, old, new) \ +- (((old ^ new) & flag) \ +- ? ((old & flag) ? (" -" string) : (" +" string)) \ +- : "") +- +-static int link_update_flags(Link *link, sd_rtnl_message *m) { +- unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags; +- uint8_t operstate; +- int r; +- +- assert(link); +- +- r = sd_rtnl_message_link_get_flags(m, &flags); +- if (r < 0) { +- log_warning_link(link, "Could not get link flags"); +- return r; +- } +- +- r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate); +- if (r < 0) +- /* if we got a message without operstate, take it to mean +- the state was unchanged */ +- operstate = link->kernel_operstate; +- +- if ((link->flags == flags) && (link->kernel_operstate == operstate)) +- return 0; +- +- if (link->flags != flags) { +- log_debug_link(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", +- FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags), +- FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags), +- FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags), +- FLAG_STRING("UP", IFF_UP, link->flags, flags), +- FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags), +- FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags), +- FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags), +- FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags), +- FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags), +- FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags), +- FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags), +- FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags), +- FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags), +- FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags), +- FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags), +- FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags), +- FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags), +- FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags), +- FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags)); +- +- unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP | +- IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING | +- IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT | +- IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL | +- IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP | +- IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO); +- unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags); +- unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags); +- +- /* link flags are currently at most 18 bits, let's align to +- * printing 20 */ +- if (unknown_flags_added) +- log_debug_link(link, +- "unknown link flags gained: %#.5x (ignoring)", +- unknown_flags_added); +- +- if (unknown_flags_removed) +- log_debug_link(link, +- "unknown link flags lost: %#.5x (ignoring)", +- unknown_flags_removed); +- } +- +- link->flags = flags; +- link->kernel_operstate = operstate; +- +- link_save(link); +- +- return 0; +-} +- + static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + _cleanup_link_unref_ Link *link = userdata; + int r; diff --git a/0168-networkd-link-do-not-manage-loopback-links.patch b/0168-networkd-link-do-not-manage-loopback-links.patch new file mode 100644 index 0000000..8995192 --- /dev/null +++ b/0168-networkd-link-do-not-manage-loopback-links.patch @@ -0,0 +1,42 @@ +From bd2efe9219a3791b47c2c5c2ef0fe2579ffd547d Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 4 Sep 2014 13:40:24 +0200 +Subject: [PATCH] networkd: link - do not manage loopback links + +Fixes https://bugs.freedesktop.org/show_bug.cgi?id=83134. +--- + TODO | 3 --- + src/network/networkd-link.c | 6 ++++++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/TODO b/TODO +index f0f2bcb12d..380fd494f2 100644 +--- a/TODO ++++ b/TODO +@@ -78,9 +78,6 @@ Features: + - ipv4ll with multiple interfaces doesn't work when both dhcp and + ipv4ll is used. for some reasons the kernel will currently pick an + ipv4ll source address to reach non-ipv4ll gateways. +- - dhcp and ipv4ll should probably be skipped for "lo" devices, even +- if the user has a catchall .network file installed, that might +- theoretically match it. + - the DHCP lease data (such as NTP/DNS) is still made available when + a carrier is lost on a link. It should be removed instantly. + - .network setting that allows overriding of the hostname to send to the dhcp server +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 1b7b1898c4..f726e2b570 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -1250,6 +1250,12 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, + } else if (r < 0) + return r; + ++ if (link->flags & IFF_LOOPBACK) { ++ log_debug_link(link, "matching network ignored for loopback link"); ++ link_enter_unmanaged(link); ++ return 1; ++ } ++ + r = network_apply(link->manager, network, link); + if (r < 0) + return r; diff --git a/0169-networkd-link-clarify-log-message-when-receiving-add.patch b/0169-networkd-link-clarify-log-message-when-receiving-add.patch new file mode 100644 index 0000000..7e22760 --- /dev/null +++ b/0169-networkd-link-clarify-log-message-when-receiving-add.patch @@ -0,0 +1,23 @@ +From a821cbb00c3f6e33d99e9e38ec1538a16dd90ce3 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 4 Sep 2014 14:16:56 +0200 +Subject: [PATCH] networkd: link - clarify log message when receiving address + for unknown link + +--- + src/network/networkd-link.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index f726e2b570..bcd2e6da51 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -1336,7 +1336,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, + } else { + r = link_get(m, ifindex, &link); + if (r < 0 || !link) { +- log_warning("rtnl: received address for a nonexistent link, ignoring"); ++ log_warning("rtnl: received address for a nonexistent link (%d), ignoring", ifindex); + return 0; + } + } diff --git a/0170-build-don-t-install-busname-units-and-target-if-kdbu.patch b/0170-build-don-t-install-busname-units-and-target-if-kdbu.patch new file mode 100644 index 0000000..d72780b --- /dev/null +++ b/0170-build-don-t-install-busname-units-and-target-if-kdbu.patch @@ -0,0 +1,164 @@ +From 36e46fe9b625b7a63a6b38f43dc55298c8a0ac89 Mon Sep 17 00:00:00 2001 +From: Michael Biebl +Date: Wed, 3 Sep 2014 23:34:29 +0200 +Subject: [PATCH] build: don't install busname units and target if kdbus + support is disabled + +--- + Makefile.am | 45 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 33 insertions(+), 12 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 58e5ce6c54..e534a23886 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -140,6 +140,7 @@ nodist_pkgsysconf_DATA = + dist_pkgdata_DATA = + dist_dbuspolicy_DATA = + dist_dbussystemservice_DATA = ++dist_systemunit_DATA_busnames = + check_PROGRAMS = + check_DATA = + tests= +@@ -263,10 +264,12 @@ install-target-wants-hook: + what="$(MULTI_USER_TARGET_WANTS)" && wants=multi-user.target && dir=$(systemunitdir) && $(add-wants) + what="$(SYSINIT_TARGET_WANTS)" && wants=sysinit.target && dir=$(systemunitdir) && $(add-wants) + what="$(SOCKETS_TARGET_WANTS)" && wants=sockets.target && dir=$(systemunitdir) && $(add-wants) +- what="$(BUSNAMES_TARGET_WANTS)" && wants=busnames.target && dir=$(systemunitdir) && $(add-wants) + what="$(TIMERS_TARGET_WANTS)" && wants=timers.target && dir=$(systemunitdir) && $(add-wants) + what="$(SLICES_TARGET_WANTS)" && wants=slices.target && dir=$(systemunitdir) && $(add-wants) + what="$(USER_SOCKETS_TARGET_WANTS)" && wants=sockets.target && dir=$(userunitdir) && $(add-wants) ++ ++install-busnames-target-wants-hook: ++ what="$(BUSNAMES_TARGET_WANTS)" && wants=busnames.target && dir=$(systemunitdir) && $(add-wants) + what="$(USER_BUSNAMES_TARGET_WANTS)" && wants=busnames.target && dir=$(userunitdir) && $(add-wants) + + define add-wants +@@ -316,6 +319,11 @@ INSTALL_EXEC_HOOKS += \ + install-aliases-hook \ + install-touch-usr-hook + ++if ENABLE_KDBUS ++INSTALL_EXEC_HOOKS += \ ++ install-busnames-target-wants-hook ++endif ++ + # ------------------------------------------------------------------------------ + AM_V_M4 = $(AM_V_M4_$(V)) + AM_V_M4_ = $(AM_V_M4_$(AM_DEFAULT_VERBOSITY)) +@@ -463,7 +471,6 @@ dist_systemunit_DATA = \ + units/sigpwr.target \ + units/sleep.target \ + units/sockets.target \ +- units/busnames.target \ + units/timers.target \ + units/paths.target \ + units/suspend.target \ +@@ -491,6 +498,14 @@ dist_systemunit_DATA = \ + units/system-update.target \ + units/initrd-switch-root.target + ++if ENABLE_KDBUS ++dist_systemunit_DATA += \ ++ $(dist_systemunit_DATA_busnames) ++endif ++ ++dist_systemunit_DATA_busnames += \ ++ units/busnames.target ++ + nodist_systemunit_DATA = \ + units/getty@.service \ + units/serial-getty@.service \ +@@ -4486,7 +4501,7 @@ rootlibexec_PROGRAMS += \ + nodist_systemunit_DATA += \ + units/systemd-hostnamed.service + +-dist_systemunit_DATA += \ ++dist_systemunit_DATA_busnames += \ + units/org.freedesktop.hostname1.busname + + dist_dbuspolicy_DATA += \ +@@ -4529,13 +4544,11 @@ EXTRA_DIST += \ + units/systemd-hostnamed.service.in + + # ------------------------------------------------------------------------------ +-if ENABLE_KDBUS +-dist_systemunit_DATA += \ ++dist_systemunit_DATA_busnames += \ + units/org.freedesktop.systemd1.busname + + BUSNAMES_TARGET_WANTS += \ + org.freedesktop.systemd1.busname +-endif + + # ------------------------------------------------------------------------------ + if ENABLE_LOCALED +@@ -4550,7 +4563,7 @@ systemd_localed_LDADD = \ + nodist_systemunit_DATA += \ + units/systemd-localed.service + +-dist_systemunit_DATA += \ ++dist_systemunit_DATA_busnames += \ + units/org.freedesktop.locale1.busname + + rootlibexec_PROGRAMS += \ +@@ -4625,7 +4638,7 @@ dist_dbuspolicy_DATA += \ + nodist_systemunit_DATA += \ + units/systemd-timedated.service + +-dist_systemunit_DATA += \ ++dist_systemunit_DATA_busnames += \ + units/org.freedesktop.timedate1.busname + + polkitpolicy_files += \ +@@ -4787,7 +4800,9 @@ nodist_systemunit_DATA += \ + units/systemd-machined.service + + dist_systemunit_DATA += \ +- units/machine.slice \ ++ units/machine.slice ++ ++dist_systemunit_DATA_busnames += \ + units/org.freedesktop.machine1.busname + + dist_dbussystemservice_DATA += \ +@@ -4897,7 +4912,7 @@ rootlibexec_PROGRAMS += \ + nodist_systemunit_DATA += \ + units/systemd-resolved.service + +-dist_systemunit_DATA += \ ++dist_systemunit_DATA_busnames += \ + units/org.freedesktop.resolve1.busname + + dist_dbuspolicy_DATA += \ +@@ -5289,7 +5304,9 @@ nodist_systemunit_DATA += \ + units/systemd-user-sessions.service + + dist_systemunit_DATA += \ +- units/user.slice \ ++ units/user.slice ++ ++dist_systemunit_DATA_busnames += \ + units/org.freedesktop.login1.busname + + dist_dbussystemservice_DATA += \ +@@ -5903,7 +5920,6 @@ SYSTEM_UNIT_ALIASES += \ + USER_UNIT_ALIASES += \ + $(systemunitdir)/shutdown.target shutdown.target \ + $(systemunitdir)/sockets.target sockets.target \ +- $(systemunitdir)/busnames.target busnames.target \ + $(systemunitdir)/timers.target timers.target \ + $(systemunitdir)/paths.target paths.target \ + $(systemunitdir)/bluetooth.target bluetooth.target \ +@@ -5911,6 +5927,11 @@ USER_UNIT_ALIASES += \ + $(systemunitdir)/sound.target sound.target \ + $(systemunitdir)/smartcard.target smartcard.target + ++if ENABLE_KDBUS ++USER_UNIT_ALIASES += \ ++ $(systemunitdir)/busnames.target busnames.target ++endif ++ + GENERAL_ALIASES += \ + $(systemunitdir)/remote-fs.target $(pkgsysconfdir)/system/multi-user.target.wants/remote-fs.target \ + $(systemunitdir)/getty@.service $(pkgsysconfdir)/system/getty.target.wants/getty@tty1.service \ diff --git a/0171-networkd-link-allow-loopback-links-to-be-manage-but-.patch b/0171-networkd-link-allow-loopback-links-to-be-manage-but-.patch new file mode 100644 index 0000000..468bab8 --- /dev/null +++ b/0171-networkd-link-allow-loopback-links-to-be-manage-but-.patch @@ -0,0 +1,163 @@ +From 78c958f82e929f015169ce1ed614d1e9c50928aa Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 4 Sep 2014 20:54:08 +0200 +Subject: [PATCH] networkd: link - allow loopback links to be manage, but + ignore DHCP/IPv4LL + +--- + src/network/networkd-link.c | 72 ++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 58 insertions(+), 14 deletions(-) + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index bcd2e6da51..a88cf48d9d 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -35,6 +35,46 @@ + + #include "dhcp-lease-internal.h" + ++static bool link_dhcp6_enabled(Link *link) { ++ if (link->flags & IFF_LOOPBACK) ++ return false; ++ ++ if (!link->network) ++ return false; ++ ++ return IN_SET(link->network->dhcp, DHCP_SUPPORT_V6, DHCP_SUPPORT_BOTH); ++} ++ ++static bool link_dhcp4_enabled(Link *link) { ++ if (link->flags & IFF_LOOPBACK) ++ return false; ++ ++ if (!link->network) ++ return false; ++ ++ return IN_SET(link->network->dhcp, DHCP_SUPPORT_V4, DHCP_SUPPORT_BOTH); ++} ++ ++static bool link_dhcp4_server_enabled(Link *link) { ++ if (link->flags & IFF_LOOPBACK) ++ return false; ++ ++ if (!link->network) ++ return false; ++ ++ return link->network->dhcp_server; ++} ++ ++static bool link_ipv4ll_enabled(Link *link) { ++ if (link->flags & IFF_LOOPBACK) ++ return false; ++ ++ if (!link->network) ++ return false; ++ ++ return link->network->ipv4ll; ++} ++ + #define FLAG_STRING(string, flag, old, new) \ + (((old ^ new) & flag) \ + ? ((old & flag) ? (" -" string) : (" +" string)) \ +@@ -387,7 +427,7 @@ static int link_enter_configured(Link *link) { + assert(link->network); + assert(link->state == LINK_STATE_SETTING_ROUTES); + +- if (link->network->dhcp_server && ++ if (link_dhcp4_server_enabled(link) && + !sd_dhcp_server_is_running(link->dhcp_server)) { + struct in_addr pool_start; + Address *address; +@@ -454,13 +494,12 @@ void link_client_handler(Link *link) { + if (!link->static_configured) + return; + +- if (link->network->ipv4ll) ++ if (link_ipv4ll_enabled(link)) + if (!link->ipv4ll_address || + !link->ipv4ll_route) + return; + +- if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) +- if (!link->dhcp4_configured) ++ if (link_dhcp4_enabled(link) && !link->dhcp4_configured) + return; + + if (link->state != LINK_STATE_CONFIGURED) +@@ -904,7 +943,7 @@ static int link_acquire_conf(Link *link) { + assert(link->manager); + assert(link->manager->event); + +- if (link->network->ipv4ll) { ++ if (link_ipv4ll_enabled(link)) { + assert(link->ipv4ll); + + log_debug_link(link, "acquiring IPv4 link-local address"); +@@ -917,7 +956,7 @@ static int link_acquire_conf(Link *link) { + } + } + +- if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) { ++ if (link_dhcp4_enabled(link)) { + assert(link->dhcp_client); + + log_debug_link(link, "acquiring DHCPv4 lease"); +@@ -930,7 +969,7 @@ static int link_acquire_conf(Link *link) { + } + } + +- if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) { ++ if (link_dhcp6_enabled(link)) { + assert(link->icmp6_router_discovery); + + log_debug_link(link, "discovering IPv6 routers"); +@@ -1170,19 +1209,19 @@ static int link_configure(Link *link) { + assert(link->network); + assert(link->state == LINK_STATE_PENDING); + +- if (link->network->ipv4ll) { ++ if (link_ipv4ll_enabled(link)) { + r = ipv4ll_configure(link); + if (r < 0) + return r; + } + +- if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) { ++ if (link_dhcp4_enabled(link)) { + r = dhcp4_configure(link); + if (r < 0) + return r; + } + +- if (link->network->dhcp_server) { ++ if (link_dhcp4_server_enabled(link)) { + r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex); + if (r < 0) + return r; +@@ -1192,7 +1231,7 @@ static int link_configure(Link *link) { + return r; + } + +- if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) { ++ if (link_dhcp6_enabled(link)) { + r = sd_icmp6_nd_new(&link->icmp6_router_discovery); + if (r < 0) + return r; +@@ -1251,9 +1290,14 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, + return r; + + if (link->flags & IFF_LOOPBACK) { +- log_debug_link(link, "matching network ignored for loopback link"); +- link_enter_unmanaged(link); +- return 1; ++ if (network->ipv4ll) ++ log_debug_link(link, "ignoring IPv4LL for loopback link"); ++ ++ if (network->dhcp != DHCP_SUPPORT_NONE) ++ log_debug_link(link, "ignoring DHCP clients for loopback link"); ++ ++ if (network->dhcp_server) ++ log_debug_link(link, "ignoring DHCP server for loopback link"); + } + + r = network_apply(link->manager, network, link); diff --git a/0172-hibernate-resume-let-s-move-all-hibernate-resume-too.patch b/0172-hibernate-resume-let-s-move-all-hibernate-resume-too.patch new file mode 100644 index 0000000..08dbc75 --- /dev/null +++ b/0172-hibernate-resume-let-s-move-all-hibernate-resume-too.patch @@ -0,0 +1,41 @@ +From 782c2652920821fe6b7d5710911630b55f5efcec Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 4 Sep 2014 21:40:00 +0200 +Subject: [PATCH] hibernate-resume: let's move all hibernate-resume tools into + the same directory + +They are closely related, so let's move them together, and clean up the +.c file naming while we are at it. +--- + Makefile.am | 2 +- + .../hibernate-resume-generator.c} | 0 + src/resume-generator/Makefile | 1 - + 3 files changed, 1 insertion(+), 2 deletions(-) + rename src/{resume-generator/resume-generator.c => hibernate-resume/hibernate-resume-generator.c} (100%) + delete mode 120000 src/resume-generator/Makefile + +diff --git a/Makefile.am b/Makefile.am +index e534a23886..9c946d7a92 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2168,7 +2168,7 @@ systemd_hibernate_resume_LDADD = \ + libsystemd-shared.la + + systemd_hibernate_resume_generator_SOURCES = \ +- src/resume-generator/resume-generator.c ++ src/hibernate-resume/hibernate-resume-generator.c + + systemd_hibernate_resume_generator_LDADD = \ + libsystemd-label.la \ +diff --git a/src/resume-generator/resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c +similarity index 100% +rename from src/resume-generator/resume-generator.c +rename to src/hibernate-resume/hibernate-resume-generator.c +diff --git a/src/resume-generator/Makefile b/src/resume-generator/Makefile +deleted file mode 120000 +index d0b0e8e008..0000000000 +--- a/src/resume-generator/Makefile ++++ /dev/null +@@ -1 +0,0 @@ +-../Makefile +\ No newline at end of file diff --git a/0173-man-make-it-more-clear-that-the-concepts-systemctl-1.patch b/0173-man-make-it-more-clear-that-the-concepts-systemctl-1.patch new file mode 100644 index 0000000..e5162b3 --- /dev/null +++ b/0173-man-make-it-more-clear-that-the-concepts-systemctl-1.patch @@ -0,0 +1,31 @@ +From a4390b6be8869172ccdd16fef208803fc6c7a114 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 4 Sep 2014 21:41:54 +0200 +Subject: [PATCH] man: make it more clear that the concepts systemctl(1) manage + are introduced in systemd(1) + +Based on a suggestion of Ken Coar. +--- + man/systemctl.xml | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 2818bcb999..b28a3b7e8a 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -60,10 +60,12 @@ along with systemd; If not, see . + + Description + +- systemctl may be used to +- introspect and control the state of the ++ systemctl may be used to introspect and ++ control the state of the systemd system and ++ service manager. Please refer to + systemd1 +- system and service manager. ++ for an introduction into the basic concepts and functionality this ++ tool manages. + + + diff --git a/0174-exec-factor-out-most-function-arguments-of-exec_spaw.patch b/0174-exec-factor-out-most-function-arguments-of-exec_spaw.patch new file mode 100644 index 0000000..a2652a0 --- /dev/null +++ b/0174-exec-factor-out-most-function-arguments-of-exec_spaw.patch @@ -0,0 +1,530 @@ +From 9fa95f8539a380e93f760956bc6982e57f5bf3af Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Sat, 23 Aug 2014 15:28:37 +0200 +Subject: [PATCH] exec: factor out most function arguments of exec_spawn() to + ExecParameters + +This way, the list of arguments to that function gets more comprehensive, +and we can get around passing lots of NULL and 0 arguments from socket.c, +swap.c and mount.c. + +It also allows for splitting up the code in exec_spawn(). + +While at it, make ExecContext const in execute.c. +--- + src/core/execute.c | 89 ++++++++++++++++++++++++------------------------------ + src/core/execute.h | 33 +++++++++++--------- + src/core/mount.c | 26 ++++++++-------- + src/core/service.c | 32 ++++++++++++-------- + src/core/socket.c | 27 +++++++++-------- + src/core/swap.c | 26 ++++++++-------- + 6 files changed, 117 insertions(+), 116 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 066efd6fdf..e683fa5e16 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1138,7 +1138,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { + } + + static int build_environment( +- ExecContext *c, ++ const ExecContext *c, + unsigned n_fds, + usec_t watchdog_usec, + const char *home, +@@ -1224,67 +1224,56 @@ static int build_environment( + } + + int exec_spawn(ExecCommand *command, +- char **argv, +- ExecContext *context, +- int fds[], unsigned n_fds, +- char **environment, +- bool apply_permissions, +- bool apply_chroot, +- bool apply_tty_stdin, +- bool confirm_spawn, +- CGroupControllerMask cgroup_supported, +- const char *cgroup_path, +- const char *runtime_prefix, +- const char *unit_id, +- usec_t watchdog_usec, +- int idle_pipe[4], ++ const ExecContext *context, ++ const ExecParameters *exec_params, + ExecRuntime *runtime, + pid_t *ret) { + + _cleanup_strv_free_ char **files_env = NULL; ++ int *fds = NULL; unsigned n_fds = 0; + int socket_fd; +- char *line; ++ char *line, **argv; + pid_t pid; + int r; + + assert(command); + assert(context); + assert(ret); +- assert(fds || n_fds <= 0); ++ assert(exec_params); ++ assert(exec_params->fds || exec_params->n_fds <= 0); + + if (context->std_input == EXEC_INPUT_SOCKET || + context->std_output == EXEC_OUTPUT_SOCKET || + context->std_error == EXEC_OUTPUT_SOCKET) { + +- if (n_fds != 1) ++ if (exec_params->n_fds != 1) + return -EINVAL; + +- socket_fd = fds[0]; +- +- fds = NULL; +- n_fds = 0; +- } else ++ socket_fd = exec_params->fds[0]; ++ } else { + socket_fd = -1; ++ fds = exec_params->fds; ++ n_fds = exec_params->n_fds; ++ } + + r = exec_context_load_environment(context, &files_env); + if (r < 0) { + log_struct_unit(LOG_ERR, +- unit_id, ++ exec_params->unit_id, + "MESSAGE=Failed to load environment files: %s", strerror(-r), + "ERRNO=%d", -r, + NULL); + return r; + } + +- if (!argv) +- argv = command->argv; ++ argv = exec_params->argv ?: command->argv; + + line = exec_command_line(argv); + if (!line) + return log_oom(); + + log_struct_unit(LOG_DEBUG, +- unit_id, ++ exec_params->unit_id, + "EXECUTABLE=%s", command->path, + "MESSAGE=About to execute: %s", line, + NULL); +@@ -1324,8 +1313,8 @@ int exec_spawn(ExecCommand *command, + goto fail_child; + } + +- if (idle_pipe) +- do_idle_pipe_dance(idle_pipe); ++ if (exec_params->idle_pipe) ++ do_idle_pipe_dance(exec_params->idle_pipe); + + /* Close sockets very early to make sure we don't + * block init reexecution because it cannot bind its +@@ -1360,7 +1349,7 @@ int exec_spawn(ExecCommand *command, + + exec_context_tty_reset(context); + +- if (confirm_spawn) { ++ if (exec_params->confirm_spawn) { + char response; + + err = ask_for_confirmation(&response, argv); +@@ -1385,26 +1374,26 @@ int exec_spawn(ExecCommand *command, + if (socket_fd >= 0) + fd_nonblock(socket_fd, false); + +- err = setup_input(context, socket_fd, apply_tty_stdin); ++ err = setup_input(context, socket_fd, exec_params->apply_tty_stdin); + if (err < 0) { + r = EXIT_STDIN; + goto fail_child; + } + +- err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin); ++ err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), exec_params->unit_id, exec_params->apply_tty_stdin); + if (err < 0) { + r = EXIT_STDOUT; + goto fail_child; + } + +- err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin); ++ err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), exec_params->unit_id, exec_params->apply_tty_stdin); + if (err < 0) { + r = EXIT_STDERR; + goto fail_child; + } + +- if (cgroup_path) { +- err = cg_attach_everywhere(cgroup_supported, cgroup_path, 0); ++ if (exec_params->cgroup_path) { ++ err = cg_attach_everywhere(exec_params->cgroup_supported, exec_params->cgroup_path, 0); + if (err < 0) { + r = EXIT_CGROUP; + goto fail_child; +@@ -1497,15 +1486,15 @@ int exec_spawn(ExecCommand *command, + } + + #ifdef HAVE_PAM +- if (cgroup_path && context->user && context->pam_name) { +- err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, 0644, uid, gid); ++ if (exec_params->cgroup_path && context->user && context->pam_name) { ++ err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, exec_params->cgroup_path, 0644, uid, gid); + if (err < 0) { + r = EXIT_CGROUP; + goto fail_child; + } + + +- err = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, 0755, uid, gid); ++ err = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, exec_params->cgroup_path, 0755, uid, gid); + if (err < 0) { + r = EXIT_CGROUP; + goto fail_child; +@@ -1513,13 +1502,13 @@ int exec_spawn(ExecCommand *command, + } + #endif + +- if (!strv_isempty(context->runtime_directory) && runtime_prefix) { ++ if (!strv_isempty(context->runtime_directory) && exec_params->runtime_prefix) { + char **rt; + + STRV_FOREACH(rt, context->runtime_directory) { + _cleanup_free_ char *p; + +- p = strjoin(runtime_prefix, "/", *rt, NULL); ++ p = strjoin(exec_params->runtime_prefix, "/", *rt, NULL); + if (!p) { + r = EXIT_RUNTIME_DIRECTORY; + err = -ENOMEM; +@@ -1534,7 +1523,7 @@ int exec_spawn(ExecCommand *command, + } + } + +- if (apply_permissions) { ++ if (exec_params->apply_permissions) { + err = enforce_groups(context, username, gid); + if (err < 0) { + r = EXIT_GROUP; +@@ -1545,7 +1534,7 @@ int exec_spawn(ExecCommand *command, + umask(context->umask); + + #ifdef HAVE_PAM +- if (apply_permissions && context->pam_name && username) { ++ if (exec_params->apply_permissions && context->pam_name && username) { + err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds); + if (err < 0) { + r = EXIT_PAM; +@@ -1601,7 +1590,7 @@ int exec_spawn(ExecCommand *command, + } + } + +- if (apply_chroot) { ++ if (exec_params->apply_chroot) { + if (context->root_directory) + if (chroot(context->root_directory) < 0) { + err = -errno; +@@ -1646,7 +1635,7 @@ int exec_spawn(ExecCommand *command, + goto fail_child; + } + +- if (apply_permissions) { ++ if (exec_params->apply_permissions) { + + for (i = 0; i < _RLIMIT_MAX; i++) { + if (!context->rlimit[i]) +@@ -1742,14 +1731,14 @@ int exec_spawn(ExecCommand *command, + #endif + } + +- err = build_environment(context, n_fds, watchdog_usec, home, username, shell, &our_env); ++ err = build_environment(context, n_fds, exec_params->watchdog_usec, home, username, shell, &our_env); + if (r < 0) { + r = EXIT_MEMORY; + goto fail_child; + } + + final_env = strv_env_merge(5, +- environment, ++ exec_params->environment, + our_env, + context->environment, + files_env, +@@ -1775,7 +1764,7 @@ int exec_spawn(ExecCommand *command, + if (line) { + log_open(); + log_struct_unit(LOG_DEBUG, +- unit_id, ++ exec_params->unit_id, + "EXECUTABLE=%s", command->path, + "MESSAGE=Executing: %s", line, + NULL); +@@ -1805,7 +1794,7 @@ int exec_spawn(ExecCommand *command, + } + + log_struct_unit(LOG_DEBUG, +- unit_id, ++ exec_params->unit_id, + "MESSAGE=Forked %s as "PID_FMT, + command->path, pid, + NULL); +@@ -1815,8 +1804,8 @@ int exec_spawn(ExecCommand *command, + * outside of the cgroup) and in the parent (so that we can be + * sure that when we kill the cgroup the process will be + * killed too). */ +- if (cgroup_path) +- cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, pid); ++ if (exec_params->cgroup_path) ++ cg_attach(SYSTEMD_CGROUP_CONTROLLER, exec_params->cgroup_path, pid); + + exec_status_start(&command->exec_status, pid); + +diff --git a/src/core/execute.h b/src/core/execute.h +index 9d05d3a9de..f31f0c9f27 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -25,6 +25,7 @@ typedef struct ExecStatus ExecStatus; + typedef struct ExecCommand ExecCommand; + typedef struct ExecContext ExecContext; + typedef struct ExecRuntime ExecRuntime; ++typedef struct ExecParameters ExecParameters; + + #include + #include +@@ -191,21 +192,25 @@ struct ExecContext { + + #include "cgroup.h" + ++struct ExecParameters { ++ char **argv; ++ int *fds; unsigned n_fds; ++ char **environment; ++ bool apply_permissions; ++ bool apply_chroot; ++ bool apply_tty_stdin; ++ bool confirm_spawn; ++ CGroupControllerMask cgroup_supported; ++ const char *cgroup_path; ++ const char *runtime_prefix; ++ const char *unit_id; ++ usec_t watchdog_usec; ++ int *idle_pipe; ++}; ++ + int exec_spawn(ExecCommand *command, +- char **argv, +- ExecContext *context, +- int fds[], unsigned n_fds, +- char **environment, +- bool apply_permissions, +- bool apply_chroot, +- bool apply_tty_stdin, +- bool confirm_spawn, +- CGroupControllerMask cgroup_mask, +- const char *cgroup_path, +- const char *runtime_prefix, +- const char *unit_id, +- usec_t watchdog_usec, +- int pipe_fd[2], ++ const ExecContext *context, ++ const ExecParameters *exec_params, + ExecRuntime *runtime, + pid_t *ret); + +diff --git a/src/core/mount.c b/src/core/mount.c +index ec90b0a670..e284357c6f 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -691,6 +691,11 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { + static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { + pid_t pid; + int r; ++ ExecParameters exec_params = { ++ .apply_permissions = true, ++ .apply_chroot = true, ++ .apply_tty_stdin = true, ++ }; + + assert(m); + assert(c); +@@ -706,21 +711,16 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { + if (r < 0) + goto fail; + ++ exec_params.environment = UNIT(m)->manager->environment; ++ exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn; ++ exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported; ++ exec_params.cgroup_path = UNIT(m)->cgroup_path; ++ exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager); ++ exec_params.unit_id = UNIT(m)->id; ++ + r = exec_spawn(c, +- NULL, + &m->exec_context, +- NULL, 0, +- UNIT(m)->manager->environment, +- true, +- true, +- true, +- UNIT(m)->manager->confirm_spawn, +- UNIT(m)->manager->cgroup_supported, +- UNIT(m)->cgroup_path, +- manager_get_runtime_prefix(UNIT(m)->manager), +- UNIT(m)->id, +- 0, +- NULL, ++ &exec_params, + m->exec_runtime, + &pid); + if (r < 0) +diff --git a/src/core/service.c b/src/core/service.c +index 223e4b3a41..f3775f24c4 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -892,6 +892,11 @@ static int service_spawn( + _cleanup_strv_free_ char + **argv = NULL, **final_env = NULL, **our_env = NULL; + const char *path; ++ ExecParameters exec_params = { ++ .apply_permissions = apply_permissions, ++ .apply_chroot = apply_chroot, ++ .apply_tty_stdin = apply_tty_stdin, ++ }; + + assert(s); + assert(c); +@@ -967,21 +972,22 @@ static int service_spawn( + } else + path = UNIT(s)->cgroup_path; + ++ exec_params.argv = argv; ++ exec_params.fds = fds; ++ exec_params.n_fds = n_fds; ++ exec_params.environment = final_env; ++ exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn; ++ exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; ++ exec_params.cgroup_path = path; ++ exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); ++ exec_params.unit_id = UNIT(s)->id; ++ exec_params.watchdog_usec = s->watchdog_usec; ++ if (s->type == SERVICE_IDLE) ++ exec_params.idle_pipe = UNIT(s)->manager->idle_pipe; ++ + r = exec_spawn(c, +- argv, + &s->exec_context, +- fds, n_fds, +- final_env, +- apply_permissions, +- apply_chroot, +- apply_tty_stdin, +- UNIT(s)->manager->confirm_spawn, +- UNIT(s)->manager->cgroup_supported, +- path, +- manager_get_runtime_prefix(UNIT(s)->manager), +- UNIT(s)->id, +- s->watchdog_usec, +- s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL, ++ &exec_params, + s->exec_runtime, + &pid); + if (r < 0) +diff --git a/src/core/socket.c b/src/core/socket.c +index 7ca8edbda8..68e21e60ac 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -1358,6 +1358,11 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { + _cleanup_free_ char **argv = NULL; + pid_t pid; + int r; ++ ExecParameters exec_params = { ++ .apply_permissions = true, ++ .apply_chroot = true, ++ .apply_tty_stdin = true, ++ }; + + assert(s); + assert(c); +@@ -1377,21 +1382,17 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { + if (r < 0) + goto fail; + ++ exec_params.argv = argv; ++ exec_params.environment = UNIT(s)->manager->environment; ++ exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn; ++ exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; ++ exec_params.cgroup_path = UNIT(s)->cgroup_path; ++ exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); ++ exec_params.unit_id = UNIT(s)->id; ++ + r = exec_spawn(c, +- argv, + &s->exec_context, +- NULL, 0, +- UNIT(s)->manager->environment, +- true, +- true, +- true, +- UNIT(s)->manager->confirm_spawn, +- UNIT(s)->manager->cgroup_supported, +- UNIT(s)->cgroup_path, +- manager_get_runtime_prefix(UNIT(s)->manager), +- UNIT(s)->id, +- 0, +- NULL, ++ &exec_params, + s->exec_runtime, + &pid); + if (r < 0) +diff --git a/src/core/swap.c b/src/core/swap.c +index 9f353af430..019d32ed0d 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -619,6 +619,11 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { + static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { + pid_t pid; + int r; ++ ExecParameters exec_params = { ++ .apply_permissions = true, ++ .apply_chroot = true, ++ .apply_tty_stdin = true, ++ }; + + assert(s); + assert(c); +@@ -634,21 +639,16 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { + if (r < 0) + goto fail; + ++ exec_params.environment = UNIT(s)->manager->environment; ++ exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn; ++ exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; ++ exec_params.cgroup_path = UNIT(s)->cgroup_path; ++ exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); ++ exec_params.unit_id = UNIT(s)->id; ++ + r = exec_spawn(c, +- NULL, + &s->exec_context, +- NULL, 0, +- UNIT(s)->manager->environment, +- true, +- true, +- true, +- UNIT(s)->manager->confirm_spawn, +- UNIT(s)->manager->cgroup_supported, +- UNIT(s)->cgroup_path, +- manager_get_runtime_prefix(UNIT(s)->manager), +- UNIT(s)->id, +- 0, +- NULL, ++ &exec_params, + s->exec_runtime, + &pid); + if (r < 0) diff --git a/0175-exec-move-code-executed-after-fork-into-exec_child.patch b/0175-exec-move-code-executed-after-fork-into-exec_child.patch new file mode 100644 index 0000000..db7444a --- /dev/null +++ b/0175-exec-move-code-executed-after-fork-into-exec_child.patch @@ -0,0 +1,1053 @@ +From d35fbf6bdf4377f3a15b084ff812b3ee272e5347 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Sat, 23 Aug 2014 16:02:21 +0200 +Subject: [PATCH] exec: move code executed after fork into exec_child() + +This factors out one conditional branch that has grown way too big, and +makes the code more readable by using return statements rather than jump +labels. +--- + src/core/execute.c | 911 +++++++++++++++++++++++++++-------------------------- + 1 file changed, 458 insertions(+), 453 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index e683fa5e16..0a5914759f 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1223,561 +1223,566 @@ static int build_environment( + return 0; + } + +-int exec_spawn(ExecCommand *command, +- const ExecContext *context, +- const ExecParameters *exec_params, +- ExecRuntime *runtime, +- pid_t *ret) { +- +- _cleanup_strv_free_ char **files_env = NULL; +- int *fds = NULL; unsigned n_fds = 0; +- int socket_fd; +- char *line, **argv; +- pid_t pid; +- int r; ++static int exec_child(ExecCommand *command, ++ const ExecContext *context, ++ const ExecParameters *params, ++ ExecRuntime *runtime, ++ char **argv, ++ int socket_fd, ++ int *fds, unsigned n_fds, ++ char **files_env, ++ int *error) { ++ ++ _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; ++ const char *username = NULL, *home = NULL, *shell = NULL; ++ unsigned n_dont_close = 0; ++ int dont_close[n_fds + 3]; ++ uid_t uid = (uid_t) -1; ++ gid_t gid = (gid_t) -1; ++ int i, err; + + assert(command); + assert(context); +- assert(ret); +- assert(exec_params); +- assert(exec_params->fds || exec_params->n_fds <= 0); ++ assert(params); ++ assert(error); + +- if (context->std_input == EXEC_INPUT_SOCKET || +- context->std_output == EXEC_OUTPUT_SOCKET || +- context->std_error == EXEC_OUTPUT_SOCKET) { ++ rename_process_from_path(command->path); + +- if (exec_params->n_fds != 1) +- return -EINVAL; ++ /* We reset exactly these signals, since they are the ++ * only ones we set to SIG_IGN in the main daemon. All ++ * others we leave untouched because we set them to ++ * SIG_DFL or a valid handler initially, both of which ++ * will be demoted to SIG_DFL. */ ++ default_signals(SIGNALS_CRASH_HANDLER, ++ SIGNALS_IGNORE, -1); + +- socket_fd = exec_params->fds[0]; +- } else { +- socket_fd = -1; +- fds = exec_params->fds; +- n_fds = exec_params->n_fds; ++ if (context->ignore_sigpipe) ++ ignore_signals(SIGPIPE, -1); ++ ++ err = reset_signal_mask(); ++ if (err < 0) { ++ *error = EXIT_SIGNAL_MASK; ++ return err; + } + +- r = exec_context_load_environment(context, &files_env); +- if (r < 0) { +- log_struct_unit(LOG_ERR, +- exec_params->unit_id, +- "MESSAGE=Failed to load environment files: %s", strerror(-r), +- "ERRNO=%d", -r, +- NULL); +- return r; ++ if (params->idle_pipe) ++ do_idle_pipe_dance(params->idle_pipe); ++ ++ /* Close sockets very early to make sure we don't ++ * block init reexecution because it cannot bind its ++ * sockets */ ++ log_forget_fds(); ++ ++ if (socket_fd >= 0) ++ dont_close[n_dont_close++] = socket_fd; ++ if (n_fds > 0) { ++ memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); ++ n_dont_close += n_fds; ++ } ++ if (runtime) { ++ if (runtime->netns_storage_socket[0] >= 0) ++ dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; ++ if (runtime->netns_storage_socket[1] >= 0) ++ dont_close[n_dont_close++] = runtime->netns_storage_socket[1]; + } + +- argv = exec_params->argv ?: command->argv; ++ err = close_all_fds(dont_close, n_dont_close); ++ if (err < 0) { ++ *error = EXIT_FDS; ++ return err; ++ } + +- line = exec_command_line(argv); +- if (!line) +- return log_oom(); ++ if (!context->same_pgrp) ++ if (setsid() < 0) { ++ *error = EXIT_SETSID; ++ return -errno; ++ } + +- log_struct_unit(LOG_DEBUG, +- exec_params->unit_id, +- "EXECUTABLE=%s", command->path, +- "MESSAGE=About to execute: %s", line, +- NULL); +- free(line); ++ exec_context_tty_reset(context); ++ ++ if (params->confirm_spawn) { ++ char response; ++ ++ err = ask_for_confirmation(&response, argv); ++ if (err == -ETIMEDOUT) ++ write_confirm_message("Confirmation question timed out, assuming positive response.\n"); ++ else if (err < 0) ++ write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err)); ++ else if (response == 's') { ++ write_confirm_message("Skipping execution.\n"); ++ *error = EXIT_CONFIRM; ++ return -ECANCELED; ++ } else if (response == 'n') { ++ write_confirm_message("Failing execution.\n"); ++ *error = 0; ++ return 0; ++ } ++ } + +- pid = fork(); +- if (pid < 0) +- return -errno; ++ /* If a socket is connected to STDIN/STDOUT/STDERR, we ++ * must sure to drop O_NONBLOCK */ ++ if (socket_fd >= 0) ++ fd_nonblock(socket_fd, false); + +- if (pid == 0) { +- _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; +- const char *username = NULL, *home = NULL, *shell = NULL; +- unsigned n_dont_close = 0; +- int dont_close[n_fds + 3]; +- uid_t uid = (uid_t) -1; +- gid_t gid = (gid_t) -1; +- int i, err; +- +- /* child */ +- +- rename_process_from_path(command->path); +- +- /* We reset exactly these signals, since they are the +- * only ones we set to SIG_IGN in the main daemon. All +- * others we leave untouched because we set them to +- * SIG_DFL or a valid handler initially, both of which +- * will be demoted to SIG_DFL. */ +- default_signals(SIGNALS_CRASH_HANDLER, +- SIGNALS_IGNORE, -1); +- +- if (context->ignore_sigpipe) +- ignore_signals(SIGPIPE, -1); +- +- err = reset_signal_mask(); ++ err = setup_input(context, socket_fd, params->apply_tty_stdin); ++ if (err < 0) { ++ *error = EXIT_STDIN; ++ return err; ++ } ++ ++ err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin); ++ if (err < 0) { ++ *error = EXIT_STDOUT; ++ return err; ++ } ++ ++ err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin); ++ if (err < 0) { ++ *error = EXIT_STDERR; ++ return err; ++ } ++ ++ if (params->cgroup_path) { ++ err = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0); + if (err < 0) { +- r = EXIT_SIGNAL_MASK; +- goto fail_child; ++ *error = EXIT_CGROUP; ++ return err; + } ++ } + +- if (exec_params->idle_pipe) +- do_idle_pipe_dance(exec_params->idle_pipe); ++ if (context->oom_score_adjust_set) { ++ char t[16]; + +- /* Close sockets very early to make sure we don't +- * block init reexecution because it cannot bind its +- * sockets */ +- log_forget_fds(); ++ snprintf(t, sizeof(t), "%i", context->oom_score_adjust); ++ char_array_0(t); + +- if (socket_fd >= 0) +- dont_close[n_dont_close++] = socket_fd; +- if (n_fds > 0) { +- memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); +- n_dont_close += n_fds; +- } +- if (runtime) { +- if (runtime->netns_storage_socket[0] >= 0) +- dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; +- if (runtime->netns_storage_socket[1] >= 0) +- dont_close[n_dont_close++] = runtime->netns_storage_socket[1]; ++ if (write_string_file("/proc/self/oom_score_adj", t) < 0) { ++ *error = EXIT_OOM_ADJUST; ++ return -errno; + } ++ } + +- err = close_all_fds(dont_close, n_dont_close); +- if (err < 0) { +- r = EXIT_FDS; +- goto fail_child; ++ if (context->nice_set) ++ if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { ++ *error = EXIT_NICE; ++ return -errno; + } + +- if (!context->same_pgrp) +- if (setsid() < 0) { +- err = -errno; +- r = EXIT_SETSID; +- goto fail_child; +- } ++ if (context->cpu_sched_set) { ++ struct sched_param param = { ++ .sched_priority = context->cpu_sched_priority, ++ }; + +- exec_context_tty_reset(context); ++ err = sched_setscheduler(0, ++ context->cpu_sched_policy | ++ (context->cpu_sched_reset_on_fork ? ++ SCHED_RESET_ON_FORK : 0), ++ ¶m); ++ if (err < 0) { ++ *error = EXIT_SETSCHEDULER; ++ return -errno; ++ } ++ } + +- if (exec_params->confirm_spawn) { +- char response; +- +- err = ask_for_confirmation(&response, argv); +- if (err == -ETIMEDOUT) +- write_confirm_message("Confirmation question timed out, assuming positive response.\n"); +- else if (err < 0) +- write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err)); +- else if (response == 's') { +- write_confirm_message("Skipping execution.\n"); +- err = -ECANCELED; +- r = EXIT_CONFIRM; +- goto fail_child; +- } else if (response == 'n') { +- write_confirm_message("Failing execution.\n"); +- err = r = 0; +- goto fail_child; +- } ++ if (context->cpuset) ++ if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) { ++ *error = EXIT_CPUAFFINITY; ++ return -errno; + } + +- /* If a socket is connected to STDIN/STDOUT/STDERR, we +- * must sure to drop O_NONBLOCK */ +- if (socket_fd >= 0) +- fd_nonblock(socket_fd, false); ++ if (context->ioprio_set) ++ if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) { ++ *error = EXIT_IOPRIO; ++ return -errno; ++ } + +- err = setup_input(context, socket_fd, exec_params->apply_tty_stdin); +- if (err < 0) { +- r = EXIT_STDIN; +- goto fail_child; ++ if (context->timer_slack_nsec != NSEC_INFINITY) ++ if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) { ++ *error = EXIT_TIMERSLACK; ++ return -errno; + } + +- err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), exec_params->unit_id, exec_params->apply_tty_stdin); +- if (err < 0) { +- r = EXIT_STDOUT; +- goto fail_child; ++ if (context->personality != 0xffffffffUL) ++ if (personality(context->personality) < 0) { ++ *error = EXIT_PERSONALITY; ++ return -errno; + } + +- err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), exec_params->unit_id, exec_params->apply_tty_stdin); ++ if (context->utmp_id) ++ utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path); ++ ++ if (context->user) { ++ username = context->user; ++ err = get_user_creds(&username, &uid, &gid, &home, &shell); + if (err < 0) { +- r = EXIT_STDERR; +- goto fail_child; ++ *error = EXIT_USER; ++ return err; + } + +- if (exec_params->cgroup_path) { +- err = cg_attach_everywhere(exec_params->cgroup_supported, exec_params->cgroup_path, 0); ++ if (is_terminal_input(context->std_input)) { ++ err = chown_terminal(STDIN_FILENO, uid); + if (err < 0) { +- r = EXIT_CGROUP; +- goto fail_child; ++ *error = EXIT_STDIN; ++ return err; + } + } ++ } + +- if (context->oom_score_adjust_set) { +- char t[16]; ++#ifdef HAVE_PAM ++ if (params->cgroup_path && context->user && context->pam_name) { ++ err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid); ++ if (err < 0) { ++ *error = EXIT_CGROUP; ++ return err; ++ } + +- snprintf(t, sizeof(t), "%i", context->oom_score_adjust); +- char_array_0(t); + +- if (write_string_file("/proc/self/oom_score_adj", t) < 0) { +- err = -errno; +- r = EXIT_OOM_ADJUST; +- goto fail_child; +- } ++ err = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid); ++ if (err < 0) { ++ *error = EXIT_CGROUP; ++ return err; + } ++ } ++#endif + +- if (context->nice_set) +- if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { +- err = -errno; +- r = EXIT_NICE; +- goto fail_child; +- } ++ if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) { ++ char **rt; + +- if (context->cpu_sched_set) { +- struct sched_param param = { +- .sched_priority = context->cpu_sched_priority, +- }; ++ STRV_FOREACH(rt, context->runtime_directory) { ++ _cleanup_free_ char *p; + +- r = sched_setscheduler(0, +- context->cpu_sched_policy | +- (context->cpu_sched_reset_on_fork ? +- SCHED_RESET_ON_FORK : 0), +- ¶m); +- if (r < 0) { +- err = -errno; +- r = EXIT_SETSCHEDULER; +- goto fail_child; ++ p = strjoin(params->runtime_prefix, "/", *rt, NULL); ++ if (!p) { ++ *error = EXIT_RUNTIME_DIRECTORY; ++ return -ENOMEM; + } +- } + +- if (context->cpuset) +- if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) { +- err = -errno; +- r = EXIT_CPUAFFINITY; +- goto fail_child; ++ err = mkdir_safe(p, context->runtime_directory_mode, uid, gid); ++ if (err < 0) { ++ *error = EXIT_RUNTIME_DIRECTORY; ++ return err; + } ++ } ++ } + +- if (context->ioprio_set) +- if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) { +- err = -errno; +- r = EXIT_IOPRIO; +- goto fail_child; +- } ++ if (params->apply_permissions) { ++ err = enforce_groups(context, username, gid); ++ if (err < 0) { ++ *error = EXIT_GROUP; ++ return err; ++ } ++ } + +- if (context->timer_slack_nsec != NSEC_INFINITY) +- if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) { +- err = -errno; +- r = EXIT_TIMERSLACK; +- goto fail_child; +- } ++ umask(context->umask); + +- if (context->personality != 0xffffffffUL) +- if (personality(context->personality) < 0) { +- err = -errno; +- r = EXIT_PERSONALITY; +- goto fail_child; +- } ++#ifdef HAVE_PAM ++ if (params->apply_permissions && context->pam_name && username) { ++ err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds); ++ if (err < 0) { ++ *error = EXIT_PAM; ++ return err; ++ } ++ } ++#endif + +- if (context->utmp_id) +- utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path); ++ if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) { ++ err = setup_netns(runtime->netns_storage_socket); ++ if (err < 0) { ++ *error = EXIT_NETWORK; ++ return err; ++ } ++ } + +- if (context->user) { +- username = context->user; +- err = get_user_creds(&username, &uid, &gid, &home, &shell); +- if (err < 0) { +- r = EXIT_USER; +- goto fail_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)) || ++ context->private_devices || ++ context->protect_system != PROTECT_SYSTEM_NO || ++ context->protect_home != PROTECT_HOME_NO) { ++ ++ char *tmp = NULL, *var = NULL; ++ ++ /* The runtime struct only contains the parent ++ * of the private /tmp, which is ++ * non-accessible to world users. Inside of it ++ * there's a /tmp that is sticky, and that's ++ * the one we want to use here. */ ++ ++ if (context->private_tmp && runtime) { ++ if (runtime->tmp_dir) ++ tmp = strappenda(runtime->tmp_dir, "/tmp"); ++ if (runtime->var_tmp_dir) ++ var = strappenda(runtime->var_tmp_dir, "/tmp"); ++ } + +- if (is_terminal_input(context->std_input)) { +- err = chown_terminal(STDIN_FILENO, uid); +- if (err < 0) { +- r = EXIT_STDIN; +- goto fail_child; +- } +- } ++ err = setup_namespace( ++ context->read_write_dirs, ++ context->read_only_dirs, ++ context->inaccessible_dirs, ++ tmp, ++ var, ++ context->private_devices, ++ context->protect_home, ++ context->protect_system, ++ context->mount_flags); ++ if (err < 0) { ++ *error = EXIT_NAMESPACE; ++ return err; + } ++ } + +-#ifdef HAVE_PAM +- if (exec_params->cgroup_path && context->user && context->pam_name) { +- err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, exec_params->cgroup_path, 0644, uid, gid); +- if (err < 0) { +- r = EXIT_CGROUP; +- goto fail_child; ++ if (params->apply_chroot) { ++ if (context->root_directory) ++ if (chroot(context->root_directory) < 0) { ++ *error = EXIT_CHROOT; ++ return -errno; + } + ++ if (chdir(context->working_directory ? context->working_directory : "/") < 0) { ++ *error = EXIT_CHDIR; ++ return -errno; ++ } ++ } else { ++ _cleanup_free_ char *d = NULL; + +- err = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, exec_params->cgroup_path, 0755, uid, gid); +- if (err < 0) { +- r = EXIT_CGROUP; +- goto fail_child; +- } ++ if (asprintf(&d, "%s/%s", ++ context->root_directory ? context->root_directory : "", ++ context->working_directory ? context->working_directory : "") < 0) { ++ *error = EXIT_MEMORY; ++ return -ENOMEM; + } +-#endif + +- if (!strv_isempty(context->runtime_directory) && exec_params->runtime_prefix) { +- char **rt; ++ if (chdir(d) < 0) { ++ *error = EXIT_CHDIR; ++ return -errno; ++ } ++ } + +- STRV_FOREACH(rt, context->runtime_directory) { +- _cleanup_free_ char *p; ++ /* We repeat the fd closing here, to make sure that ++ * nothing is leaked from the PAM modules. Note that ++ * we are more aggressive this time since socket_fd ++ * and the netns fds we don#t need anymore. */ ++ err = close_all_fds(fds, n_fds); ++ if (err >= 0) ++ err = shift_fds(fds, n_fds); ++ if (err >= 0) ++ err = flags_fds(fds, n_fds, context->non_blocking); ++ if (err < 0) { ++ *error = EXIT_FDS; ++ return err; ++ } + +- p = strjoin(exec_params->runtime_prefix, "/", *rt, NULL); +- if (!p) { +- r = EXIT_RUNTIME_DIRECTORY; +- err = -ENOMEM; +- goto fail_child; +- } ++ if (params->apply_permissions) { + +- err = mkdir_safe(p, context->runtime_directory_mode, uid, gid); +- if (err < 0) { +- r = EXIT_RUNTIME_DIRECTORY; +- goto fail_child; +- } ++ for (i = 0; i < _RLIMIT_MAX; i++) { ++ if (!context->rlimit[i]) ++ continue; ++ ++ if (setrlimit_closest(i, context->rlimit[i]) < 0) { ++ *error = EXIT_LIMITS; ++ return -errno; + } + } + +- if (exec_params->apply_permissions) { +- err = enforce_groups(context, username, gid); ++ if (context->capability_bounding_set_drop) { ++ err = capability_bounding_set_drop(context->capability_bounding_set_drop, false); + if (err < 0) { +- r = EXIT_GROUP; +- goto fail_child; ++ *error = EXIT_CAPABILITIES; ++ return err; + } + } + +- umask(context->umask); +- +-#ifdef HAVE_PAM +- if (exec_params->apply_permissions && context->pam_name && username) { +- err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds); ++ if (context->user) { ++ err = enforce_user(context, uid); + if (err < 0) { +- r = EXIT_PAM; +- goto fail_child; ++ *error = EXIT_USER; ++ return err; + } + } +-#endif +- if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) { +- err = setup_netns(runtime->netns_storage_socket); +- if (err < 0) { +- r = EXIT_NETWORK; +- goto fail_child; ++ ++ /* PR_GET_SECUREBITS is not privileged, while ++ * PR_SET_SECUREBITS is. So to suppress ++ * potential EPERMs we'll try not to call ++ * PR_SET_SECUREBITS unless necessary. */ ++ if (prctl(PR_GET_SECUREBITS) != context->secure_bits) ++ if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) { ++ *error = EXIT_SECUREBITS; ++ return -errno; ++ } ++ ++ if (context->capabilities) ++ if (cap_set_proc(context->capabilities) < 0) { ++ *error = EXIT_CAPABILITIES; ++ return -errno; + } +- } + +- 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)) || +- context->private_devices || +- context->protect_system != PROTECT_SYSTEM_NO || +- context->protect_home != PROTECT_HOME_NO) { +- +- char *tmp = NULL, *var = NULL; +- +- /* The runtime struct only contains the parent +- * of the private /tmp, which is +- * non-accessible to world users. Inside of it +- * there's a /tmp that is sticky, and that's +- * the one we want to use here. */ +- +- if (context->private_tmp && runtime) { +- if (runtime->tmp_dir) +- tmp = strappenda(runtime->tmp_dir, "/tmp"); +- if (runtime->var_tmp_dir) +- var = strappenda(runtime->var_tmp_dir, "/tmp"); ++ if (context->no_new_privileges) ++ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { ++ *error = EXIT_NO_NEW_PRIVILEGES; ++ return -errno; + } + +- err = setup_namespace( +- context->read_write_dirs, +- context->read_only_dirs, +- context->inaccessible_dirs, +- tmp, +- var, +- context->private_devices, +- context->protect_home, +- context->protect_system, +- context->mount_flags); ++#ifdef HAVE_SECCOMP ++ if (context->address_families_whitelist || ++ !set_isempty(context->address_families)) { ++ err = apply_address_families(context); + if (err < 0) { +- r = EXIT_NAMESPACE; +- goto fail_child; ++ *error = EXIT_ADDRESS_FAMILIES; ++ return err; + } + } + +- if (exec_params->apply_chroot) { +- if (context->root_directory) +- if (chroot(context->root_directory) < 0) { +- err = -errno; +- r = EXIT_CHROOT; +- goto fail_child; +- } +- +- if (chdir(context->working_directory ? context->working_directory : "/") < 0) { +- err = -errno; +- r = EXIT_CHDIR; +- goto fail_child; +- } +- } else { +- _cleanup_free_ char *d = NULL; +- +- if (asprintf(&d, "%s/%s", +- context->root_directory ? context->root_directory : "", +- context->working_directory ? context->working_directory : "") < 0) { +- err = -ENOMEM; +- r = EXIT_MEMORY; +- goto fail_child; ++ if (context->syscall_whitelist || ++ !set_isempty(context->syscall_filter) || ++ !set_isempty(context->syscall_archs)) { ++ err = apply_seccomp(context); ++ if (err < 0) { ++ *error = EXIT_SECCOMP; ++ return err; + } ++ } ++#endif + +- if (chdir(d) < 0) { +- err = -errno; +- r = EXIT_CHDIR; +- goto fail_child; ++#ifdef HAVE_SELINUX ++ if (context->selinux_context && use_selinux()) { ++ err = setexeccon(context->selinux_context); ++ if (err < 0 && !context->selinux_context_ignore) { ++ *error = EXIT_SELINUX_CONTEXT; ++ return err; + } + } ++#endif + +- /* We repeat the fd closing here, to make sure that +- * nothing is leaked from the PAM modules. Note that +- * we are more aggressive this time since socket_fd +- * and the netns fds we don#t need anymore. */ +- err = close_all_fds(fds, n_fds); +- if (err >= 0) +- err = shift_fds(fds, n_fds); +- if (err >= 0) +- err = flags_fds(fds, n_fds, context->non_blocking); +- if (err < 0) { +- r = EXIT_FDS; +- goto fail_child; ++#ifdef HAVE_APPARMOR ++ if (context->apparmor_profile && use_apparmor()) { ++ err = aa_change_onexec(context->apparmor_profile); ++ if (err < 0 && !context->apparmor_profile_ignore) { ++ *error = EXIT_APPARMOR_PROFILE; ++ return err; ++ } + } ++#endif ++ } + +- if (exec_params->apply_permissions) { ++ err = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env); ++ if (err < 0) { ++ *error = EXIT_MEMORY; ++ return err; ++ } + +- for (i = 0; i < _RLIMIT_MAX; i++) { +- if (!context->rlimit[i]) +- continue; ++ final_env = strv_env_merge(5, ++ params->environment, ++ our_env, ++ context->environment, ++ files_env, ++ pam_env, ++ NULL); ++ if (!final_env) { ++ *error = EXIT_MEMORY; ++ return -ENOMEM; ++ } + +- if (setrlimit_closest(i, context->rlimit[i]) < 0) { +- err = -errno; +- r = EXIT_LIMITS; +- goto fail_child; +- } +- } ++ final_argv = replace_env_argv(argv, final_env); ++ if (!final_argv) { ++ *error = EXIT_MEMORY; ++ return -ENOMEM; ++ } + +- if (context->capability_bounding_set_drop) { +- err = capability_bounding_set_drop(context->capability_bounding_set_drop, false); +- if (err < 0) { +- r = EXIT_CAPABILITIES; +- goto fail_child; +- } +- } ++ final_env = strv_env_clean(final_env); + +- if (context->user) { +- err = enforce_user(context, uid); +- if (err < 0) { +- r = EXIT_USER; +- goto fail_child; +- } +- } ++ if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { ++ _cleanup_free_ char *line; + +- /* PR_GET_SECUREBITS is not privileged, while +- * PR_SET_SECUREBITS is. So to suppress +- * potential EPERMs we'll try not to call +- * PR_SET_SECUREBITS unless necessary. */ +- if (prctl(PR_GET_SECUREBITS) != context->secure_bits) +- if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) { +- err = -errno; +- r = EXIT_SECUREBITS; +- goto fail_child; +- } ++ line = exec_command_line(final_argv); ++ if (line) { ++ log_open(); ++ log_struct_unit(LOG_DEBUG, ++ params->unit_id, ++ "EXECUTABLE=%s", command->path, ++ "MESSAGE=Executing: %s", line, ++ NULL); ++ log_close(); ++ } ++ } ++ execve(command->path, final_argv, final_env); ++ *error = EXIT_EXEC; ++ return -errno; ++} + +- if (context->capabilities) +- if (cap_set_proc(context->capabilities) < 0) { +- err = -errno; +- r = EXIT_CAPABILITIES; +- goto fail_child; +- } ++int exec_spawn(ExecCommand *command, ++ const ExecContext *context, ++ const ExecParameters *params, ++ ExecRuntime *runtime, ++ pid_t *ret) { + +- if (context->no_new_privileges) +- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { +- err = -errno; +- r = EXIT_NO_NEW_PRIVILEGES; +- goto fail_child; +- } ++ _cleanup_strv_free_ char **files_env = NULL; ++ int *fds = NULL; unsigned n_fds = 0; ++ char *line, **argv; ++ int socket_fd; ++ pid_t pid; ++ int err; + +-#ifdef HAVE_SECCOMP +- if (context->address_families_whitelist || +- !set_isempty(context->address_families)) { +- err = apply_address_families(context); +- if (err < 0) { +- r = EXIT_ADDRESS_FAMILIES; +- goto fail_child; +- } +- } ++ assert(command); ++ assert(context); ++ assert(ret); ++ assert(params); ++ assert(params->fds || params->n_fds <= 0); + +- if (context->syscall_whitelist || +- !set_isempty(context->syscall_filter) || +- !set_isempty(context->syscall_archs)) { +- err = apply_seccomp(context); +- if (err < 0) { +- r = EXIT_SECCOMP; +- goto fail_child; +- } +- } +-#endif ++ if (context->std_input == EXEC_INPUT_SOCKET || ++ context->std_output == EXEC_OUTPUT_SOCKET || ++ context->std_error == EXEC_OUTPUT_SOCKET) { + +-#ifdef HAVE_SELINUX +- if (context->selinux_context && use_selinux()) { +- err = setexeccon(context->selinux_context); +- if (err < 0 && !context->selinux_context_ignore) { +- r = EXIT_SELINUX_CONTEXT; +- goto fail_child; +- } +- } +-#endif ++ if (params->n_fds != 1) ++ return -EINVAL; + +-#ifdef HAVE_APPARMOR +- if (context->apparmor_profile && use_apparmor()) { +- err = aa_change_onexec(context->apparmor_profile); +- if (err < 0 && !context->apparmor_profile_ignore) { +- r = EXIT_APPARMOR_PROFILE; +- goto fail_child; +- } +- } +-#endif +- } ++ socket_fd = params->fds[0]; ++ } else { ++ socket_fd = -1; ++ fds = params->fds; ++ n_fds = params->n_fds; ++ } + +- err = build_environment(context, n_fds, exec_params->watchdog_usec, home, username, shell, &our_env); +- if (r < 0) { +- r = EXIT_MEMORY; +- goto fail_child; +- } ++ err = exec_context_load_environment(context, &files_env); ++ if (err < 0) { ++ log_struct_unit(LOG_ERR, ++ params->unit_id, ++ "MESSAGE=Failed to load environment files: %s", strerror(-err), ++ "ERRNO=%d", -err, ++ NULL); ++ return err; ++ } + +- final_env = strv_env_merge(5, +- exec_params->environment, +- our_env, +- context->environment, +- files_env, +- pam_env, +- NULL); +- if (!final_env) { +- err = -ENOMEM; +- r = EXIT_MEMORY; +- goto fail_child; +- } ++ argv = params->argv ?: command->argv; + +- final_argv = replace_env_argv(argv, final_env); +- if (!final_argv) { +- err = -ENOMEM; +- r = EXIT_MEMORY; +- goto fail_child; +- } ++ line = exec_command_line(argv); ++ if (!line) ++ return log_oom(); + +- final_env = strv_env_clean(final_env); +- +- if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { +- line = exec_command_line(final_argv); +- if (line) { +- log_open(); +- log_struct_unit(LOG_DEBUG, +- exec_params->unit_id, +- "EXECUTABLE=%s", command->path, +- "MESSAGE=Executing: %s", line, +- NULL); +- log_close(); +- free(line); +- line = NULL; +- } +- } +- execve(command->path, final_argv, final_env); +- err = -errno; +- r = EXIT_EXEC; ++ log_struct_unit(LOG_DEBUG, ++ params->unit_id, ++ "EXECUTABLE=%s", command->path, ++ "MESSAGE=About to execute: %s", line, ++ NULL); ++ free(line); ++ ++ pid = fork(); ++ if (pid < 0) ++ return -errno; ++ ++ if (pid == 0) { ++ int r; + +- fail_child: ++ err = exec_child(command, ++ context, ++ params, ++ runtime, ++ argv, ++ socket_fd, ++ fds, n_fds, ++ files_env, ++ &r); + if (r != 0) { + log_open(); + log_struct(LOG_ERR, MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED), +@@ -1794,7 +1799,7 @@ int exec_spawn(ExecCommand *command, + } + + log_struct_unit(LOG_DEBUG, +- exec_params->unit_id, ++ params->unit_id, + "MESSAGE=Forked %s as "PID_FMT, + command->path, pid, + NULL); +@@ -1804,8 +1809,8 @@ int exec_spawn(ExecCommand *command, + * outside of the cgroup) and in the parent (so that we can be + * sure that when we kill the cgroup the process will be + * killed too). */ +- if (exec_params->cgroup_path) +- cg_attach(SYSTEMD_CGROUP_CONTROLLER, exec_params->cgroup_path, pid); ++ if (params->cgroup_path) ++ cg_attach(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, pid); + + exec_status_start(&command->exec_status, pid); + diff --git a/0176-exit-status-fix-URL-in-comment.patch b/0176-exit-status-fix-URL-in-comment.patch new file mode 100644 index 0000000..109b86b --- /dev/null +++ b/0176-exit-status-fix-URL-in-comment.patch @@ -0,0 +1,23 @@ +From 5b89f67f03dce933c0b30408ce81e2ac539ed544 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 5 Sep 2014 13:48:05 +0200 +Subject: [PATCH] exit-status: fix URL in comment + +The LSB sites have moved, so update the URL. +--- + src/shared/exit-status.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h +index 7438508e4d..9d27c01658 100644 +--- a/src/shared/exit-status.h ++++ b/src/shared/exit-status.h +@@ -39,7 +39,7 @@ typedef enum ExitStatus { + * use them here under the assumption that they hence are + * unused by init scripts. + * +- * http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */ ++ * http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */ + + EXIT_CHDIR = 200, + EXIT_NICE, diff --git a/0177-update-TODO.patch b/0177-update-TODO.patch new file mode 100644 index 0000000..49ad4c1 --- /dev/null +++ b/0177-update-TODO.patch @@ -0,0 +1,22 @@ +From 3bcde97e8502c48b53f7420e2433ca68e601662d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 5 Sep 2014 21:49:23 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/TODO b/TODO +index 380fd494f2..7029769770 100644 +--- a/TODO ++++ b/TODO +@@ -26,6 +26,8 @@ External: + + Features: + ++* man: maybe use the word "inspect" rather than "introspect"? ++ + * introduce machines.target to order after all nspawn instances + + * systemd-nspawn@.service should fail if some nspawn arg is invalid, with Type=notify diff --git a/0178-man-fix-references-to-systemctl-man-page-which-is-no.patch b/0178-man-fix-references-to-systemctl-man-page-which-is-no.patch new file mode 100644 index 0000000..c20536e --- /dev/null +++ b/0178-man-fix-references-to-systemctl-man-page-which-is-no.patch @@ -0,0 +1,201 @@ +From 67826132adfdf626413f08fb664debd4a7ec35b7 Mon Sep 17 00:00:00 2001 +From: Michael Biebl +Date: Sat, 6 Sep 2014 13:43:25 +0200 +Subject: [PATCH] man: fix references to systemctl man page which is now in + section 1 + +https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=760613 +--- + man/systemd.automount.xml | 2 +- + man/systemd.device.xml | 2 +- + man/systemd.exec.xml | 2 +- + man/systemd.kill.xml | 2 +- + man/systemd.mount.xml | 2 +- + man/systemd.path.xml | 2 +- + man/systemd.service.xml | 2 +- + man/systemd.snapshot.xml | 4 ++-- + man/systemd.socket.xml | 2 +- + man/systemd.swap.xml | 2 +- + man/systemd.target.xml | 2 +- + man/systemd.timer.xml | 2 +- + man/systemd.unit.xml | 2 +- + 13 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml +index 34105126cd..f04a4a4927 100644 +--- a/man/systemd.automount.xml ++++ b/man/systemd.automount.xml +@@ -156,7 +156,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.mount5, + mount8, +diff --git a/man/systemd.device.xml b/man/systemd.device.xml +index 619fe19680..557f15f906 100644 +--- a/man/systemd.device.xml ++++ b/man/systemd.device.xml +@@ -185,7 +185,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + udev7, + systemd.directives7 +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 707d582b4f..6d0113f5cc 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -1533,7 +1533,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + journalctl8, + systemd.unit5, + systemd.service5, +diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml +index 39796470a0..caee371c81 100644 +--- a/man/systemd.kill.xml ++++ b/man/systemd.kill.xml +@@ -199,7 +199,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + journalctl8, + systemd.unit5, + systemd.service5, +diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml +index f116aa577c..ba841c3bab 100644 +--- a/man/systemd.mount.xml ++++ b/man/systemd.mount.xml +@@ -352,7 +352,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.exec5, + systemd.kill5, +diff --git a/man/systemd.path.xml b/man/systemd.path.xml +index 8d86fca5d6..c6d61cf2b1 100644 +--- a/man/systemd.path.xml ++++ b/man/systemd.path.xml +@@ -224,7 +224,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.service5, + inotify7, +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index 8b17f857ce..c84a5254b3 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -1236,7 +1236,7 @@ ExecStart=/bin/echo $ONE $TWO ${TWO} + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.exec5, + systemd.resource-control5, +diff --git a/man/systemd.snapshot.xml b/man/systemd.snapshot.xml +index 1bb074a9b1..f08e38e07e 100644 +--- a/man/systemd.snapshot.xml ++++ b/man/systemd.snapshot.xml +@@ -63,7 +63,7 @@ + Snapshots are not configured on disk but created + dynamically via systemctl snapshot + (see +- systemctl8 ++ systemctl1 + for details) or an equivalent command. When created, + they will automatically get dependencies on the + currently activated units. They act as saved +@@ -79,7 +79,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.directives7 + +diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml +index 8394fa81aa..7a63348caf 100644 +--- a/man/systemd.socket.xml ++++ b/man/systemd.socket.xml +@@ -889,7 +889,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.exec5, + systemd.kill5, +diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml +index 61901d268e..62a4d08b9c 100644 +--- a/man/systemd.swap.xml ++++ b/man/systemd.swap.xml +@@ -204,7 +204,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.exec5, + systemd.kill5, +diff --git a/man/systemd.target.xml b/man/systemd.target.xml +index 15662a548d..e2cdfd83c3 100644 +--- a/man/systemd.target.xml ++++ b/man/systemd.target.xml +@@ -99,7 +99,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.special7, + systemd.directives7 +diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml +index 9fcf5ccb97..55b458557f 100644 +--- a/man/systemd.timer.xml ++++ b/man/systemd.timer.xml +@@ -298,7 +298,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.unit5, + systemd.service5, + systemd.time7, +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index a1fcfd8781..6ea552e8b4 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -1504,7 +1504,7 @@ + See Also + + systemd1, +- systemctl8, ++ systemctl1, + systemd.special7, + systemd.service5, + systemd.socket5, diff --git a/0179-hwdb-Update-database-of-Bluetooth-company-identifier.patch b/0179-hwdb-Update-database-of-Bluetooth-company-identifier.patch new file mode 100644 index 0000000..345ec31 --- /dev/null +++ b/0179-hwdb-Update-database-of-Bluetooth-company-identifier.patch @@ -0,0 +1,101 @@ +From de68938a2cb3ab535ebd9198723a651753c1a1df Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Mon, 8 Sep 2014 05:06:18 +0200 +Subject: [PATCH] hwdb: Update database of Bluetooth company identifiers + +--- + hwdb/20-bluetooth-vendor-product.hwdb | 77 ++++++++++++++++++++++++++++++++++- + 1 file changed, 76 insertions(+), 1 deletion(-) + +diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb +index 9f3136a6a7..14aee74a1a 100644 +--- a/hwdb/20-bluetooth-vendor-product.hwdb ++++ b/hwdb/20-bluetooth-vendor-product.hwdb +@@ -184,7 +184,7 @@ bluetooth:v003B* + ID_VENDOR_FROM_DATABASE=Gennum Corporation + + bluetooth:v003C* +- ID_VENDOR_FROM_DATABASE=Research In Motion ++ ID_VENDOR_FROM_DATABASE=BlackBerry Limited (formerly Research In Motion) + + bluetooth:v003D* + ID_VENDOR_FROM_DATABASE=IPextreme, Inc. +@@ -1073,3 +1073,78 @@ bluetooth:v0162* + + bluetooth:v0163* + ID_VENDOR_FROM_DATABASE=PCH International ++ ++bluetooth:v0164* ++ ID_VENDOR_FROM_DATABASE=Qingdao Yeelink Information Technology Co., Ltd. ++ ++bluetooth:v0165* ++ ID_VENDOR_FROM_DATABASE=Milwaukee Tool (formerly Milwaukee Electric Tools) ++ ++bluetooth:v0166* ++ ID_VENDOR_FROM_DATABASE=MISHIK Pte Ltd ++ ++bluetooth:v0167* ++ ID_VENDOR_FROM_DATABASE=Bayer HealthCare ++ ++bluetooth:v0168* ++ ID_VENDOR_FROM_DATABASE=Spicebox LLC ++ ++bluetooth:v0169* ++ ID_VENDOR_FROM_DATABASE=emberlight ++ ++bluetooth:v016A* ++ ID_VENDOR_FROM_DATABASE=Cooper-Atkins Corporation ++ ++bluetooth:v016B* ++ ID_VENDOR_FROM_DATABASE=Qblinks ++ ++bluetooth:v016C* ++ ID_VENDOR_FROM_DATABASE=MYSPHERA ++ ++bluetooth:v016D* ++ ID_VENDOR_FROM_DATABASE=LifeScan Inc ++ ++bluetooth:v016E* ++ ID_VENDOR_FROM_DATABASE=Volantic AB ++ ++bluetooth:v016F* ++ ID_VENDOR_FROM_DATABASE=Podo Labs, Inc ++ ++bluetooth:v0170* ++ ID_VENDOR_FROM_DATABASE=Roche Diabetes Care AG ++ ++bluetooth:v0171* ++ ID_VENDOR_FROM_DATABASE=Amazon Fulfillment Service ++ ++bluetooth:v0172* ++ ID_VENDOR_FROM_DATABASE=Connovate Technology Private Limited ++ ++bluetooth:v0173* ++ ID_VENDOR_FROM_DATABASE=Kocomojo, LLC ++ ++bluetooth:v0174* ++ ID_VENDOR_FROM_DATABASE=Everykey LLC ++ ++bluetooth:v0175* ++ ID_VENDOR_FROM_DATABASE=Dynamic Controls ++ ++bluetooth:v0176* ++ ID_VENDOR_FROM_DATABASE=SentriLock ++ ++bluetooth:v0177* ++ ID_VENDOR_FROM_DATABASE=I-SYST inc. ++ ++bluetooth:v0178* ++ ID_VENDOR_FROM_DATABASE=CASIO COMPUTER CO., LTD. ++ ++bluetooth:v0179* ++ ID_VENDOR_FROM_DATABASE=LAPIS Semiconductor Co., Ltd. ++ ++bluetooth:v017A* ++ ID_VENDOR_FROM_DATABASE=Telemonitor, Inc. ++ ++bluetooth:v017B* ++ ID_VENDOR_FROM_DATABASE=taskit GmbH ++ ++bluetooth:v017C* ++ ID_VENDOR_FROM_DATABASE=Daimler AG diff --git a/0180-bus-factor-out-bus-policy-items.patch b/0180-bus-factor-out-bus-policy-items.patch new file mode 100644 index 0000000..8f73f8c --- /dev/null +++ b/0180-bus-factor-out-bus-policy-items.patch @@ -0,0 +1,268 @@ +From 5369c77d2ee864ac0464d4adc0774ee70ba9c4bc Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Mon, 18 Aug 2014 22:07:47 +0200 +Subject: [PATCH] bus: factor out bus policy items + +In order to re-use the policy definitions, factor them out into their own +files. +--- + Makefile.am | 2 ++ + src/core/bus-common.c | 35 +++++++++++++++++++++++++++++++++++ + src/core/bus-common.h | 35 +++++++++++++++++++++++++++++++++++ + src/core/busname.c | 8 -------- + src/core/busname.h | 16 +++------------- + src/core/load-fragment.c | 4 ++-- + src/libsystemd/sd-bus/bus-kernel.c | 12 ++++++------ + src/libsystemd/sd-bus/bus-kernel.h | 2 +- + src/test/test-tables.c | 2 +- + 9 files changed, 85 insertions(+), 31 deletions(-) + create mode 100644 src/core/bus-common.c + create mode 100644 src/core/bus-common.h + +diff --git a/Makefile.am b/Makefile.am +index 9c946d7a92..68a78963c1 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1026,6 +1026,8 @@ libsystemd_core_la_SOURCES = \ + src/core/socket.h \ + src/core/busname.c \ + src/core/busname.h \ ++ src/core/bus-common.c \ ++ src/core/bus-common.h \ + src/core/target.c \ + src/core/target.h \ + src/core/snapshot.c \ +diff --git a/src/core/bus-common.c b/src/core/bus-common.c +new file mode 100644 +index 0000000000..4a61cb9a3a +--- /dev/null ++++ b/src/core/bus-common.c +@@ -0,0 +1,35 @@ ++/*-*- 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 "special.h" ++#include "bus-kernel.h" ++#include "bus-internal.h" ++#include "bus-util.h" ++#include "service.h" ++#include "bus-common.h" ++ ++static const char* const bus_policy_access_table[_BUS_POLICY_ACCESS_MAX] = { ++ [BUS_POLICY_ACCESS_SEE] = "see", ++ [BUS_POLICY_ACCESS_TALK] = "talk", ++ [BUS_POLICY_ACCESS_OWN] = "own", ++}; ++ ++DEFINE_STRING_TABLE_LOOKUP(bus_policy_access, BusPolicyAccess); +diff --git a/src/core/bus-common.h b/src/core/bus-common.h +new file mode 100644 +index 0000000000..209f870c72 +--- /dev/null ++++ b/src/core/bus-common.h +@@ -0,0 +1,35 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++#pragma once ++ ++#include "macro.h" ++ ++/*** ++ 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 . ++***/ ++ ++typedef enum BusPolicyAccess { ++ BUS_POLICY_ACCESS_SEE, ++ BUS_POLICY_ACCESS_TALK, ++ BUS_POLICY_ACCESS_OWN, ++ _BUS_POLICY_ACCESS_MAX, ++ _BUS_POLICY_ACCESS_INVALID = -1 ++} BusPolicyAccess; ++ ++const char* bus_policy_access_to_string(BusPolicyAccess i) _const_; ++BusPolicyAccess bus_policy_access_from_string(const char *s) _pure_; +diff --git a/src/core/busname.c b/src/core/busname.c +index 39ea6a0d93..22d2a6d24b 100644 +--- a/src/core/busname.c ++++ b/src/core/busname.c +@@ -911,14 +911,6 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult); + +-static const char* const busname_policy_access_table[_BUSNAME_POLICY_ACCESS_MAX] = { +- [BUSNAME_POLICY_ACCESS_SEE] = "see", +- [BUSNAME_POLICY_ACCESS_TALK] = "talk", +- [BUSNAME_POLICY_ACCESS_OWN] = "own", +-}; +- +-DEFINE_STRING_TABLE_LOOKUP(busname_policy_access, BusNamePolicyAccess); +- + const UnitVTable busname_vtable = { + .object_size = sizeof(BusName), + +diff --git a/src/core/busname.h b/src/core/busname.h +index 65d57f710a..c9b653d82e 100644 +--- a/src/core/busname.h ++++ b/src/core/busname.h +@@ -25,6 +25,7 @@ typedef struct BusName BusName; + typedef struct BusNamePolicy BusNamePolicy; + + #include "unit.h" ++#include "bus-common.h" + + typedef enum BusNameState { + BUSNAME_DEAD, +@@ -58,17 +59,9 @@ typedef enum BusNamePolicyType { + _BUSNAME_POLICY_TYPE_INVALID = -1 + } BusNamePolicyType; + +-typedef enum BusNamePolicyAccess { +- BUSNAME_POLICY_ACCESS_SEE, +- BUSNAME_POLICY_ACCESS_TALK, +- BUSNAME_POLICY_ACCESS_OWN, +- _BUSNAME_POLICY_ACCESS_MAX, +- _BUSNAME_POLICY_ACCESS_INVALID = -1 +-} BusNamePolicyAccess; +- + struct BusNamePolicy { + BusNamePolicyType type; +- BusNamePolicyAccess access; ++ BusPolicyAccess access; + + char *name; + +@@ -97,7 +90,7 @@ struct BusName { + pid_t control_pid; + + LIST_HEAD(BusNamePolicy, policy); +- BusNamePolicyAccess policy_world; ++ BusPolicyAccess policy_world; + }; + + extern const UnitVTable busname_vtable; +@@ -107,6 +100,3 @@ BusNameState busname_state_from_string(const char *s) _pure_; + + const char* busname_result_to_string(BusNameResult i) _const_; + BusNameResult busname_result_from_string(const char *s) _pure_; +- +-const char* busname_policy_access_to_string(BusNamePolicyAccess i) _const_; +-BusNamePolicyAccess busname_policy_access_from_string(const char *s) _pure_; +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index fda27becb5..b4da6a550e 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1686,7 +1686,7 @@ int config_parse_busname_service( + return 0; + } + +-DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access"); ++DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access"); + + int config_parse_bus_policy( + const char *unit, +@@ -1736,7 +1736,7 @@ int config_parse_bus_policy( + access_str++; + access_str += strspn(access_str, WHITESPACE); + +- p->access = busname_policy_access_from_string(access_str); ++ p->access = bus_policy_access_from_string(access_str); + if (p->access < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Invalid busname policy access type '%s'", access_str); +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 03c4165095..ca0eddb38d 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -1322,19 +1322,19 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) { + return fd; + } + +-static int bus_kernel_translate_access(BusNamePolicyAccess access) { ++static int bus_kernel_translate_access(BusPolicyAccess access) { + assert(access >= 0); +- assert(access < _BUSNAME_POLICY_ACCESS_MAX); ++ assert(access < _BUS_POLICY_ACCESS_MAX); + + switch (access) { + +- case BUSNAME_POLICY_ACCESS_SEE: ++ case BUS_POLICY_ACCESS_SEE: + return KDBUS_POLICY_SEE; + +- case BUSNAME_POLICY_ACCESS_TALK: ++ case BUS_POLICY_ACCESS_TALK: + return KDBUS_POLICY_TALK; + +- case BUSNAME_POLICY_ACCESS_OWN: ++ case BUS_POLICY_ACCESS_OWN: + return KDBUS_POLICY_OWN; + + default: +@@ -1414,7 +1414,7 @@ int bus_kernel_make_starter( + bool activating, + bool accept_fd, + BusNamePolicy *policy, +- BusNamePolicyAccess world_policy) { ++ BusPolicyAccess world_policy) { + + struct kdbus_cmd_hello *hello; + struct kdbus_item *n; +diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h +index 448dd3a797..182f953d47 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.h ++++ b/src/libsystemd/sd-bus/bus-kernel.h +@@ -66,7 +66,7 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call + int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority); + + int bus_kernel_open_bus_fd(const char *bus, char **path); +-int bus_kernel_make_starter(int fd, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy, BusNamePolicyAccess world_policy); ++int bus_kernel_make_starter(int fd, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy, BusPolicyAccess world_policy); + + int bus_kernel_create_bus(const char *name, bool world, char **s); + int bus_kernel_create_domain(const char *name, char **s); +diff --git a/src/test/test-tables.c b/src/test/test-tables.c +index 58fe4433b7..907958e461 100644 +--- a/src/test/test-tables.c ++++ b/src/test/test-tables.c +@@ -55,7 +55,7 @@ int main(int argc, char **argv) { + test_table(architecture, ARCHITECTURE); + test_table(automount_result, AUTOMOUNT_RESULT); + test_table(automount_state, AUTOMOUNT_STATE); +- test_table(busname_policy_access, BUSNAME_POLICY_ACCESS); ++ test_table(bus_policy_access, BUS_POLICY_ACCESS); + test_table(busname_result, BUSNAME_RESULT); + test_table(busname_state, BUSNAME_STATE); + test_table(cgroup_device_policy, CGROUP_DEVICE_POLICY); diff --git a/0181-bus-add-kdbus-endpoint-types.patch b/0181-bus-add-kdbus-endpoint-types.patch new file mode 100644 index 0000000..6d1dc53 --- /dev/null +++ b/0181-bus-add-kdbus-endpoint-types.patch @@ -0,0 +1,210 @@ +From bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Mon, 18 Aug 2014 19:55:32 +0200 +Subject: [PATCH] bus: add kdbus endpoint types + +Add types to describe endpoints and associated policy entries, +and add a BusEndpoint instace to ExecContext. +--- + Makefile.am | 2 ++ + src/core/bus-endpoint.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ + src/core/bus-endpoint.h | 42 +++++++++++++++++++++++ + src/core/execute.c | 3 ++ + src/core/execute.h | 4 +++ + 5 files changed, 141 insertions(+) + create mode 100644 src/core/bus-endpoint.c + create mode 100644 src/core/bus-endpoint.h + +diff --git a/Makefile.am b/Makefile.am +index 68a78963c1..35c877fe2a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1028,6 +1028,8 @@ libsystemd_core_la_SOURCES = \ + src/core/busname.h \ + src/core/bus-common.c \ + src/core/bus-common.h \ ++ src/core/bus-endpoint.c \ ++ src/core/bus-endpoint.h \ + src/core/target.c \ + src/core/target.h \ + src/core/snapshot.c \ +diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c +new file mode 100644 +index 0000000000..8d11974db4 +--- /dev/null ++++ b/src/core/bus-endpoint.c +@@ -0,0 +1,90 @@ ++/*** ++ 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 "bus-endpoint.h" ++ ++int bus_endpoint_new(BusEndpoint **ep) ++{ ++ assert(ep); ++ ++ *ep = new0(BusEndpoint, 1); ++ if (!*ep) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access) ++{ ++ _cleanup_free_ BusEndpointPolicy *po; ++ _cleanup_free_ char *key; ++ int r; ++ ++ assert(ep); ++ assert(name); ++ assert(access > _BUS_POLICY_ACCESS_INVALID && access < _BUS_POLICY_ACCESS_MAX); ++ ++ /* check if we already have this name in the policy list. If we do, see if the new access level ++ * is higher than the exising one, and upgrade the entry in that case. Otherwise, do nothing. ++ */ ++ ++ if (ep->policy_hash) { ++ po = hashmap_get(ep->policy_hash, name); ++ if (po) { ++ if (po->access < access) ++ po->access = access; ++ ++ return 0; ++ } ++ } else { ++ ep->policy_hash = hashmap_new(string_hash_func, string_compare_func); ++ if (!ep->policy_hash) ++ return -ENOMEM; ++ } ++ ++ po = new0(BusEndpointPolicy, 1); ++ if (!po) ++ return -ENOMEM; ++ ++ key = strdup(name); ++ if (!key) ++ return -ENOMEM; ++ ++ po->name = key; ++ po->access = access; ++ ++ r = hashmap_put(ep->policy_hash, key, po); ++ if (r < 0) ++ return r; ++ ++ po = NULL; ++ key = NULL; ++ return 0; ++} ++ ++void bus_endpoint_free(BusEndpoint *endpoint) ++{ ++ if (!endpoint) ++ return; ++ ++ hashmap_free_free_free(endpoint->policy_hash); ++ free(endpoint); ++} +diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h +new file mode 100644 +index 0000000000..2c5415f34e +--- /dev/null ++++ b/src/core/bus-endpoint.h +@@ -0,0 +1,42 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++#pragma once ++ ++/*** ++ 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 . ++***/ ++ ++typedef struct BusEndpoint BusEndpoint; ++typedef struct BusEndpointPolicy BusEndpointPolicy; ++ ++#include "bus-common.h" ++#include "hashmap.h" ++ ++struct BusEndpointPolicy { ++ char *name; ++ BusPolicyAccess access; ++}; ++ ++struct BusEndpoint { ++ Hashmap *policy_hash; ++}; ++ ++int bus_endpoint_new(BusEndpoint **ep); ++void bus_endpoint_free(BusEndpoint *endpoint); ++ ++int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access); +diff --git a/src/core/execute.c b/src/core/execute.c +index 0a5914759f..a88e1b1953 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1908,6 +1908,9 @@ void exec_context_done(ExecContext *c) { + + strv_free(c->runtime_directory); + c->runtime_directory = NULL; ++ ++ bus_endpoint_free(c->bus_endpoint); ++ c->bus_endpoint = NULL; + } + + int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) { +diff --git a/src/core/execute.h b/src/core/execute.h +index f31f0c9f27..e3cebfd72c 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -41,6 +41,7 @@ typedef struct ExecParameters ExecParameters; + #include "fdset.h" + #include "missing.h" + #include "namespace.h" ++#include "bus-endpoint.h" + + typedef enum ExecInput { + EXEC_INPUT_NULL, +@@ -188,6 +189,9 @@ struct ExecContext { + bool ioprio_set:1; + bool cpu_sched_set:1; + bool no_new_privileges_set:1; ++ ++ /* custom dbus enpoint */ ++ BusEndpoint *bus_endpoint; + }; + + #include "cgroup.h" diff --git a/0182-bus-add-code-to-create-custom-endpoints-and-set-thei.patch b/0182-bus-add-code-to-create-custom-endpoints-and-set-thei.patch new file mode 100644 index 0000000..b691fed --- /dev/null +++ b/0182-bus-add-code-to-create-custom-endpoints-and-set-thei.patch @@ -0,0 +1,147 @@ +From e7d718afdb28b1049d382604e5e7bf1d213a8291 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Mon, 18 Aug 2014 19:58:42 +0200 +Subject: [PATCH] bus: add code to create custom endpoints and set their policy + +Custom endpoints are alternative connection points to a bus, allowing +specific policy to be uploaded. + +Add two functions to bus-kernel. One to create such endpoints, and another +one for setting a policy for them. +--- + src/libsystemd/sd-bus/bus-kernel.c | 90 ++++++++++++++++++++++++++++++++++++++ + src/libsystemd/sd-bus/bus-kernel.h | 4 ++ + 2 files changed, 94 insertions(+) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index ca0eddb38d..505f335e07 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -25,6 +25,7 @@ + + #include + #include ++#include + #include + #include + +@@ -1408,6 +1409,95 @@ int bus_kernel_open_bus_fd(const char *bus, char **path) { + return fd; + } + ++int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **ep_path) { ++ _cleanup_free_ char *path; ++ struct kdbus_cmd_make *make; ++ struct kdbus_item *n; ++ size_t size; ++ int fd; ++ ++ fd = bus_kernel_open_bus_fd(bus_name, &path); ++ if (fd < 0) ++ return fd; ++ ++ size = ALIGN8(offsetof(struct kdbus_cmd_make, items)); ++ size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(ep_name) + 1); ++ ++ make = alloca0(size); ++ make->size = size; ++ make->flags = KDBUS_MAKE_ACCESS_WORLD; ++ ++ n = make->items; ++ ++ n->type = KDBUS_ITEM_MAKE_NAME; ++ n->size = offsetof(struct kdbus_item, str) + strlen(ep_name) + 1; ++ strcpy(n->str, ep_name); ++ ++ if (ioctl(fd, KDBUS_CMD_EP_MAKE, make) < 0) { ++ safe_close(fd); ++ return -errno; ++ } ++ ++ /* The higher 32bit of the flags field are considered ++ * 'incompatible flags'. Refuse them all for now. */ ++ if (make->flags > 0xFFFFFFFFULL) { ++ safe_close(fd); ++ return -ENOTSUP; ++ } ++ ++ if (ep_path) { ++ asprintf(ep_path, "%s/%s", dirname(path), ep_name); ++ if (!*ep_path) ++ return -ENOMEM; ++ } ++ ++ return fd; ++} ++ ++int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) { ++ ++ struct kdbus_cmd_update *update; ++ struct kdbus_item *n; ++ BusEndpointPolicy *po; ++ Iterator i; ++ size_t size; ++ int r; ++ ++ size = ALIGN8(offsetof(struct kdbus_cmd_update, items)); ++ ++ HASHMAP_FOREACH(po, ep->policy_hash, i) { ++ size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(po->name) + 1); ++ size += ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access)); ++ } ++ ++ update = alloca0(size); ++ update->size = size; ++ ++ n = update->items; ++ ++ HASHMAP_FOREACH(po, ep->policy_hash, i) { ++ n->type = KDBUS_ITEM_NAME; ++ n->size = offsetof(struct kdbus_item, str) + strlen(po->name) + 1; ++ strcpy(n->str, po->name); ++ n = KDBUS_ITEM_NEXT(n); ++ ++ n->type = KDBUS_ITEM_POLICY_ACCESS; ++ n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access); ++ ++ n->policy_access.type = KDBUS_POLICY_ACCESS_USER; ++ n->policy_access.access = bus_kernel_translate_access(po->access); ++ n->policy_access.id = uid; ++ ++ n = KDBUS_ITEM_NEXT(n); ++ } ++ ++ r = ioctl(fd, KDBUS_CMD_EP_UPDATE, update); ++ if (r < 0) ++ return -errno; ++ ++ return 0; ++} ++ + int bus_kernel_make_starter( + int fd, + const char *name, +diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h +index 182f953d47..f1d832a764 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.h ++++ b/src/libsystemd/sd-bus/bus-kernel.h +@@ -24,6 +24,7 @@ + #include + + #include "busname.h" ++#include "bus-endpoint.h" + #include "sd-bus.h" + + #define KDBUS_ITEM_NEXT(item) \ +@@ -69,8 +70,11 @@ int bus_kernel_open_bus_fd(const char *bus, char **path); + int bus_kernel_make_starter(int fd, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy, BusPolicyAccess world_policy); + + int bus_kernel_create_bus(const char *name, bool world, char **s); ++int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **path); + int bus_kernel_create_domain(const char *name, char **s); + ++int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep); ++ + int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated); + void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated); + diff --git a/0183-bus-parse-BusPolicy-directive-in-service-files.patch b/0183-bus-parse-BusPolicy-directive-in-service-files.patch new file mode 100644 index 0000000..9e5385f --- /dev/null +++ b/0183-bus-parse-BusPolicy-directive-in-service-files.patch @@ -0,0 +1,159 @@ +From 501996231293506a85bf4d610938a655ddc8cb92 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Mon, 18 Aug 2014 22:42:28 +0200 +Subject: [PATCH] bus: parse BusPolicy directive in service files + +Add a new directive called BusPolicy to define custom endpoint policies. If +one such directive is given, an endpoint object in the service's ExecContext is +created and the given policy is added to it. +--- + man/systemd.service.xml | 40 +++++++++++++++++++++++++ + src/core/load-fragment-gperf.gperf.m4 | 3 ++ + src/core/load-fragment.c | 56 +++++++++++++++++++++++++++++++++++ + src/core/load-fragment.h | 1 + + 4 files changed, 100 insertions(+) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index c84a5254b3..a82dfb2c86 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -308,6 +308,46 @@ + + + ++ BusPolicy= ++ ++ If specfied, a custom kdbus ++ endpoint will be created and installed as the ++ default bus node for the service. Such a custom ++ endpoint can hold an own set of policy rules ++ that are enforced on top of the bus-wide ones. ++ The custom endpoint is named after the service ++ it was created for, and its node will be ++ bind-mounted over the default bus node ++ location, so the service can only access the ++ bus through its own endpoint. Note that custom ++ bus endpoints default to a 'deny all' policy. ++ Hence, if at least one ++ BusPolicy= directive is ++ given, you have to make sure to add explicit ++ rules for everything the service should be able ++ to do. ++ The value of this directive is comprised ++ of two parts; the bus name, and a verb to ++ specify to granted access, which is one of ++ , ++ or ++ . ++ implies ++ , and ++ implies both and ++ . ++ If multiple access levels are specified for the ++ same bus name, the most powerful one takes ++ effect. ++ ++ Examples: ++ BusPolicy=org.freedesktop.systemd1 talk ++ BusPolicy=org.foo.bar see ++ This option is only available on kdbus enabled systems. ++ ++ ++ ++ + ExecStart= + Commands with their + arguments that are executed when this +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 24aa80d9ea..e764d68ce4 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -205,6 +205,9 @@ Service.NonBlocking, config_parse_bool, 0, + Service.BusName, config_parse_unit_string_printf, 0, offsetof(Service, bus_name) + Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) + Service.Sockets, config_parse_service_sockets, 0, 0 ++m4_ifdef(`ENABLE_KDBUS', ++`Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context)', ++`Service.BusPolicy, config_parse_warn_compat, 0, 0') + EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl + CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl + KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index b4da6a550e..2f3acd7cbe 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1752,6 +1752,62 @@ int config_parse_bus_policy( + return 0; + } + ++int config_parse_bus_endpoint_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) { ++ ++ _cleanup_free_ char *name = NULL; ++ BusPolicyAccess access; ++ ExecContext *c = data; ++ char *access_str; ++ int r; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ name = strdup(rvalue); ++ if (!name) ++ return log_oom(); ++ ++ access_str = strpbrk(name, WHITESPACE); ++ if (!access_str) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, ++ "Invalid endpoint policy value '%s'", rvalue); ++ return 0; ++ } ++ ++ *access_str = '\0'; ++ access_str++; ++ access_str += strspn(access_str, WHITESPACE); ++ ++ access = bus_policy_access_from_string(access_str); ++ if (access <= _BUS_POLICY_ACCESS_INVALID || ++ access >= _BUS_POLICY_ACCESS_MAX) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, ++ "Invalid endpoint policy access type '%s'", access_str); ++ return 0; ++ } ++ ++ if (!c->bus_endpoint) { ++ r = bus_endpoint_new(&c->bus_endpoint); ++ ++ if (r < 0) ++ return r; ++ } ++ ++ return bus_endpoint_add_policy(c->bus_endpoint, name, access); ++} ++ + int config_parse_unit_env_file(const char *unit, + const char *filename, + unsigned line, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 9a1d7c5aac..65100c9bd7 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -67,6 +67,7 @@ int config_parse_service_sockets(const char *unit, const char *filename, unsigne + int config_parse_busname_service(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_bus_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_bus_policy_world(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_bus_endpoint_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_unit_env_file(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_ip_tos(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_condition_path(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/0184-namespace-add-support-for-custom-kdbus-endpoint.patch b/0184-namespace-add-support-for-custom-kdbus-endpoint.patch new file mode 100644 index 0000000..261785a --- /dev/null +++ b/0184-namespace-add-support-for-custom-kdbus-endpoint.patch @@ -0,0 +1,192 @@ +From a610cc4f18c24a007e5a2cac21b2ecbd81e5f3c3 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 22 Aug 2014 18:55:21 +0200 +Subject: [PATCH] namespace: add support for custom kdbus endpoint + +If a path to a previously created custom kdbus endpoint is passed in, +bind-mount a new devtmpfs that contains a 'bus' node, which in turn in +bind-mounted with the custom endpoint. This tmpfs then mounted over the +kdbus subtree that refers to the current bus. + +This way, we can fake the bus node in order to lock down services with +a kdbus custom endpoint policy. +--- + src/core/execute.c | 1 + + src/core/namespace.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++- + src/core/namespace.h | 1 + + src/test/test-ns.c | 1 + + 4 files changed, 93 insertions(+), 1 deletion(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index a88e1b1953..96cabe6d99 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1523,6 +1523,7 @@ static int exec_child(ExecCommand *command, + context->inaccessible_dirs, + tmp, + var, ++ NULL, + context->private_devices, + context->protect_home, + context->protect_system, +diff --git a/src/core/namespace.c b/src/core/namespace.c +index fe95377871..eaaebdd644 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -51,6 +51,7 @@ typedef enum MountMode { + PRIVATE_TMP, + PRIVATE_VAR_TMP, + PRIVATE_DEV, ++ PRIVATE_BUS_ENDPOINT, + READWRITE + } MountMode; + +@@ -272,6 +273,84 @@ fail: + return r; + } + ++static int mount_kdbus(BindMount *m) { ++ ++ char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX"; ++ _cleanup_free_ char *basepath = NULL; ++ _cleanup_umask_ mode_t u; ++ char *busnode, *root; ++ struct stat st; ++ int r; ++ ++ assert(m); ++ ++ u = umask(0000); ++ ++ if (!mkdtemp(temporary_mount)) { ++ log_error("Failed create temp dir: %m"); ++ return -errno; ++ } ++ ++ root = strappenda(temporary_mount, "/kdbus"); ++ mkdir(root, 0755); ++ if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) { ++ r = -errno; ++ goto fail; ++ } ++ ++ /* create a new /dev/null dev node copy so we have some fodder to ++ * bind-mount the custom endpoint over. */ ++ if (stat("/dev/null", &st) < 0) { ++ log_error("Failed to stat /dev/null: %m"); ++ r = -errno; ++ goto fail; ++ } ++ ++ busnode = strappenda(root, "/bus"); ++ if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) { ++ log_error("mknod() for %s failed: %m", busnode); ++ r = -errno; ++ goto fail; ++ } ++ ++ r = mount(m->path, busnode, "bind", MS_BIND, NULL); ++ if (r < 0) { ++ log_error("bind mount of %s failed: %m", m->path); ++ r = -errno; ++ goto fail; ++ } ++ ++ basepath = dirname_malloc(m->path); ++ if (!basepath) { ++ r = -ENOMEM; ++ goto fail; ++ } ++ ++ if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) { ++ log_error("bind mount of %s failed: %m", basepath); ++ r = -errno; ++ goto fail; ++ } ++ ++ rmdir(temporary_mount); ++ return 0; ++ ++fail: ++ if (busnode) { ++ umount(busnode); ++ unlink(busnode); ++ } ++ ++ if (root) { ++ umount(root); ++ rmdir(root); ++ } ++ ++ rmdir(temporary_mount); ++ ++ return r; ++} ++ + static int apply_mount( + BindMount *m, + const char *tmp_dir, +@@ -311,6 +390,9 @@ static int apply_mount( + case PRIVATE_DEV: + return mount_dev(m); + ++ case PRIVATE_BUS_ENDPOINT: ++ return mount_kdbus(m); ++ + default: + assert_not_reached("Unknown mode"); + } +@@ -350,6 +432,7 @@ int setup_namespace( + char** inaccessible_dirs, + char* tmp_dir, + char* var_tmp_dir, ++ char* bus_endpoint_path, + bool private_dev, + ProtectHome protect_home, + ProtectSystem protect_system, +@@ -365,7 +448,7 @@ int setup_namespace( + if (unshare(CLONE_NEWNS) < 0) + return -errno; + +- n = !!tmp_dir + !!var_tmp_dir + ++ n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path + + strv_length(read_write_dirs) + + strv_length(read_only_dirs) + + strv_length(inaccessible_dirs) + +@@ -406,6 +489,12 @@ int setup_namespace( + m++; + } + ++ if (bus_endpoint_path) { ++ m->path = 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); + if (r < 0) +diff --git a/src/core/namespace.h b/src/core/namespace.h +index 9343fe3264..9cd420e958 100644 +--- a/src/core/namespace.h ++++ b/src/core/namespace.h +@@ -46,6 +46,7 @@ int setup_namespace(char **read_write_dirs, + char **inaccessible_dirs, + char *tmp_dir, + char *var_tmp_dir, ++ char *endpoint_path, + bool private_dev, + ProtectHome protect_home, + ProtectSystem protect_system, +diff --git a/src/test/test-ns.c b/src/test/test-ns.c +index acad725899..7714e49ad9 100644 +--- a/src/test/test-ns.c ++++ b/src/test/test-ns.c +@@ -59,6 +59,7 @@ int main(int argc, char *argv[]) { + (char **) inaccessible, + tmp_dir, + var_tmp_dir, ++ NULL, + true, + PROTECT_HOME_NO, + PROTECT_SYSTEM_NO, diff --git a/0185-exit-status-add-new-exit-code-for-custom-endpoint-er.patch b/0185-exit-status-add-new-exit-code-for-custom-endpoint-er.patch new file mode 100644 index 0000000..c02aa6c --- /dev/null +++ b/0185-exit-status-add-new-exit-code-for-custom-endpoint-er.patch @@ -0,0 +1,36 @@ +From 060e088e94852cbe166592429c330e3997c21c4c Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 5 Sep 2014 17:24:27 +0200 +Subject: [PATCH] exit-status: add new exit code for custom endpoint errors + +--- + src/shared/exit-status.c | 3 +++ + src/shared/exit-status.h | 1 + + 2 files changed, 4 insertions(+) + +diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c +index f3434f7ccc..b036ded1f4 100644 +--- a/src/shared/exit-status.c ++++ b/src/shared/exit-status.c +@@ -148,6 +148,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { + + case EXIT_MAKE_STARTER: + return "MAKE_STARTER"; ++ ++ case EXIT_BUS_ENDPOINT: ++ return "EXIT_BUS_ENDPOINT"; + } + } + +diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h +index 9d27c01658..f719580426 100644 +--- a/src/shared/exit-status.h ++++ b/src/shared/exit-status.h +@@ -77,6 +77,7 @@ typedef enum ExitStatus { + EXIT_RUNTIME_DIRECTORY, + EXIT_MAKE_STARTER, + EXIT_CHOWN, ++ EXIT_BUS_ENDPOINT, + } ExitStatus; + + typedef enum ExitStatusLevel { diff --git a/0186-service-hook-up-custom-endpoint-logic.patch b/0186-service-hook-up-custom-endpoint-logic.patch new file mode 100644 index 0000000..628be82 --- /dev/null +++ b/0186-service-hook-up-custom-endpoint-logic.patch @@ -0,0 +1,233 @@ +From e44da745d19b9e02e67e32ea82c3bad86175120c Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 22 Aug 2014 19:02:03 +0200 +Subject: [PATCH] service: hook up custom endpoint logic + +If BusPolicy= was passed, the parser function will have created +an ExecContext->bus_endpoint object, along with policy information. + +In that case, create a kdbus endpoint, and pass its path name to the +namespace logic, to it will be mounted over the actual 'bus' node. + +At endpoint creation time, no policy is updloaded. That is done after +fork(), through a separate call. This is necessary because we don't +know the real uid of the process earlier than that. +--- + src/core/execute.c | 24 +++++++++++++++++++++--- + src/core/execute.h | 2 ++ + src/core/service.c | 39 ++++++++++++++++++++++++++++++++++++++- + src/core/service.h | 2 ++ + 4 files changed, 63 insertions(+), 4 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 96cabe6d99..2b16b36c19 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -83,6 +83,7 @@ + #include "af-list.h" + #include "mkdir.h" + #include "apparmor-util.h" ++#include "bus-kernel.h" + + #ifdef HAVE_SECCOMP + #include "seccomp-util.h" +@@ -1236,7 +1237,7 @@ static int exec_child(ExecCommand *command, + _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; + const char *username = NULL, *home = NULL, *shell = NULL; + unsigned n_dont_close = 0; +- int dont_close[n_fds + 3]; ++ int dont_close[n_fds + 4]; + uid_t uid = (uid_t) -1; + gid_t gid = (gid_t) -1; + int i, err; +@@ -1279,6 +1280,8 @@ static int exec_child(ExecCommand *command, + memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); + n_dont_close += n_fds; + } ++ if (params->bus_endpoint_fd >= 0) ++ dont_close[n_dont_close++] = params->bus_endpoint_fd; + if (runtime) { + if (runtime->netns_storage_socket[0] >= 0) + dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; +@@ -1428,6 +1431,18 @@ static int exec_child(ExecCommand *command, + } + } + ++#ifdef ENABLE_KDBUS ++ if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) { ++ uid_t ep_uid = (uid == (uid_t) -1) ? 0 : uid; ++ ++ err = bus_kernel_set_endpoint_policy(params->bus_endpoint_fd, ep_uid, context->bus_endpoint); ++ if (err < 0) { ++ *error = EXIT_BUS_ENDPOINT; ++ return err; ++ } ++ } ++#endif ++ + #ifdef HAVE_PAM + if (params->cgroup_path && context->user && context->pam_name) { + err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid); +@@ -1498,6 +1513,7 @@ static int exec_child(ExecCommand *command, + !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) { +@@ -1523,7 +1539,7 @@ static int exec_child(ExecCommand *command, + context->inaccessible_dirs, + tmp, + var, +- NULL, ++ params->bus_endpoint_path, + context->private_devices, + context->protect_home, + context->protect_system, +@@ -1564,7 +1580,9 @@ static int exec_child(ExecCommand *command, + /* We repeat the fd closing here, to make sure that + * nothing is leaked from the PAM modules. Note that + * we are more aggressive this time since socket_fd +- * and the netns fds we don#t need anymore. */ ++ * and the netns fds we don't need anymore. The custom ++ * endpoint fd was needed to upload the policy and can ++ * now be closed as well. */ + err = close_all_fds(fds, n_fds); + if (err >= 0) + err = shift_fds(fds, n_fds); +diff --git a/src/core/execute.h b/src/core/execute.h +index e3cebfd72c..9c1f249cd4 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -210,6 +210,8 @@ struct ExecParameters { + const char *unit_id; + usec_t watchdog_usec; + int *idle_pipe; ++ char *bus_endpoint_path; ++ int bus_endpoint_fd; + }; + + int exec_spawn(ExecCommand *command, +diff --git a/src/core/service.c b/src/core/service.c +index f3775f24c4..3f6595c5c8 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -45,6 +45,7 @@ + #include "fileio.h" + #include "bus-error.h" + #include "bus-util.h" ++#include "bus-kernel.h" + + static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = UNIT_INACTIVE, +@@ -102,6 +103,7 @@ static void service_init(Unit *u) { + s->restart_usec = u->manager->default_restart_usec; + s->type = _SERVICE_TYPE_INVALID; + s->socket_fd = -1; ++ s->bus_endpoint_fd = -1; + s->guess_main_pid = true; + + RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst); +@@ -273,6 +275,7 @@ static void service_done(Unit *u) { + s->bus_name = NULL; + } + ++ s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd); + service_close_socket_fd(s); + service_connection_unref(s); + +@@ -889,6 +892,7 @@ static int service_spawn( + int *fds = NULL; + _cleanup_free_ int *fdsbuf = NULL; + unsigned n_fds = 0, n_env = 0; ++ _cleanup_free_ char *bus_endpoint_path = NULL; + _cleanup_strv_free_ char + **argv = NULL, **final_env = NULL, **our_env = NULL; + const char *path; +@@ -896,6 +900,7 @@ static int service_spawn( + .apply_permissions = apply_permissions, + .apply_chroot = apply_chroot, + .apply_tty_stdin = apply_tty_stdin, ++ .bus_endpoint_fd = -1, + }; + + assert(s); +@@ -972,6 +977,20 @@ static int service_spawn( + } else + path = UNIT(s)->cgroup_path; + ++#ifdef ENABLE_KDBUS ++ if (s->exec_context.bus_endpoint) { ++ r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user", ++ UNIT(s)->id, &bus_endpoint_path); ++ if (r < 0) ++ goto fail; ++ ++ /* Pass the fd to the exec_params so that the child process can upload the policy. ++ * Keep a reference to the fd in the service, so the endpoint is kept alive as long ++ * as the service is running. */ ++ exec_params.bus_endpoint_fd = s->bus_endpoint_fd = r; ++ } ++#endif ++ + exec_params.argv = argv; + exec_params.fds = fds; + exec_params.n_fds = n_fds; +@@ -982,6 +1001,7 @@ static int service_spawn( + exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); + exec_params.unit_id = UNIT(s)->id; + exec_params.watchdog_usec = s->watchdog_usec; ++ exec_params.bus_endpoint_path = bus_endpoint_path; + if (s->type == SERVICE_IDLE) + exec_params.idle_pipe = UNIT(s)->manager->idle_pipe; + +@@ -1770,6 +1790,15 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + unit_serialize_item_format(u, f, "socket-fd", "%i", copy); + } + ++ if (s->bus_endpoint_fd >= 0) { ++ int copy; ++ ++ if ((copy = fdset_put_dup(fds, s->bus_endpoint_fd)) < 0) ++ return copy; ++ ++ unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy); ++ } ++ + if (s->main_exec_status.pid > 0) { + unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT, + s->main_exec_status.pid); +@@ -1879,10 +1908,18 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse socket-fd value %s", value); + else { +- + asynchronous_close(s->socket_fd); + s->socket_fd = fdset_remove(fds, fd); + } ++ } else if (streq(key, "endpoint-fd")) { ++ int fd; ++ ++ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) ++ log_debug_unit(u->id, "Failed to parse endpoint-fd value %s", value); ++ else { ++ safe_close(s->bus_endpoint_fd); ++ s->bus_endpoint_fd = fdset_remove(fds, fd); ++ } + } else if (streq(key, "main-exec-status-pid")) { + pid_t pid; + +diff --git a/src/core/service.h b/src/core/service.h +index 5bcfd14339..ad0b3b381e 100644 +--- a/src/core/service.h ++++ b/src/core/service.h +@@ -162,6 +162,8 @@ struct Service { + pid_t main_pid, control_pid; + int socket_fd; + ++ int bus_endpoint_fd; ++ + bool permissions_start_only; + bool root_directory_start_only; + bool remain_after_exit; diff --git a/0187-networkd-tuntap-return-correct-error-when-dev-net-tu.patch b/0187-networkd-tuntap-return-correct-error-when-dev-net-tu.patch new file mode 100644 index 0000000..aa7cbb9 --- /dev/null +++ b/0187-networkd-tuntap-return-correct-error-when-dev-net-tu.patch @@ -0,0 +1,44 @@ +From 6f44acfb48d4b58565d4c14714d082997389afd3 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 6 Sep 2014 22:06:58 +0200 +Subject: [PATCH] networkd: tuntap - return correct error when /dev/net/tun + cannot be opened + +--- + src/network/networkd-netdev-tuntap.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c +index eef8747210..eaf5df4971 100644 +--- a/src/network/networkd-netdev-tuntap.c ++++ b/src/network/networkd-netdev-tuntap.c +@@ -63,17 +63,15 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) { + const char *group; + uid_t uid; + gid_t gid; +- int r = 0; ++ int r; + + assert(netdev); + assert(ifr); + + fd = open(TUN_DEV, O_RDWR); + if (fd < 0) { +- log_error_netdev(netdev, +- "Failed to open tun dev: %s", +- strerror(-r)); +- return r; ++ log_error_netdev(netdev, "Failed to open tun dev: %m"); ++ return -errno; + } + + r = ioctl(fd, TUNSETIFF, ifr); +@@ -139,7 +137,7 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) { + return r; + } + +- return r; ++ return 0; + } + + static int netdev_create_tuntap(NetDev *netdev) { diff --git a/0188-networkd-netdev-failing-to-create-a-netdev-is-not-fa.patch b/0188-networkd-netdev-failing-to-create-a-netdev-is-not-fa.patch new file mode 100644 index 0000000..7e7bf3e --- /dev/null +++ b/0188-networkd-netdev-failing-to-create-a-netdev-is-not-fa.patch @@ -0,0 +1,23 @@ +From 1eb808756e3e4cc724ba17725a8513e562551c21 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 6 Sep 2014 22:16:20 +0200 +Subject: [PATCH] networkd: netdev - failing to create a netdev is not fatal, + just fail that netdev + +--- + 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 1a436f75df..fd1f51ec56 100644 +--- a/src/network/networkd-netdev.c ++++ b/src/network/networkd-netdev.c +@@ -721,7 +721,7 @@ static int netdev_load_one(Manager *manager, const char *filename) { + case NETDEV_CREATE_INDEPENDENT: + r = netdev_create(netdev, NULL, NULL); + if (r < 0) +- return r; ++ return 0; + + break; + default: diff --git a/0189-units-networkd-order-after-udev.patch b/0189-units-networkd-order-after-udev.patch new file mode 100644 index 0000000..f8bc950 --- /dev/null +++ b/0189-units-networkd-order-after-udev.patch @@ -0,0 +1,26 @@ +From 4bd5ace3e78ec0ca4c174bc875e3d9f6e1ae7405 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 6 Sep 2014 22:37:31 +0200 +Subject: [PATCH] units: networkd - order after udev + +This way we are sure that /dev/net/tun has been given the right permissions before we try to connect to it. +Ideally, we should create tun/tap devices over netlink, and then this whole issue would go away. +--- + units/systemd-networkd.service.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in +index f33c65e6ff..fe92da2123 100644 +--- a/units/systemd-networkd.service.in ++++ b/units/systemd-networkd.service.in +@@ -10,7 +10,9 @@ Description=Network Service + Documentation=man:systemd-networkd.service(8) + ConditionCapability=CAP_NET_ADMIN + DefaultDependencies=no +-After=dbus.service network-pre.target systemd-sysusers.service ++# dbus.service can be dropped once on kdbus, and systemd-udevd.service can be ++# dropped once tuntap is moved to netlink ++After=systemd-udevd.service dbus.service network-pre.target systemd-sysusers.service + Before=network.target multi-user.target shutdown.target + Conflicts=shutdown.target + Wants=network.target diff --git a/0190-networkd-add-preferred-source-to-dhcp4-gateway-route.patch b/0190-networkd-add-preferred-source-to-dhcp4-gateway-route.patch new file mode 100644 index 0000000..49ebb80 --- /dev/null +++ b/0190-networkd-add-preferred-source-to-dhcp4-gateway-route.patch @@ -0,0 +1,106 @@ +From 46b0c76e2c355c0d0cc4792abb98cde07b28bc53 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Fri, 5 Sep 2014 11:56:02 +0200 +Subject: [PATCH] networkd: add preferred source to dhcp4 gateway route + +This makes DHCPv4 and IPv4LL coexist peacefully. + +[tomegun: apply to both the dhcp routes, use in_addr_is_null() rather than a +separate variable to indicate when prefsrc should be applied] +--- + src/network/networkd-dhcp4.c | 11 +++++++++++ + src/network/networkd-route.c | 22 ++++++++++++++++++++++ + src/network/networkd.h | 1 + + 3 files changed, 34 insertions(+) + +diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c +index 5e4ff2b80b..b87fa73082 100644 +--- a/src/network/networkd-dhcp4.c ++++ b/src/network/networkd-dhcp4.c +@@ -67,9 +67,18 @@ static int link_set_dhcp_routes(Link *link) { + return r; + } + if (r >= 0) { ++ struct in_addr address; + _cleanup_route_free_ Route *route = NULL; + _cleanup_route_free_ Route *route_gw = NULL; + ++ r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); ++ if (r < 0) { ++ log_warning_link(link, ++ "DHCP error: could not get address: %s", ++ strerror(-r)); ++ return r; ++ } ++ + r = route_new_dynamic(&route, RTPROT_DHCP); + if (r < 0) { + log_error_link(link, +@@ -92,6 +101,7 @@ static int link_set_dhcp_routes(Link *link) { + route_gw->family = AF_INET; + route_gw->dst_addr.in = gateway; + route_gw->dst_prefixlen = 32; ++ route_gw->prefsrc_addr.in = address; + route_gw->scope = RT_SCOPE_LINK; + route_gw->metrics = DHCP_ROUTE_METRIC; + +@@ -107,6 +117,7 @@ static int link_set_dhcp_routes(Link *link) { + + route->family = AF_INET; + route->in_addr.in = gateway; ++ route->prefsrc_addr.in = address; + route->metrics = DHCP_ROUTE_METRIC; + + r = route_configure(route, link, &dhcp4_route_handler); +diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c +index aead4fbb9e..10d8cd902a 100644 +--- a/src/network/networkd-route.c ++++ b/src/network/networkd-route.c +@@ -144,6 +144,17 @@ int route_drop(Route *route, Link *link, + } + } + ++ if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { ++ if (route->family == AF_INET) ++ r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); ++ else if (route->family == AF_INET6) ++ r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); ++ if (r < 0) { ++ log_error("Could not append RTA_PREFSRC attribute: %s", strerror(-r)); ++ return r; ++ } ++ } ++ + r = sd_rtnl_message_route_set_scope(req, route->scope); + if (r < 0) { + log_error("Could not set scope: %s", strerror(-r)); +@@ -218,6 +229,17 @@ int route_configure(Route *route, Link *link, + } + } + ++ if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { ++ if (route->family == AF_INET) ++ r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); ++ else if (route->family == AF_INET6) ++ r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); ++ if (r < 0) { ++ log_error("Could not append RTA_PREFSRC attribute: %s", strerror(-r)); ++ return r; ++ } ++ } ++ + r = sd_rtnl_message_route_set_scope(req, route->scope); + if (r < 0) { + log_error("Could not set scope: %s", strerror(-r)); +diff --git a/src/network/networkd.h b/src/network/networkd.h +index ab5df1aa3c..c6e6b22c38 100644 +--- a/src/network/networkd.h ++++ b/src/network/networkd.h +@@ -150,6 +150,7 @@ struct Route { + + union in_addr_union in_addr; + union in_addr_union dst_addr; ++ union in_addr_union prefsrc_addr; + + LIST_FIELDS(Route, routes); + }; diff --git a/0191-TODO.patch b/0191-TODO.patch new file mode 100644 index 0000000..7dedb99 --- /dev/null +++ b/0191-TODO.patch @@ -0,0 +1,23 @@ +From b70c73fcf1885b717b464353edecaf650a1e520a Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 8 Sep 2014 13:12:06 +0200 +Subject: [PATCH] TODO + +--- + TODO | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/TODO b/TODO +index 7029769770..f036430c43 100644 +--- a/TODO ++++ b/TODO +@@ -77,9 +77,6 @@ Features: + + * networkd: + - add LLDP client side support +- - ipv4ll with multiple interfaces doesn't work when both dhcp and +- ipv4ll is used. for some reasons the kernel will currently pick an +- ipv4ll source address to reach non-ipv4ll gateways. + - the DHCP lease data (such as NTP/DNS) is still made available when + a carrier is lost on a link. It should be removed instantly. + - .network setting that allows overriding of the hostname to send to the dhcp server diff --git a/0192-sd-network-add-_get_network_file-api.patch b/0192-sd-network-add-_get_network_file-api.patch new file mode 100644 index 0000000..e0fa5fe --- /dev/null +++ b/0192-sd-network-add-_get_network_file-api.patch @@ -0,0 +1,73 @@ +From adc5b2e2ebcb91ee18b6a32681b8ec1e52793473 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 8 Sep 2014 13:50:52 +0200 +Subject: [PATCH] sd-network: add _get_network_file api + +--- + src/libsystemd/sd-network/sd-network.c | 24 ++++++++++++++++++++++++ + src/network/networkd-link.c | 2 ++ + src/systemd/sd-network.h | 3 +++ + 3 files changed, 29 insertions(+) + +diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c +index 3a3f53576f..d63e6f9dfa 100644 +--- a/src/libsystemd/sd-network/sd-network.c ++++ b/src/libsystemd/sd-network/sd-network.c +@@ -120,6 +120,30 @@ _public_ int sd_network_link_get_setup_state(int ifindex, char **state) { + return 0; + } + ++_public_ int sd_network_link_get_network_file(int ifindex, char **filename) { ++ _cleanup_free_ char *s = NULL, *p = NULL; ++ int r; ++ ++ assert_return(ifindex > 0, -EINVAL); ++ assert_return(filename, -EINVAL); ++ ++ if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) ++ return -ENOMEM; ++ ++ r = parse_env_file(p, NEWLINE, "NETWORK_FILE", &s, NULL); ++ if (r == -ENOENT) ++ return -ENODATA; ++ if (r < 0) ++ return r; ++ if (isempty(s)) ++ return -ENODATA; ++ ++ *filename = s; ++ s = NULL; ++ ++ return 0; ++} ++ + _public_ int sd_network_link_get_operational_state(int ifindex, char **state) { + _cleanup_free_ char *s = NULL, *p = NULL; + int r; +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index a88cf48d9d..11ac1307d8 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -1785,6 +1785,8 @@ int link_save(Link *link) { + char **address, **domain; + bool space; + ++ fprintf(f, "NETWORK_FILE=%s\n", link->network->filename); ++ + fputs("DNS=", f); + space = false; + STRV_FOREACH(address, link->network->dns) { +diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h +index b2086c7836..203a2a6a47 100644 +--- a/src/systemd/sd-network.h ++++ b/src/systemd/sd-network.h +@@ -93,6 +93,9 @@ int sd_network_link_get_setup_state(int ifindex, char **state); + */ + int sd_network_link_get_operational_state(int ifindex, char **state); + ++/* Get path to .network file applied to link */ ++int sd_network_link_get_network_file(int ifindex, char **filename); ++ + /* Get DNS entries for a given link. These are string representations of + * IP addresses */ + int sd_network_link_get_dns(int ifindex, char ***addr); diff --git a/0193-networkctl-show-the-network-file-applied-to-each-lin.patch b/0193-networkctl-show-the-network-file-applied-to-each-lin.patch new file mode 100644 index 0000000..98bd014 --- /dev/null +++ b/0193-networkctl-show-the-network-file-applied-to-each-lin.patch @@ -0,0 +1,38 @@ +From 373d9f173f910d547159917401c4b1f84af85736 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 8 Sep 2014 14:00:34 +0200 +Subject: [PATCH] networkctl: show the network file applied to each link + +--- + src/network/networkctl.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index d6d2e1dd27..43258bb942 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -294,7 +294,7 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL; + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + char devid[2 + DECIMAL_STR_MAX(int)]; +- _cleanup_free_ char *t = NULL; ++ _cleanup_free_ char *t = NULL, *network = NULL; + const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL; + const char *on_color_operational, *off_color_operational, + *on_color_setup, *off_color_setup; +@@ -396,11 +396,14 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) { + model = udev_device_get_property_value(d, "ID_MODEL"); + } + ++ sd_network_link_get_network_file(ifindex, &network); + + printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name); + +- printf(" Type: %s\n" ++ printf("Network File: %s\n" ++ " Type: %s\n" + " State: %s%s%s (%s%s%s)\n", ++ strna(network), + strna(t), + on_color_operational, strna(operational_state), off_color_operational, + on_color_setup, strna(setup_state), off_color_setup); diff --git a/0194-udev-net_setup_link-export-the-.link-filename-applie.patch b/0194-udev-net_setup_link-export-the-.link-filename-applie.patch new file mode 100644 index 0000000..f78ee06 --- /dev/null +++ b/0194-udev-net_setup_link-export-the-.link-filename-applie.patch @@ -0,0 +1,23 @@ +From ad6e5b348fa88f44d6cbfe7aabda7612a1d0463f Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 8 Sep 2014 14:00:58 +0200 +Subject: [PATCH] udev: net_setup_link - export the .link filename applied to + the link + +--- + src/udev/udev-builtin-net_setup_link.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c +index 6207269ab9..14351de6a6 100644 +--- a/src/udev/udev-builtin-net_setup_link.c ++++ b/src/udev/udev-builtin-net_setup_link.c +@@ -57,6 +57,8 @@ static int builtin_net_setup_link(struct udev_device *dev, int argc, char **argv + return EXIT_FAILURE; + } + ++ udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE", link->filename); ++ + if (name) + udev_builtin_add_property(dev, test, "ID_NET_NAME", name); + diff --git a/0195-udev-link-config-only-set-name-on-success.patch b/0195-udev-link-config-only-set-name-on-success.patch new file mode 100644 index 0000000..fe1f7df --- /dev/null +++ b/0195-udev-link-config-only-set-name-on-success.patch @@ -0,0 +1,31 @@ +From d95b83b87d7d7c50e550f7128827f73a321c8934 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 8 Sep 2014 14:17:46 +0200 +Subject: [PATCH] udev: link-config - only set *name on success + +--- + src/udev/net/link-config.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index c2881d6b41..64ff00dc0d 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -424,8 +424,6 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, + } else + new_name = NULL; + +- *name = new_name; +- + switch (config->mac_policy) { + case MACPOLICY_PERSISTENT: + if (mac_is_random(device)) { +@@ -459,6 +457,8 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, + return r; + } + ++ *name = new_name; ++ + return 0; + } + diff --git a/0196-networkctl-show-the-link-file-applied-to-each-link.patch b/0196-networkctl-show-the-link-file-applied-to-each-link.patch new file mode 100644 index 0000000..747a399 --- /dev/null +++ b/0196-networkctl-show-the-link-file-applied-to-each-link.patch @@ -0,0 +1,43 @@ +From af5effc4220dab6c4c87a130bae7be441f6967ca Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 8 Sep 2014 14:18:32 +0200 +Subject: [PATCH] networkctl: show the link file applied to each link + +--- + src/network/networkctl.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index 43258bb942..b374121fbc 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -295,7 +295,7 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + char devid[2 + DECIMAL_STR_MAX(int)]; + _cleanup_free_ char *t = NULL, *network = NULL; +- const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL; ++ const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL; + const char *on_color_operational, *off_color_operational, + *on_color_setup, *off_color_setup; + struct ether_addr e; +@@ -384,6 +384,7 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) { + link_get_type_string(iftype, d, &t); + + if (d) { ++ link = udev_device_get_property_value(d, "ID_NET_LINK_FILE"); + driver = udev_device_get_property_value(d, "ID_NET_DRIVER"); + path = udev_device_get_property_value(d, "ID_PATH"); + +@@ -400,9 +401,11 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) { + + printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name); + +- printf("Network File: %s\n" ++ printf(" Link File: %s\n" ++ "Network File: %s\n" + " Type: %s\n" + " State: %s%s%s (%s%s%s)\n", ++ strna(link), + strna(network), + strna(t), + on_color_operational, strna(operational_state), off_color_operational, diff --git a/0197-networkd-allow-specification-of-DHCP-route-metric.patch b/0197-networkd-allow-specification-of-DHCP-route-metric.patch new file mode 100644 index 0000000..866339f --- /dev/null +++ b/0197-networkd-allow-specification-of-DHCP-route-metric.patch @@ -0,0 +1,100 @@ +From 84b5b79a8f7b423c5b7cad4170eb68d57fe5e26c Mon Sep 17 00:00:00 2001 +From: Angus Gibson +Date: Mon, 8 Sep 2014 20:26:47 +1000 +Subject: [PATCH] networkd: allow specification of DHCP route metric + +This lets the routing metric for links to be specified per-network, +still defaulting to DHCP_ROUTE_METRIC (1024) if unspecified. Hopefully +this helps with multiple interfaces configured via DHCP. +--- + man/systemd.network.xml | 6 ++++++ + src/network/networkd-dhcp4.c | 6 +++--- + src/network/networkd-network-gperf.gperf | 1 + + src/network/networkd-network.c | 1 + + src/network/networkd.h | 1 + + 5 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/man/systemd.network.xml b/man/systemd.network.xml +index 641e02aab1..4cc13b2afc 100644 +--- a/man/systemd.network.xml ++++ b/man/systemd.network.xml +@@ -494,6 +494,12 @@ + hand, this must not be enabled on networks where broadcasts are filtered out. + + ++ ++ RouteMetric= ++ ++ Set the routing metric for routes specified by the DHCP server. ++ ++ + + + +diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c +index b87fa73082..e0b3acad1b 100644 +--- a/src/network/networkd-dhcp4.c ++++ b/src/network/networkd-dhcp4.c +@@ -103,7 +103,7 @@ static int link_set_dhcp_routes(Link *link) { + route_gw->dst_prefixlen = 32; + route_gw->prefsrc_addr.in = address; + route_gw->scope = RT_SCOPE_LINK; +- route_gw->metrics = DHCP_ROUTE_METRIC; ++ route_gw->metrics = link->network->dhcp_route_metric; + + r = route_configure(route_gw, link, &dhcp4_route_handler); + if (r < 0) { +@@ -118,7 +118,7 @@ static int link_set_dhcp_routes(Link *link) { + route->family = AF_INET; + route->in_addr.in = gateway; + route->prefsrc_addr.in = address; +- route->metrics = DHCP_ROUTE_METRIC; ++ route->metrics = link->network->dhcp_route_metric; + + r = route_configure(route, link, &dhcp4_route_handler); + if (r < 0) { +@@ -157,7 +157,7 @@ static int link_set_dhcp_routes(Link *link) { + route->in_addr.in = static_routes[i].gw_addr; + route->dst_addr.in = static_routes[i].dst_addr; + route->dst_prefixlen = static_routes[i].dst_prefixlen; +- route->metrics = DHCP_ROUTE_METRIC; ++ route->metrics = link->network->dhcp_route_metric; + + r = route_configure(route, link, &dhcp4_route_handler); + if (r < 0) { +diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf +index c5b9614a2b..a73646187e 100644 +--- a/src/network/networkd-network-gperf.gperf ++++ b/src/network/networkd-network-gperf.gperf +@@ -57,6 +57,7 @@ DHCP.SendHostname, config_parse_bool, 0, + DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) + DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) + DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) ++DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) + /* backwards compatibility: do not add new entries to this section */ + DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) + DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c +index fc62395217..a2e27e0910 100644 +--- a/src/network/networkd-network.c ++++ b/src/network/networkd-network.c +@@ -85,6 +85,7 @@ static int network_load_one(Manager *manager, const char *filename) { + network->dhcp_hostname = true; + network->dhcp_routes = true; + network->dhcp_sendhost = true; ++ network->dhcp_route_metric = DHCP_ROUTE_METRIC; + + network->llmnr = LLMNR_SUPPORT_YES; + +diff --git a/src/network/networkd.h b/src/network/networkd.h +index c6e6b22c38..7c5459b6ac 100644 +--- a/src/network/networkd.h ++++ b/src/network/networkd.h +@@ -100,6 +100,7 @@ struct Network { + bool dhcp_broadcast; + bool dhcp_critical; + bool dhcp_routes; ++ unsigned dhcp_route_metric; + bool ipv4ll; + bool ipv4ll_route; + diff --git a/0198-machined-remove-redundant-sd_notify.patch b/0198-machined-remove-redundant-sd_notify.patch new file mode 100644 index 0000000..b19af29 --- /dev/null +++ b/0198-machined-remove-redundant-sd_notify.patch @@ -0,0 +1,27 @@ +From 4cb40606785c30710bcf39bba33167bee66ad0bd Mon Sep 17 00:00:00 2001 +From: Dave Reisner +Date: Mon, 8 Sep 2014 09:27:41 -0400 +Subject: [PATCH] machined: remove redundant sd_notify + +We already call this on via bus_event_loop_with_idle on exit. This +makes machined consistent with other similar daemons: localed, +hostnamed, timedated. +--- + src/machine/machined.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/machine/machined.c b/src/machine/machined.c +index f9d180d24a..aac670ba78 100644 +--- a/src/machine/machined.c ++++ b/src/machine/machined.c +@@ -349,10 +349,6 @@ int main(int argc, char *argv[]) { + log_debug("systemd-machined stopped as pid "PID_FMT, getpid()); + + finish: +- sd_notify(false, +- "STOPPING=1\n" +- "STATUS=Shutting down..."); +- + if (m) + manager_free(m); + diff --git a/0199-rules-net-setup-link-preserve-ID_NET_LINK_FILE-and-I.patch b/0199-rules-net-setup-link-preserve-ID_NET_LINK_FILE-and-I.patch new file mode 100644 index 0000000..c6cc988 --- /dev/null +++ b/0199-rules-net-setup-link-preserve-ID_NET_LINK_FILE-and-I.patch @@ -0,0 +1,24 @@ +From e4d7c49050769877c7f10184bbe2a1e77d0b5333 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 8 Sep 2014 17:16:24 +0200 +Subject: [PATCH] rules: net-setup-link - preserve ID_NET_LINK_FILE and + ID_NET_NAME after MOVE + +--- + rules/80-net-setup-link.rules | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/rules/80-net-setup-link.rules b/rules/80-net-setup-link.rules +index f390fcb0dd..27c43b9437 100644 +--- a/rules/80-net-setup-link.rules ++++ b/rules/80-net-setup-link.rules +@@ -4,7 +4,8 @@ SUBSYSTEM!="net", GOTO="net_setup_link_end" + + IMPORT{builtin}="path_id" + +-ACTION=="move", IMPORT{db}="ID_NET_DRIVER" ++ACTION=="move", IMPORT{db}="ID_NET_DRIVER", IMPORT{db}="ID_NET_LINK_FILE", ++IMPORT{db}="ID_NET_NAME" + + ACTION!="add", GOTO="net_setup_link_end" + diff --git a/0200-rules-net-setup-link-remove-stray-linebreak.patch b/0200-rules-net-setup-link-remove-stray-linebreak.patch new file mode 100644 index 0000000..8136231 --- /dev/null +++ b/0200-rules-net-setup-link-remove-stray-linebreak.patch @@ -0,0 +1,24 @@ +From 52e231b04635400292179cf51b30d7d9b6323fb2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mantas=20Mikul=C4=97nas?= +Date: Mon, 8 Sep 2014 22:53:39 +0300 +Subject: [PATCH] rules: net-setup-link - remove stray linebreak + +If not backslash-escaped, it splits the rule in two. +--- + rules/80-net-setup-link.rules | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/rules/80-net-setup-link.rules b/rules/80-net-setup-link.rules +index 27c43b9437..420769497f 100644 +--- a/rules/80-net-setup-link.rules ++++ b/rules/80-net-setup-link.rules +@@ -4,8 +4,7 @@ SUBSYSTEM!="net", GOTO="net_setup_link_end" + + IMPORT{builtin}="path_id" + +-ACTION=="move", IMPORT{db}="ID_NET_DRIVER", IMPORT{db}="ID_NET_LINK_FILE", +-IMPORT{db}="ID_NET_NAME" ++ACTION=="move", IMPORT{db}="ID_NET_DRIVER", IMPORT{db}="ID_NET_LINK_FILE", IMPORT{db}="ID_NET_NAME" + + ACTION!="add", GOTO="net_setup_link_end" + diff --git a/0201-namespace-avoid-posible-use-of-uninitialized-variabl.patch b/0201-namespace-avoid-posible-use-of-uninitialized-variabl.patch new file mode 100644 index 0000000..2aac0b6 --- /dev/null +++ b/0201-namespace-avoid-posible-use-of-uninitialized-variabl.patch @@ -0,0 +1,22 @@ +From 120d578e5fa11ee3c210121905fb63bc24e3f043 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Mon, 8 Sep 2014 22:05:17 +0200 +Subject: [PATCH] namespace: avoid posible use of uninitialized variable + +--- + 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 eaaebdd644..f76d3891c3 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -278,7 +278,7 @@ static int mount_kdbus(BindMount *m) { + char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX"; + _cleanup_free_ char *basepath = NULL; + _cleanup_umask_ mode_t u; +- char *busnode, *root; ++ char *busnode = NULL, *root; + struct stat st; + int r; + diff --git a/0202-execute-silence-warnings.patch b/0202-execute-silence-warnings.patch new file mode 100644 index 0000000..822ebd2 --- /dev/null +++ b/0202-execute-silence-warnings.patch @@ -0,0 +1,32 @@ +From 822a59607c4974915db0644b627070f001986825 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Mon, 8 Sep 2014 22:10:36 +0200 +Subject: [PATCH] execute: silence warnings + +Mark two function parameters as const +--- + 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 2b16b36c19..db755777c1 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -939,7 +939,7 @@ static void rename_process_from_path(const char *path) { + + #ifdef HAVE_SECCOMP + +-static int apply_seccomp(ExecContext *c) { ++static int apply_seccomp(const ExecContext *c) { + uint32_t negative_action, action; + scmp_filter_ctx *seccomp; + Iterator i; +@@ -988,7 +988,7 @@ finish: + return r; + } + +-static int apply_address_families(ExecContext *c) { ++static int apply_address_families(const ExecContext *c) { + scmp_filter_ctx *seccomp; + Iterator i; + int r; diff --git a/0203-hwdb-update.patch b/0203-hwdb-update.patch new file mode 100644 index 0000000..ed2607a --- /dev/null +++ b/0203-hwdb-update.patch @@ -0,0 +1,3360 @@ +From fea0bfaed5411de43811dc428e763029d3aaabe5 Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Tue, 9 Sep 2014 07:44:02 +0200 +Subject: [PATCH] hwdb: update + +--- + hwdb/20-OUI.hwdb | 249 +++++- + hwdb/20-pci-vendor-model.hwdb | 1987 ++++++++++++++++++++++++++++++++++++++++- + hwdb/20-usb-vendor-model.hwdb | 2 +- + 3 files changed, 2199 insertions(+), 39 deletions(-) + +diff --git a/hwdb/20-OUI.hwdb b/hwdb/20-OUI.hwdb +index e0c5fed985..73df96cf6b 100644 +--- a/hwdb/20-OUI.hwdb ++++ b/hwdb/20-OUI.hwdb +@@ -4103,7 +4103,7 @@ OUI:0050C2561* + ID_OUI_FROM_DATABASE=Seitec Elektronik GmbH + + OUI:0050C2562* +- ID_OUI_FROM_DATABASE=C21 Technology Limited ++ ID_OUI_FROM_DATABASE=C21 Systems Limited + + OUI:0050C2563* + ID_OUI_FROM_DATABASE=ORTRAT, S.L. +@@ -26081,7 +26081,7 @@ OUI:00105D* + ID_OUI_FROM_DATABASE=Draeger Medical + + OUI:00105E* +- ID_OUI_FROM_DATABASE=HEKIMIAN LABORATORIES, INC. ++ ID_OUI_FROM_DATABASE=Spirent plc, Service Assurance Broadband + + OUI:00105F* + ID_OUI_FROM_DATABASE=ZODIAC DATA SYSTEMS +@@ -35786,7 +35786,7 @@ OUI:001D04* + ID_OUI_FROM_DATABASE=Zipit Wireless, Inc. + + OUI:001D05* +- ID_OUI_FROM_DATABASE=iLight ++ ID_OUI_FROM_DATABASE=Eaton Corporation + + OUI:001D06* + ID_OUI_FROM_DATABASE=HM Electronics, Inc. +@@ -44287,6 +44287,9 @@ OUI:0034F1* + OUI:003532* + ID_OUI_FROM_DATABASE=Electro-Metrics Corporation + ++OUI:003560* ++ ID_OUI_FROM_DATABASE=Rosen Aviation ++ + OUI:0036F8* + ID_OUI_FROM_DATABASE=Conti Temic microelectronic GmbH + +@@ -50072,7 +50075,7 @@ OUI:00D01E* + ID_OUI_FROM_DATABASE=PINGTEL CORP. + + OUI:00D01F* +- ID_OUI_FROM_DATABASE=CTAM PTY. LTD. ++ ID_OUI_FROM_DATABASE=Senetas Security + + OUI:00D020* + ID_OUI_FROM_DATABASE=AIM SYSTEM, INC. +@@ -51616,6 +51619,9 @@ OUI:00EEBD* + OUI:00F051* + ID_OUI_FROM_DATABASE=KWB Gmbh + ++OUI:00F3DB* ++ ID_OUI_FROM_DATABASE=WOO Sports ++ + OUI:00F403* + ID_OUI_FROM_DATABASE=Orbis Systems Oy + +@@ -51889,6 +51895,9 @@ OUI:04B3B6* + OUI:04B466* + ID_OUI_FROM_DATABASE=BSP Co., Ltd. + ++OUI:04BD70* ++ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD ++ + OUI:04BFA8* + ID_OUI_FROM_DATABASE=ISB Corporation + +@@ -51898,6 +51907,9 @@ OUI:04C05B* + OUI:04C06F* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + ++OUI:04C09C* ++ ID_OUI_FROM_DATABASE=Tellabs Inc. ++ + OUI:04C1B9* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +@@ -52657,6 +52669,9 @@ OUI:089F97* + OUI:08A12B* + ID_OUI_FROM_DATABASE=ShenZhen EZL Technology Co., Ltd + ++OUI:08A5C8* ++ ID_OUI_FROM_DATABASE=Sunnovo International Limited ++ + OUI:08A95A* + ID_OUI_FROM_DATABASE=Azurewave + +@@ -52747,6 +52762,9 @@ OUI:08EE8B* + OUI:08EF3B* + ID_OUI_FROM_DATABASE=MCS Logic Inc. + ++OUI:08EFAB* ++ ID_OUI_FROM_DATABASE=SAYME WIRELESS SENSOR NETWORK ++ + OUI:08F1B7* + ID_OUI_FROM_DATABASE=Towerstream Corpration + +@@ -53125,6 +53143,9 @@ OUI:1001CA* + OUI:1005CA* + ID_OUI_FROM_DATABASE=Cisco + ++OUI:100723* ++ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information. ++ + OUI:1008B1* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +@@ -53389,6 +53410,9 @@ OUI:10C586* + OUI:10C61F* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + ++OUI:10C67E* ++ ID_OUI_FROM_DATABASE=SHENZHEN JUCHIN TECHNOLOGY CO., LTD ++ + OUI:10C6FC* + ID_OUI_FROM_DATABASE=Garmin International + +@@ -53446,6 +53470,9 @@ OUI:10F3DB* + OUI:10F49A* + ID_OUI_FROM_DATABASE=T3 Innovation + ++OUI:10F681* ++ ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. ++ + OUI:10F96F* + ID_OUI_FROM_DATABASE=LG Electronics + +@@ -53527,6 +53554,9 @@ OUI:1435B3* + OUI:143605* + ID_OUI_FROM_DATABASE=Nokia Corporation + ++OUI:1436C6* ++ ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. ++ + OUI:14373B* + ID_OUI_FROM_DATABASE=PROCOM Systems + +@@ -53782,6 +53812,9 @@ OUI:18193F* + OUI:181BEB* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + ++OUI:181E78* ++ ID_OUI_FROM_DATABASE=SAGEMCOM ++ + OUI:181EB0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +@@ -53881,6 +53914,9 @@ OUI:18622C* + OUI:186472* + ID_OUI_FROM_DATABASE=Aruba Networks + ++OUI:186571* ++ ID_OUI_FROM_DATABASE=Top Victory Electronics (Taiwan) Co., Ltd. ++ + OUI:1866E3* + ID_OUI_FROM_DATABASE=Veros Systems, Inc. + +@@ -54023,7 +54059,7 @@ OUI:18CF5E* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + + OUI:18D071* +- ID_OUI_FROM_DATABASE=DASAN SMC, Inc. ++ ID_OUI_FROM_DATABASE=DASAN CO., LTD. + + OUI:18D5B6* + ID_OUI_FROM_DATABASE=SMG Holdings LLC +@@ -55270,6 +55306,9 @@ OUI:28D576* + OUI:28D93E* + ID_OUI_FROM_DATABASE=Telecor Inc. + ++OUI:28D98A* ++ ID_OUI_FROM_DATABASE=Hangzhou Konke Technology Co.,Ltd. ++ + OUI:28D997* + ID_OUI_FROM_DATABASE=Yuduan Mobile Co., Ltd. + +@@ -55387,6 +55426,9 @@ OUI:2C2D48* + OUI:2C3068* + ID_OUI_FROM_DATABASE=Pantech Co.,Ltd + ++OUI:2C337A* ++ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. ++ + OUI:2C3427* + ID_OUI_FROM_DATABASE=ERCO & GENER + +@@ -55891,6 +55933,9 @@ OUI:30D357* + OUI:30D46A* + ID_OUI_FROM_DATABASE=Autosales Incorporated + ++OUI:30D587* ++ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd ++ + OUI:30D6C9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +@@ -56062,6 +56107,9 @@ OUI:346BD3* + OUI:346E8A* + ID_OUI_FROM_DATABASE=Ecosense + ++OUI:346F90* ++ ID_OUI_FROM_DATABASE=Cisco ++ + OUI:346F92* + ID_OUI_FROM_DATABASE=White Rodgers Division + +@@ -56266,6 +56314,9 @@ OUI:34E42A* + OUI:34E6AD* + ID_OUI_FROM_DATABASE=Intel Corporate + ++OUI:34E6D7* ++ ID_OUI_FROM_DATABASE=Dell Inc. ++ + OUI:34EF44* + ID_OUI_FROM_DATABASE=2Wire + +@@ -56413,6 +56464,9 @@ OUI:385FC3* + OUI:386077* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + ++OUI:3863BB* ++ ID_OUI_FROM_DATABASE=Hewlett Packard ++ + OUI:3863F6* + ID_OUI_FROM_DATABASE=3NOD MULTIMEDIA(SHENZHEN)CO.,LTD + +@@ -56677,6 +56731,9 @@ OUI:3C3888* + OUI:3C39C3* + ID_OUI_FROM_DATABASE=JW Electronics Co., Ltd. + ++OUI:3C39E7* ++ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information. ++ + OUI:3C3A73* + ID_OUI_FROM_DATABASE=Avaya, Inc + +@@ -56689,6 +56746,9 @@ OUI:3C438E* + OUI:3C46D8* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + ++OUI:3C4937* ++ ID_OUI_FROM_DATABASE=ASSMANN Electronic GmbH ++ + OUI:3C4A92* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +@@ -56815,6 +56875,9 @@ OUI:3CAA3F* + OUI:3CAB8E* + ID_OUI_FROM_DATABASE=Apple + ++OUI:3CAE69* ++ ID_OUI_FROM_DATABASE=ESA Elektroschaltanlagen Grimma GmbH ++ + OUI:3CB15B* + ID_OUI_FROM_DATABASE=Avaya, Inc + +@@ -57211,6 +57274,9 @@ OUI:40E730* + OUI:40E793* + ID_OUI_FROM_DATABASE=Shenzhen Siviton Technology Co.,Ltd + ++OUI:40EACE* ++ ID_OUI_FROM_DATABASE=FOUNDER BROADBAND NETWORK SERVICE CO.,LTD ++ + OUI:40ECF8* + ID_OUI_FROM_DATABASE=Siemens AG + +@@ -57535,6 +57601,9 @@ OUI:44DCCB* + OUI:44E08E* + ID_OUI_FROM_DATABASE=Cisco SPVTG + ++OUI:44E137* ++ ID_OUI_FROM_DATABASE=ARRIS Group, Inc. ++ + OUI:44E49A* + ID_OUI_FROM_DATABASE=OMNITRONICS PTY LTD + +@@ -58348,6 +58417,9 @@ OUI:50A733* + OUI:50ABBF* + ID_OUI_FROM_DATABASE=Hoseo Telecom + ++OUI:50ADD5* ++ ID_OUI_FROM_DATABASE=Dynalec Corporation ++ + OUI:50AF73* + ID_OUI_FROM_DATABASE=Shenzhen Bitland Information Technology Co., Ltd. + +@@ -58537,6 +58609,9 @@ OUI:544A05* + OUI:544A16* + ID_OUI_FROM_DATABASE=Texas Instruments + ++OUI:545146* ++ ID_OUI_FROM_DATABASE=AMG Systems Ltd. ++ + OUI:5453ED* + ID_OUI_FROM_DATABASE=Sony Corporation + +@@ -58852,6 +58927,9 @@ OUI:58696C* + OUI:5869F9* + ID_OUI_FROM_DATABASE=Fusion Transactive Ltd. + ++OUI:586AB1* ++ ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited ++ + OUI:586D8F* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +@@ -59080,6 +59158,9 @@ OUI:5C2BF5* + OUI:5C2E59* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + ++OUI:5C2ED2* ++ ID_OUI_FROM_DATABASE=ABC(XiSheng) Electronics Co.,Ltd ++ + OUI:5C313E* + ID_OUI_FROM_DATABASE=Texas Instruments + +@@ -59272,6 +59353,9 @@ OUI:5CDAD4* + OUI:5CDD70* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + ++OUI:5CE0C5* ++ ID_OUI_FROM_DATABASE=Intel Corporate ++ + OUI:5CE0CA* + ID_OUI_FROM_DATABASE=FeiTian United (Beijing) System Technology Co., Ltd. + +@@ -59767,6 +59851,9 @@ OUI:64317E* + OUI:643409* + ID_OUI_FROM_DATABASE=BITwave Pte Ltd + ++OUI:643E8C* ++ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD ++ + OUI:643F5F* + ID_OUI_FROM_DATABASE=Exablaze + +@@ -59908,6 +59995,9 @@ OUI:6487D7* + OUI:6488FF* + ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd. + ++OUI:64899A* ++ ID_OUI_FROM_DATABASE=LG Electronics ++ + OUI:648D9E* + ID_OUI_FROM_DATABASE=IVT Electronic Co.,Ltd + +@@ -60328,6 +60418,9 @@ OUI:68BC0C* + OUI:68BDAB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + ++OUI:68C90B* ++ ID_OUI_FROM_DATABASE=Texas Instruments ++ + OUI:68CA00* + ID_OUI_FROM_DATABASE=Octopus Systems Limited + +@@ -60442,6 +60535,9 @@ OUI:6C22AB* + OUI:6C23B9* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + ++OUI:6C25B9* ++ ID_OUI_FROM_DATABASE=BBK Electronics Corp., Ltd., ++ + OUI:6C2995* + ID_OUI_FROM_DATABASE=Intel Corporate + +@@ -60574,6 +60670,9 @@ OUI:6C90B1* + OUI:6C92BF* + ID_OUI_FROM_DATABASE=Inspur Electronic Information Industry Co.,Ltd. + ++OUI:6C94F8* ++ ID_OUI_FROM_DATABASE=Apple ++ + OUI:6C98EB* + ID_OUI_FROM_DATABASE=Ocedo GmbH + +@@ -60724,6 +60823,9 @@ OUI:700514* + OUI:700BC0* + ID_OUI_FROM_DATABASE=Dewav Technology Company + ++OUI:700FC7* ++ ID_OUI_FROM_DATABASE=SHENZHEN IKINLOOP TECHNOLOGY CO.,LTD. ++ + OUI:700FEC* + ID_OUI_FROM_DATABASE=Poindus Systems Corp. + +@@ -60802,6 +60904,9 @@ OUI:703AD8* + OUI:703C39* + ID_OUI_FROM_DATABASE=SEAWING Kft + ++OUI:703EAC* ++ ID_OUI_FROM_DATABASE=Apple ++ + OUI:7041B7* + ID_OUI_FROM_DATABASE=Edwards Lifesciences LLC + +@@ -60901,6 +61006,9 @@ OUI:7076DD* + OUI:7076F0* + ID_OUI_FROM_DATABASE=LevelOne Communications (India) Private Limited + ++OUI:7076FF* ++ ID_OUI_FROM_DATABASE=KERLINK ++ + OUI:707BE8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +@@ -61105,6 +61213,9 @@ OUI:74273C* + OUI:7427EA* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., Ltd. + ++OUI:7429AF* ++ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. ++ + OUI:742B0F* + ID_OUI_FROM_DATABASE=Infinidat Ltd. + +@@ -61447,6 +61558,9 @@ OUI:78303B* + OUI:7830E1* + ID_OUI_FROM_DATABASE=UltraClenz, LLC + ++OUI:78312B* ++ ID_OUI_FROM_DATABASE=zte corporation ++ + OUI:7831C1* + ID_OUI_FROM_DATABASE=Apple + +@@ -61639,6 +61753,9 @@ OUI:78ACC0* + OUI:78AE0C* + ID_OUI_FROM_DATABASE=Far South Networks + ++OUI:78B3B9* ++ ID_OUI_FROM_DATABASE=ShangHai sunup lighting CO.,LTD ++ + OUI:78B3CE* + ID_OUI_FROM_DATABASE=Elo touch solutions + +@@ -61741,6 +61858,9 @@ OUI:78E7D1* + OUI:78E8B6* + ID_OUI_FROM_DATABASE=zte corporation + ++OUI:78EB14* ++ ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD ++ + OUI:78EC22* + ID_OUI_FROM_DATABASE=Shanghai Qihui Telecom Technology Co., LTD + +@@ -62569,6 +62689,9 @@ OUI:843A4B* + OUI:843F4E* + ID_OUI_FROM_DATABASE=Tri-Tech Manufacturing, Inc. + ++OUI:844464* ++ ID_OUI_FROM_DATABASE=ServerU Inc ++ + OUI:844823* + ID_OUI_FROM_DATABASE=WOXTER TECHNOLOGY Co. Ltd + +@@ -62605,6 +62728,9 @@ OUI:846223* + OUI:8462A6* + ID_OUI_FROM_DATABASE=EuroCB (Phils), Inc. + ++OUI:8463D6* ++ ID_OUI_FROM_DATABASE=Microsoft Corporation ++ + OUI:846AED* + ID_OUI_FROM_DATABASE=Wireless Tsukamoto.,co.LTD + +@@ -62665,6 +62791,9 @@ OUI:848E0C* + OUI:848E96* + ID_OUI_FROM_DATABASE=Embertec Pty Ltd + ++OUI:848EDF* ++ ID_OUI_FROM_DATABASE=Sony Mobile Communications AB ++ + OUI:848F69* + ID_OUI_FROM_DATABASE=Dell Inc. + +@@ -62746,6 +62875,9 @@ OUI:84DB2F* + OUI:84DD20* + ID_OUI_FROM_DATABASE=Texas Instruments + ++OUI:84DDB7* ++ ID_OUI_FROM_DATABASE=Cilag GmbH International ++ + OUI:84DE3D* + ID_OUI_FROM_DATABASE=Crystal Vision Ltd + +@@ -62812,6 +62944,9 @@ OUI:881544* + OUI:8818AE* + ID_OUI_FROM_DATABASE=Tamron Co., Ltd + ++OUI:881DFC* ++ ID_OUI_FROM_DATABASE=Cisco ++ + OUI:881FA1* + ID_OUI_FROM_DATABASE=Apple + +@@ -63367,6 +63502,9 @@ OUI:8CDF9D* + OUI:8CE081* + ID_OUI_FROM_DATABASE=zte corporation + ++OUI:8CE78C* ++ ID_OUI_FROM_DATABASE=DK Networks ++ + OUI:8CE7B3* + ID_OUI_FROM_DATABASE=Sonardyne International Ltd + +@@ -63409,6 +63547,9 @@ OUI:900917* + OUI:900A3A* + ID_OUI_FROM_DATABASE=PSG Plastic Service GmbH + ++OUI:900CB4* ++ ID_OUI_FROM_DATABASE=Alinket Electronic Technology Co., Ltd ++ + OUI:900D66* + ID_OUI_FROM_DATABASE=Digimore Electronics Co., Ltd + +@@ -63556,6 +63697,9 @@ OUI:9067B5* + OUI:9067F3* + ID_OUI_FROM_DATABASE=Alcatel Lucent + ++OUI:9068C3* ++ ID_OUI_FROM_DATABASE=Motorola Mobility LLC ++ + OUI:906DC8* + ID_OUI_FROM_DATABASE=DLG Automação Industrial Ltda + +@@ -63781,6 +63925,9 @@ OUI:940149* + OUI:9401C2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + ++OUI:9405B6* ++ ID_OUI_FROM_DATABASE=Liling FullRiver Electronics & Technology Ltd ++ + OUI:940B2D* + ID_OUI_FROM_DATABASE=NetView Technologies(Shenzhen) Co., Ltd + +@@ -63913,6 +64060,9 @@ OUI:948B03* + OUI:948D50* + ID_OUI_FROM_DATABASE=Beamex Oy Ab + ++OUI:948E89* ++ ID_OUI_FROM_DATABASE=INDUSTRIAS UNIDAS SA DE CV ++ + OUI:948FEE* + ID_OUI_FROM_DATABASE=Hughes Telematics, Inc. + +@@ -64639,6 +64789,9 @@ OUI:9CD36D* + OUI:9CD643* + ID_OUI_FROM_DATABASE=D-Link International + ++OUI:9CD917* ++ ID_OUI_FROM_DATABASE=Motorola Mobility LLC ++ + OUI:9CDF03* + ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH + +@@ -65407,6 +65560,9 @@ OUI:A81B18* + OUI:A81B5D* + ID_OUI_FROM_DATABASE=Foxtel Management Pty Ltd + ++OUI:A81D16* ++ ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc ++ + OUI:A81FAF* + ID_OUI_FROM_DATABASE=KRYPTON POLSKA + +@@ -65473,6 +65629,9 @@ OUI:A863DF* + OUI:A863F2* + ID_OUI_FROM_DATABASE=Texas Instruments + ++OUI:A86405* ++ ID_OUI_FROM_DATABASE=nimbus 9, Inc ++ + OUI:A865B2* + ID_OUI_FROM_DATABASE=DONGGUAN YISHANG ELECTRONIC TECHNOLOGY CO., LIMITED + +@@ -66064,6 +66223,9 @@ OUI:B0435D* + OUI:B04515* + ID_OUI_FROM_DATABASE=mira fitness,LLC. + ++OUI:B04519* ++ ID_OUI_FROM_DATABASE=TCT mobile ltd ++ + OUI:B04545* + ID_OUI_FROM_DATABASE=YACOUB Automation GmbH + +@@ -67105,6 +67267,9 @@ OUI:BC4760* + OUI:BC4B79* + ID_OUI_FROM_DATABASE=SensingTek + ++OUI:BC4DFB* ++ ID_OUI_FROM_DATABASE=Hitron Technologies. Inc ++ + OUI:BC4E3C* + ID_OUI_FROM_DATABASE=CORE STAFF CO., LTD. + +@@ -67114,6 +67279,9 @@ OUI:BC4E5D* + OUI:BC51FE* + ID_OUI_FROM_DATABASE=Swann Communications Pty Ltd + ++OUI:BC52B4* ++ ID_OUI_FROM_DATABASE=Alcatel-Lucent ++ + OUI:BC52B7* + ID_OUI_FROM_DATABASE=Apple + +@@ -67153,6 +67321,9 @@ OUI:BC71C1* + OUI:BC72B1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + ++OUI:BC74D7* ++ ID_OUI_FROM_DATABASE=HangZhou JuRu Technology CO.,LTD ++ + OUI:BC764E* + ID_OUI_FROM_DATABASE=Rackspace US, Inc. + +@@ -67363,6 +67534,9 @@ OUI:C03580* + OUI:C035BD* + ID_OUI_FROM_DATABASE=Velocytech Aps + ++OUI:C035C5* ++ ID_OUI_FROM_DATABASE=Prosoft Systems LTD ++ + OUI:C03896* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +@@ -67867,6 +68041,9 @@ OUI:C4BA99* + OUI:C4BD6A* + ID_OUI_FROM_DATABASE=SKF GmbH + ++OUI:C4BE84* ++ ID_OUI_FROM_DATABASE=Texas Instruments. ++ + OUI:C4C0AE* + ID_OUI_FROM_DATABASE=MIDORI ELECTRONIC CO., LTD. + +@@ -68527,6 +68704,9 @@ OUI:CCB8F1* + OUI:CCBD35* + ID_OUI_FROM_DATABASE=Steinel GmbH + ++OUI:CCBDD3* ++ ID_OUI_FROM_DATABASE=Ultimaker B.V. ++ + OUI:CCBE71* + ID_OUI_FROM_DATABASE=OptiLogix BV + +@@ -68698,6 +68878,9 @@ OUI:D046DC* + OUI:D04CC1* + ID_OUI_FROM_DATABASE=SINTRONES Technology Corp. + ++OUI:D04F7E* ++ ID_OUI_FROM_DATABASE=Apple ++ + OUI:D05099* + ID_OUI_FROM_DATABASE=ASRock Incorporation + +@@ -68734,6 +68917,9 @@ OUI:D05A0F* + OUI:D05AF1* + ID_OUI_FROM_DATABASE=Shenzhen Pulier Tech CO.,Ltd + ++OUI:D05BA8* ++ ID_OUI_FROM_DATABASE=zte corporation ++ + OUI:D05FB8* + ID_OUI_FROM_DATABASE=Texas Instruments + +@@ -69025,6 +69211,9 @@ OUI:D42F23* + OUI:D4319D* + ID_OUI_FROM_DATABASE=Sinwatec + ++OUI:D43266* ++ ID_OUI_FROM_DATABASE=Fike Corporation ++ + OUI:D437D7* + ID_OUI_FROM_DATABASE=zte corporation + +@@ -69307,6 +69496,9 @@ OUI:D4F143* + OUI:D4F46F* + ID_OUI_FROM_DATABASE=Apple + ++OUI:D4F513* ++ ID_OUI_FROM_DATABASE=Texas Instruments ++ + OUI:D4F63F* + ID_OUI_FROM_DATABASE=IEA S.R.L. + +@@ -69568,6 +69760,9 @@ OUI:D8B8F6* + OUI:D8B90E* + ID_OUI_FROM_DATABASE=Triple Domain Vision Co.,Ltd. + ++OUI:D8BB2C* ++ ID_OUI_FROM_DATABASE=Apple ++ + OUI:D8BF4C* + ID_OUI_FROM_DATABASE=Victory Concept Electronics Limited + +@@ -69635,7 +69830,7 @@ OUI:D8E56D* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + + OUI:D8E72B* +- ID_OUI_FROM_DATABASE=OnPATH Technologies ++ ID_OUI_FROM_DATABASE=NetScout Systems, Inc. + + OUI:D8E743* + ID_OUI_FROM_DATABASE=Wush, Inc +@@ -70084,6 +70279,9 @@ OUI:E08177* + OUI:E087B1* + ID_OUI_FROM_DATABASE=Nata-Info Ltd. + ++OUI:E0885D* ++ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc ++ + OUI:E08A7E* + ID_OUI_FROM_DATABASE=Exponent + +@@ -70474,6 +70672,9 @@ OUI:E4AFA1* + OUI:E4B021* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + ++OUI:E4BAD9* ++ ID_OUI_FROM_DATABASE=360 Fly Inc. ++ + OUI:E4C146* + ID_OUI_FROM_DATABASE=Objetivos y Servicios de Valor A + +@@ -70603,6 +70804,9 @@ OUI:E82AEA* + OUI:E82E24* + ID_OUI_FROM_DATABASE=Out of the Fog Research LLC + ++OUI:E83381* ++ ID_OUI_FROM_DATABASE=ARRIS Group, Inc. ++ + OUI:E83935* + ID_OUI_FROM_DATABASE=Hewlett Packard + +@@ -70720,6 +70924,9 @@ OUI:E88D28* + OUI:E88DF5* + ID_OUI_FROM_DATABASE=ZNYX Networks, Inc. + ++OUI:E88E60* ++ ID_OUI_FROM_DATABASE=NSD Corporation ++ + OUI:E89218* + ID_OUI_FROM_DATABASE=Arcontia International AB + +@@ -70918,6 +71125,9 @@ OUI:EC233D* + OUI:EC2368* + ID_OUI_FROM_DATABASE=IntelliVoice Co.,Ltd. + ++OUI:EC24B8* ++ ID_OUI_FROM_DATABASE=Texas Instruments ++ + OUI:EC2AF0* + ID_OUI_FROM_DATABASE=Ypsomed AG + +@@ -70978,6 +71188,9 @@ OUI:EC542E* + OUI:EC55F9* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + ++OUI:EC59E7* ++ ID_OUI_FROM_DATABASE=Microsoft Corporation ++ + OUI:EC5C69* + ID_OUI_FROM_DATABASE=MITSUBISHI HEAVY INDUSTRIES MECHATRONICS SYSTEMS,LTD. + +@@ -71002,6 +71215,9 @@ OUI:EC7C74* + OUI:EC7D9D* + ID_OUI_FROM_DATABASE=MEI + ++OUI:EC8009* ++ ID_OUI_FROM_DATABASE=NovaSparks ++ + OUI:EC836C* + ID_OUI_FROM_DATABASE=RM Tech Co., Ltd. + +@@ -71449,6 +71665,9 @@ OUI:F0F002* + OUI:F0F260* + ID_OUI_FROM_DATABASE=Mobitec AB + ++OUI:F0F336* ++ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD ++ + OUI:F0F5AE* + ID_OUI_FROM_DATABASE=Adaptrum Inc. + +@@ -71476,6 +71695,9 @@ OUI:F0F9F7* + OUI:F0FDA0* + ID_OUI_FROM_DATABASE=Acurix Networks LP + ++OUI:F0FE6B* ++ ID_OUI_FROM_DATABASE=Shanghai High-Flying Electronics Technology Co., Ltd ++ + OUI:F40321* + ID_OUI_FROM_DATABASE=BeNeXt B.V. + +@@ -71758,6 +71980,9 @@ OUI:F4EA67* + OUI:F4EC38* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + ++OUI:F4EE14* ++ ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. ++ + OUI:F4F15A* + ID_OUI_FROM_DATABASE=Apple + +@@ -71881,6 +72106,9 @@ OUI:F83DFF* + OUI:F842FB* + ID_OUI_FROM_DATABASE=Yasuda Joho Co.,ltd. + ++OUI:F84360* ++ ID_OUI_FROM_DATABASE=INGENICO ++ + OUI:F845AD* + ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. + +@@ -72037,12 +72265,18 @@ OUI:F8AC6D* + OUI:F8B156* + ID_OUI_FROM_DATABASE=Dell Inc + ++OUI:F8B2F3* ++ ID_OUI_FROM_DATABASE=GUANGZHOU BOSMA TECHNOLOGY CO.,LTD ++ + OUI:F8B599* + ID_OUI_FROM_DATABASE=Guangzhou CHNAVS Digital Technology Co.,Ltd + + OUI:F8BC12* + ID_OUI_FROM_DATABASE=Dell Inc + ++OUI:F8BC41* ++ ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited ++ + OUI:F8C001* + ID_OUI_FROM_DATABASE=Juniper Networks + +@@ -72310,6 +72544,9 @@ OUI:FC6198* + OUI:FC626E* + ID_OUI_FROM_DATABASE=Beijing MDC Telecom + ++OUI:FC62B9* ++ ID_OUI_FROM_DATABASE=ALPS ERECTRIC CO.,LTD ++ + OUI:FC683E* + ID_OUI_FROM_DATABASE=Directed Perception, Inc + +diff --git a/hwdb/20-pci-vendor-model.hwdb b/hwdb/20-pci-vendor-model.hwdb +index 3bcdbc0d1f..1b98b1d2e7 100644 +--- a/hwdb/20-pci-vendor-model.hwdb ++++ b/hwdb/20-pci-vendor-model.hwdb +@@ -7892,6 +7892,9 @@ pci:v00001002d0000692B* + pci:v00001002d0000692F* + ID_MODEL_FROM_DATABASE=Tonga XT GL [FirePro W8100] + ++pci:v00001002d00006939* ++ ID_MODEL_FROM_DATABASE=Tonga PRO [Radeon R9 285] ++ + pci:v00001002d0000700F* + ID_MODEL_FROM_DATABASE=RS100 AGP Bridge + +@@ -17466,7 +17469,7 @@ pci:v00001093d00000162* + ID_MODEL_FROM_DATABASE=PCI-MIO-16XE-50 + + pci:v00001093d00001150* +- ID_MODEL_FROM_DATABASE=PCI-DIO-32HS High Speed Digital I/O Board ++ ID_MODEL_FROM_DATABASE=PCI-6533 (PCI-DIO-32HS) + + pci:v00001093d00001170* + ID_MODEL_FROM_DATABASE=PCI-MIO-16XE-10 +@@ -17481,22 +17484,31 @@ pci:v00001093d000011B0* + ID_MODEL_FROM_DATABASE=PXI-6070E + + pci:v00001093d000011C0* +- ID_MODEL_FROM_DATABASE=PXI-6040e ++ ID_MODEL_FROM_DATABASE=PXI-6040E + + pci:v00001093d000011D0* +- ID_MODEL_FROM_DATABASE=PXI-6030e ++ ID_MODEL_FROM_DATABASE=PXI-6030E + + pci:v00001093d00001270* +- ID_MODEL_FROM_DATABASE=PCI-6032e ++ ID_MODEL_FROM_DATABASE=PCI-6032E ++ ++pci:v00001093d00001290* ++ ID_MODEL_FROM_DATABASE=PCI-6704 ++ ++pci:v00001093d000012B0* ++ ID_MODEL_FROM_DATABASE=PCI-6534 + + pci:v00001093d00001310* + ID_MODEL_FROM_DATABASE=PCI-6602 + ++pci:v00001093d00001320* ++ ID_MODEL_FROM_DATABASE=PXI-6533 ++ + pci:v00001093d00001330* + ID_MODEL_FROM_DATABASE=PCI-6031E + + pci:v00001093d00001340* +- ID_MODEL_FROM_DATABASE=PCI-6033e ++ ID_MODEL_FROM_DATABASE=PCI-6033E + + pci:v00001093d00001350* + ID_MODEL_FROM_DATABASE=PCI-6071E +@@ -17504,6 +17516,12 @@ pci:v00001093d00001350* + pci:v00001093d00001360* + ID_MODEL_FROM_DATABASE=PXI-6602 + ++pci:v00001093d000013C0* ++ ID_MODEL_FROM_DATABASE=PXI-6508 ++ ++pci:v00001093d00001490* ++ ID_MODEL_FROM_DATABASE=PXI-6534 ++ + pci:v00001093d000014E0* + ID_MODEL_FROM_DATABASE=PCI-6110 + +@@ -17519,6 +17537,9 @@ pci:v00001093d000015B0* + pci:v00001093d00001710* + ID_MODEL_FROM_DATABASE=PXI-6509 + ++pci:v00001093d000017C0* ++ ID_MODEL_FROM_DATABASE=PXI-5690 ++ + pci:v00001093d000017D0* + ID_MODEL_FROM_DATABASE=PCI-6503 + +@@ -17534,6 +17555,33 @@ pci:v00001093d000018B0* + pci:v00001093d000018C0* + ID_MODEL_FROM_DATABASE=PXI-6052E + ++pci:v00001093d00001920* ++ ID_MODEL_FROM_DATABASE=PXI-6704 ++ ++pci:v00001093d00001930* ++ ID_MODEL_FROM_DATABASE=PCI-6040E ++ ++pci:v00001093d000019C0* ++ ID_MODEL_FROM_DATABASE=PCI-4472 ++ ++pci:v00001093d00001AA0* ++ ID_MODEL_FROM_DATABASE=PXI-4110 ++ ++pci:v00001093d00001AD0* ++ ID_MODEL_FROM_DATABASE=PCI-6133 ++ ++pci:v00001093d00001AE0* ++ ID_MODEL_FROM_DATABASE=PXI-6133 ++ ++pci:v00001093d00001E30* ++ ID_MODEL_FROM_DATABASE=PCI-6624 ++ ++pci:v00001093d00001E40* ++ ID_MODEL_FROM_DATABASE=PXI-6624 ++ ++pci:v00001093d00001E50* ++ ID_MODEL_FROM_DATABASE=PXI-5404 ++ + pci:v00001093d00002410* + ID_MODEL_FROM_DATABASE=PCI-6733 + +@@ -17543,12 +17591,42 @@ pci:v00001093d00002420* + pci:v00001093d00002430* + ID_MODEL_FROM_DATABASE=PCI-6731 + ++pci:v00001093d00002470* ++ ID_MODEL_FROM_DATABASE=PCI-4474 ++ ++pci:v00001093d000024A0* ++ ID_MODEL_FROM_DATABASE=PCI-4065 ++ ++pci:v00001093d000024B0* ++ ID_MODEL_FROM_DATABASE=PXI-4200 ++ ++pci:v00001093d000024F0* ++ ID_MODEL_FROM_DATABASE=PXI-4472 ++ ++pci:v00001093d00002510* ++ ID_MODEL_FROM_DATABASE=PCI-4472 ++ ++pci:v00001093d00002520* ++ ID_MODEL_FROM_DATABASE=PCI-4474 ++ ++pci:v00001093d000027A0* ++ ID_MODEL_FROM_DATABASE=PCI-6123 ++ ++pci:v00001093d000027B0* ++ ID_MODEL_FROM_DATABASE=PXI-6123 ++ + pci:v00001093d00002880* + ID_MODEL_FROM_DATABASE=DAQCard-6601 + + pci:v00001093d00002890* + ID_MODEL_FROM_DATABASE=PCI-6036E + ++pci:v00001093d000028A0* ++ ID_MODEL_FROM_DATABASE=PXI-4461 ++ ++pci:v00001093d000028B0* ++ ID_MODEL_FROM_DATABASE=PCI-6013 ++ + pci:v00001093d000028C0* + ID_MODEL_FROM_DATABASE=PCI-6014 + +@@ -17558,6 +17636,12 @@ pci:v00001093d000028D0* + pci:v00001093d000028E0* + ID_MODEL_FROM_DATABASE=PXI-5122 + ++pci:v00001093d000029F0* ++ ID_MODEL_FROM_DATABASE=PXI-7334 ++ ++pci:v00001093d00002A00* ++ ID_MODEL_FROM_DATABASE=PXI-7344 ++ + pci:v00001093d00002A60* + ID_MODEL_FROM_DATABASE=PCI-6023E + +@@ -17568,7 +17652,13 @@ pci:v00001093d00002A80* + ID_MODEL_FROM_DATABASE=PCI-6025E + + pci:v00001093d00002AB0* +- ID_MODEL_FROM_DATABASE=PXI-6025e ++ ID_MODEL_FROM_DATABASE=PXI-6025E ++ ++pci:v00001093d00002B10* ++ ID_MODEL_FROM_DATABASE=PXI-6527 ++ ++pci:v00001093d00002B20* ++ ID_MODEL_FROM_DATABASE=PCI-6527 + + pci:v00001093d00002B80* + ID_MODEL_FROM_DATABASE=PXI-6713 +@@ -17585,15 +17675,75 @@ pci:v00001093d00002C70* + pci:v00001093d00002C80* + ID_MODEL_FROM_DATABASE=PCI-6035E + ++pci:v00001093d00002C90* ++ ID_MODEL_FROM_DATABASE=PCI-6703 ++ + pci:v00001093d00002CA0* + ID_MODEL_FROM_DATABASE=PCI-6034E + ++pci:v00001093d00002CB0* ++ ID_MODEL_FROM_DATABASE=PCI-7344 ++ + pci:v00001093d00002CC0* + ID_MODEL_FROM_DATABASE=PXI-6608 + ++pci:v00001093d00002D20* ++ ID_MODEL_FROM_DATABASE=PXI-5600 ++ + pci:v00001093d00002DB0* + ID_MODEL_FROM_DATABASE=PCI-6608 + ++pci:v00001093d00002DC0* ++ ID_MODEL_FROM_DATABASE=PCI-4070 ++ ++pci:v00001093d00002DD0* ++ ID_MODEL_FROM_DATABASE=PXI-4070 ++ ++pci:v00001093d00002EB0* ++ ID_MODEL_FROM_DATABASE=PXI-4472 ++ ++pci:v00001093d00002EC0* ++ ID_MODEL_FROM_DATABASE=PXI-6115 ++ ++pci:v00001093d00002ED0* ++ ID_MODEL_FROM_DATABASE=PCI-6115 ++ ++pci:v00001093d00002EE0* ++ ID_MODEL_FROM_DATABASE=PXI-6120 ++ ++pci:v00001093d00002EF0* ++ ID_MODEL_FROM_DATABASE=PCI-6120 ++ ++pci:v00001093d00002FD1* ++ ID_MODEL_FROM_DATABASE=PCI-7334 ++ ++pci:v00001093d00002FD2* ++ ID_MODEL_FROM_DATABASE=PCI-7350 ++ ++pci:v00001093d00002FD3* ++ ID_MODEL_FROM_DATABASE=PCI-7342 ++ ++pci:v00001093d00002FD5* ++ ID_MODEL_FROM_DATABASE=PXI-7350 ++ ++pci:v00001093d00002FD6* ++ ID_MODEL_FROM_DATABASE=PXI-7342 ++ ++pci:v00001093d00007003* ++ ID_MODEL_FROM_DATABASE=PCI-6551 ++ ++pci:v00001093d00007004* ++ ID_MODEL_FROM_DATABASE=PXI-6551 ++ ++pci:v00001093d0000700B* ++ ID_MODEL_FROM_DATABASE=PXI-5421 ++ ++pci:v00001093d0000700C* ++ ID_MODEL_FROM_DATABASE=PCI-5421 ++ ++pci:v00001093d00007023* ++ ID_MODEL_FROM_DATABASE=PXI-2593 ++ + pci:v00001093d0000702C* + ID_MODEL_FROM_DATABASE=PXI-7831R + +@@ -17606,23 +17756,152 @@ pci:v00001093d0000702E* + pci:v00001093d0000702F* + ID_MODEL_FROM_DATABASE=PCI-7811R + ++pci:v00001093d00007030* ++ ID_MODEL_FROM_DATABASE=PCI-CAN (Series 2) ++ ++pci:v00001093d00007031* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/2 (Series 2) ++ ++pci:v00001093d00007032* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/LS (Series 2) ++ ++pci:v00001093d00007033* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/LS2 (Series 2) ++ ++pci:v00001093d00007034* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/DS (Series 2) ++ ++pci:v00001093d00007035* ++ ID_MODEL_FROM_DATABASE=PXI-8460 (Series 2, 1 port) ++ ++pci:v00001093d00007036* ++ ID_MODEL_FROM_DATABASE=PXI-8460 (Series 2, 2 ports) ++ ++pci:v00001093d00007037* ++ ID_MODEL_FROM_DATABASE=PXI-8461 (Series 2, 1 port) ++ ++pci:v00001093d00007038* ++ ID_MODEL_FROM_DATABASE=PXI-8461 (Series 2, 2 ports) ++ ++pci:v00001093d00007039* ++ ID_MODEL_FROM_DATABASE=PXI-8462 (Series 2) ++ ++pci:v00001093d0000703F* ++ ID_MODEL_FROM_DATABASE=PXI-2566 ++ ++pci:v00001093d00007040* ++ ID_MODEL_FROM_DATABASE=PXI-2567 ++ ++pci:v00001093d00007044* ++ ID_MODEL_FROM_DATABASE=MXI-4 Connection Monitor ++ ++pci:v00001093d00007047* ++ ID_MODEL_FROM_DATABASE=PXI-6653 ++ ++pci:v00001093d0000704C* ++ ID_MODEL_FROM_DATABASE=PXI-2530 ++ ++pci:v00001093d0000704F* ++ ID_MODEL_FROM_DATABASE=PXI-4220 ++ ++pci:v00001093d00007050* ++ ID_MODEL_FROM_DATABASE=PXI-4204 ++ + pci:v00001093d00007055* + ID_MODEL_FROM_DATABASE=PXI-7830R + + pci:v00001093d00007056* + ID_MODEL_FROM_DATABASE=PCI-7830R + ++pci:v00001093d0000705A* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/XS (Series 2) ++ ++pci:v00001093d0000705B* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/XS2 (Series 2) ++ ++pci:v00001093d0000705C* ++ ID_MODEL_FROM_DATABASE=PXI-8464 (Series 2, 1 port) ++ ++pci:v00001093d0000705D* ++ ID_MODEL_FROM_DATABASE=PXI-8464 (Series 2, 2 ports) ++ ++pci:v00001093d0000705E* ++ ID_MODEL_FROM_DATABASE=cRIO-9102 ++ ++pci:v00001093d00007060* ++ ID_MODEL_FROM_DATABASE=PXI-5610 ++ ++pci:v00001093d00007064* ++ ID_MODEL_FROM_DATABASE=PXI-1045 Trigger Routing Module ++ ++pci:v00001093d00007065* ++ ID_MODEL_FROM_DATABASE=PXI-6652 ++ ++pci:v00001093d00007066* ++ ID_MODEL_FROM_DATABASE=PXI-6651 ++ ++pci:v00001093d00007067* ++ ID_MODEL_FROM_DATABASE=PXI-2529 ++ ++pci:v00001093d00007068* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/SW (Series 2) ++ ++pci:v00001093d00007069* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/SW2 (Series 2) ++ ++pci:v00001093d0000706A* ++ ID_MODEL_FROM_DATABASE=PXI-8463 (Series 2, 1 port) ++ ++pci:v00001093d0000706B* ++ ID_MODEL_FROM_DATABASE=PXI-8463 (Series 2, 2 ports) ++ ++pci:v00001093d00007073* ++ ID_MODEL_FROM_DATABASE=PCI-6723 ++ + pci:v00001093d00007074* + ID_MODEL_FROM_DATABASE=PXI-7833R + ++pci:v00001093d00007075* ++ ID_MODEL_FROM_DATABASE=PXI-6552 ++ ++pci:v00001093d00007076* ++ ID_MODEL_FROM_DATABASE=PCI-6552 ++ ++pci:v00001093d0000707C* ++ ID_MODEL_FROM_DATABASE=PXI-1428 ++ ++pci:v00001093d0000707E* ++ ID_MODEL_FROM_DATABASE=PXI-4462 ++ ++pci:v00001093d00007080* ++ ID_MODEL_FROM_DATABASE=PXI-8430/2 (RS-232) Interface ++ ++pci:v00001093d00007081* ++ ID_MODEL_FROM_DATABASE=PXI-8431/2 (RS-485) Interface ++ + pci:v00001093d00007083* + ID_MODEL_FROM_DATABASE=PCI-7833R + + pci:v00001093d00007085* + ID_MODEL_FROM_DATABASE=PCI-6509 + ++pci:v00001093d00007086* ++ ID_MODEL_FROM_DATABASE=PXI-6528 ++ ++pci:v00001093d00007087* ++ ID_MODEL_FROM_DATABASE=PCI-6515 ++ ++pci:v00001093d00007088* ++ ID_MODEL_FROM_DATABASE=PCI-6514 ++ ++pci:v00001093d0000708C* ++ ID_MODEL_FROM_DATABASE=PXI-2568 ++ ++pci:v00001093d0000708D* ++ ID_MODEL_FROM_DATABASE=PXI-2569 ++ + pci:v00001093d000070A9* +- ID_MODEL_FROM_DATABASE=PCI-6528 (Digital I/O at 60V) ++ ID_MODEL_FROM_DATABASE=PCI-6528 + + pci:v00001093d000070AA* + ID_MODEL_FROM_DATABASE=PCI-6229 +@@ -17633,6 +17912,9 @@ pci:v00001093d000070AB* + pci:v00001093d000070AC* + ID_MODEL_FROM_DATABASE=PCI-6289 + ++pci:v00001093d000070AD* ++ ID_MODEL_FROM_DATABASE=PXI-6251 ++ + pci:v00001093d000070AE* + ID_MODEL_FROM_DATABASE=PXI-6220 + +@@ -17642,9 +17924,21 @@ pci:v00001093d000070AF* + pci:v00001093d000070B0* + ID_MODEL_FROM_DATABASE=PCI-6220 + ++pci:v00001093d000070B1* ++ ID_MODEL_FROM_DATABASE=PXI-6229 ++ ++pci:v00001093d000070B2* ++ ID_MODEL_FROM_DATABASE=PXI-6259 ++ ++pci:v00001093d000070B3* ++ ID_MODEL_FROM_DATABASE=PXI-6289 ++ + pci:v00001093d000070B4* + ID_MODEL_FROM_DATABASE=PCI-6250 + ++pci:v00001093d000070B5* ++ ID_MODEL_FROM_DATABASE=PXI-6221 ++ + pci:v00001093d000070B6* + ID_MODEL_FROM_DATABASE=PCI-6280 + +@@ -17652,7 +17946,16 @@ pci:v00001093d000070B7* + ID_MODEL_FROM_DATABASE=PCI-6254 + + pci:v00001093d000070B8* +- ID_MODEL_FROM_DATABASE=PCI-6251 [M Series - High Speed Multifunction DAQ] ++ ID_MODEL_FROM_DATABASE=PCI-6251 ++ ++pci:v00001093d000070B9* ++ ID_MODEL_FROM_DATABASE=PXI-6250 ++ ++pci:v00001093d000070BA* ++ ID_MODEL_FROM_DATABASE=PXI-6254 ++ ++pci:v00001093d000070BB* ++ ID_MODEL_FROM_DATABASE=PXI-6280 + + pci:v00001093d000070BC* + ID_MODEL_FROM_DATABASE=PCI-6284 +@@ -17660,12 +17963,144 @@ pci:v00001093d000070BC* + pci:v00001093d000070BD* + ID_MODEL_FROM_DATABASE=PCI-6281 + ++pci:v00001093d000070BE* ++ ID_MODEL_FROM_DATABASE=PXI-6284 ++ + pci:v00001093d000070BF* + ID_MODEL_FROM_DATABASE=PXI-6281 + + pci:v00001093d000070C0* + ID_MODEL_FROM_DATABASE=PCI-6143 + ++pci:v00001093d000070C3* ++ ID_MODEL_FROM_DATABASE=PCI-6511 ++ ++pci:v00001093d000070C4* ++ ID_MODEL_FROM_DATABASE=PXI-7330 ++ ++pci:v00001093d000070C5* ++ ID_MODEL_FROM_DATABASE=PXI-7340 ++ ++pci:v00001093d000070C6* ++ ID_MODEL_FROM_DATABASE=PCI-7330 ++ ++pci:v00001093d000070C7* ++ ID_MODEL_FROM_DATABASE=PCI-7340 ++ ++pci:v00001093d000070C8* ++ ID_MODEL_FROM_DATABASE=PCI-6513 ++ ++pci:v00001093d000070C9* ++ ID_MODEL_FROM_DATABASE=PXI-6515 ++ ++pci:v00001093d000070CA* ++ ID_MODEL_FROM_DATABASE=PCI-1405 ++ ++pci:v00001093d000070CC* ++ ID_MODEL_FROM_DATABASE=PCI-6512 ++ ++pci:v00001093d000070CD* ++ ID_MODEL_FROM_DATABASE=PXI-6514 ++ ++pci:v00001093d000070CE* ++ ID_MODEL_FROM_DATABASE=PXI-1405 ++ ++pci:v00001093d000070CF* ++ ID_MODEL_FROM_DATABASE=PCIe-GPIB ++ ++pci:v00001093d000070D0* ++ ID_MODEL_FROM_DATABASE=PXI-2570 ++ ++pci:v00001093d000070D1* ++ ID_MODEL_FROM_DATABASE=PXI-6513 ++ ++pci:v00001093d000070D2* ++ ID_MODEL_FROM_DATABASE=PXI-6512 ++ ++pci:v00001093d000070D3* ++ ID_MODEL_FROM_DATABASE=PXI-6511 ++ ++pci:v00001093d000070D4* ++ ID_MODEL_FROM_DATABASE=PCI-6722 ++ ++pci:v00001093d000070D6* ++ ID_MODEL_FROM_DATABASE=PXI-4072 ++ ++pci:v00001093d000070D7* ++ ID_MODEL_FROM_DATABASE=PXI-6541 ++ ++pci:v00001093d000070D8* ++ ID_MODEL_FROM_DATABASE=PXI-6542 ++ ++pci:v00001093d000070D9* ++ ID_MODEL_FROM_DATABASE=PCI-6541 ++ ++pci:v00001093d000070DA* ++ ID_MODEL_FROM_DATABASE=PCI-6542 ++ ++pci:v00001093d000070DB* ++ ID_MODEL_FROM_DATABASE=PCI-8430/2 (RS-232) Interface ++ ++pci:v00001093d000070DC* ++ ID_MODEL_FROM_DATABASE=PCI-8431/2 (RS-485) Interface ++ ++pci:v00001093d000070DD* ++ ID_MODEL_FROM_DATABASE=PXI-8430/4 (RS-232) Interface ++ ++pci:v00001093d000070DE* ++ ID_MODEL_FROM_DATABASE=PXI-8431/4 (RS-485) Interface ++ ++pci:v00001093d000070DF* ++ ID_MODEL_FROM_DATABASE=PCI-8430/4 (RS-232) Interface ++ ++pci:v00001093d000070E0* ++ ID_MODEL_FROM_DATABASE=PCI-8431/4 (RS-485) Interface ++ ++pci:v00001093d000070E1* ++ ID_MODEL_FROM_DATABASE=PXI-2532 ++ ++pci:v00001093d000070E2* ++ ID_MODEL_FROM_DATABASE=PXI-8430/8 (RS-232) Interface ++ ++pci:v00001093d000070E3* ++ ID_MODEL_FROM_DATABASE=PXI-8431/8 (RS-485) Interface ++ ++pci:v00001093d000070E4* ++ ID_MODEL_FROM_DATABASE=PCI-8430/8 (RS-232) Interface ++ ++pci:v00001093d000070E5* ++ ID_MODEL_FROM_DATABASE=PCI-8431/8 (RS-485) Interface ++ ++pci:v00001093d000070E6* ++ ID_MODEL_FROM_DATABASE=PXI-8430/16 (RS-232) Interface ++ ++pci:v00001093d000070E7* ++ ID_MODEL_FROM_DATABASE=PCI-8430/16 (RS-232) Interface ++ ++pci:v00001093d000070E8* ++ ID_MODEL_FROM_DATABASE=PXI-8432/2 (Isolated RS-232) Interface ++ ++pci:v00001093d000070E9* ++ ID_MODEL_FROM_DATABASE=PXI-8433/2 (Isolated RS-485) Interface ++ ++pci:v00001093d000070EA* ++ ID_MODEL_FROM_DATABASE=PCI-8432/2 (Isolated RS-232) Interface ++ ++pci:v00001093d000070EB* ++ ID_MODEL_FROM_DATABASE=PCI-8433/2 (Isolated RS-485) Interface ++ ++pci:v00001093d000070EC* ++ ID_MODEL_FROM_DATABASE=PXI-8432/4 (Isolated RS-232) Interface ++ ++pci:v00001093d000070ED* ++ ID_MODEL_FROM_DATABASE=PXI-8433/4 (Isolated RS-485) Interface ++ ++pci:v00001093d000070EE* ++ ID_MODEL_FROM_DATABASE=PCI-8432/4 (Isolated RS-232) Interface ++ ++pci:v00001093d000070EF* ++ ID_MODEL_FROM_DATABASE=PCI-8433/4 (Isolated RS-485) Interface ++ + pci:v00001093d000070F0* + ID_MODEL_FROM_DATABASE=PXI-5922 + +@@ -17675,57 +18110,363 @@ pci:v00001093d000070F1* + pci:v00001093d000070F2* + ID_MODEL_FROM_DATABASE=PCI-6224 + ++pci:v00001093d000070F3* ++ ID_MODEL_FROM_DATABASE=PXI-6224 ++ ++pci:v00001093d000070F6* ++ ID_MODEL_FROM_DATABASE=cRIO-9101 ++ ++pci:v00001093d000070F7* ++ ID_MODEL_FROM_DATABASE=cRIO-9103 ++ ++pci:v00001093d000070F8* ++ ID_MODEL_FROM_DATABASE=cRIO-9104 ++ ++pci:v00001093d000070FF* ++ ID_MODEL_FROM_DATABASE=PXI-6723 ++ ++pci:v00001093d00007100* ++ ID_MODEL_FROM_DATABASE=PXI-6722 ++ ++pci:v00001093d00007104* ++ ID_MODEL_FROM_DATABASE=PCIx-1429 ++ ++pci:v00001093d00007105* ++ ID_MODEL_FROM_DATABASE=PCIe-1429 ++ ++pci:v00001093d0000710A* ++ ID_MODEL_FROM_DATABASE=PXI-4071 ++ ++pci:v00001093d0000710D* ++ ID_MODEL_FROM_DATABASE=PXI-6143 ++ ++pci:v00001093d0000710E* ++ ID_MODEL_FROM_DATABASE=PCIe-GPIB ++ ++pci:v00001093d0000710F* ++ ID_MODEL_FROM_DATABASE=PXI-5422 ++ ++pci:v00001093d00007110* ++ ID_MODEL_FROM_DATABASE=PCI-5422 ++ ++pci:v00001093d00007111* ++ ID_MODEL_FROM_DATABASE=PXI-5441 ++ ++pci:v00001093d00007119* ++ ID_MODEL_FROM_DATABASE=PXI-6561 ++ ++pci:v00001093d0000711A* ++ ID_MODEL_FROM_DATABASE=PXI-6562 ++ ++pci:v00001093d0000711B* ++ ID_MODEL_FROM_DATABASE=PCI-6561 ++ ++pci:v00001093d0000711C* ++ ID_MODEL_FROM_DATABASE=PCI-6562 ++ ++pci:v00001093d00007120* ++ ID_MODEL_FROM_DATABASE=PCI-7390 ++ + pci:v00001093d00007121* + ID_MODEL_FROM_DATABASE=PXI-5122EX + + pci:v00001093d00007122* + ID_MODEL_FROM_DATABASE=PCI-5122EX + ++pci:v00001093d00007123* ++ ID_MODEL_FROM_DATABASE=PXIe-5653 ++ ++pci:v00001093d00007124* ++ ID_MODEL_FROM_DATABASE=PCI-6510 ++ ++pci:v00001093d00007125* ++ ID_MODEL_FROM_DATABASE=PCI-6516 ++ ++pci:v00001093d00007126* ++ ID_MODEL_FROM_DATABASE=PCI-6517 ++ ++pci:v00001093d00007127* ++ ID_MODEL_FROM_DATABASE=PCI-6518 ++ ++pci:v00001093d00007128* ++ ID_MODEL_FROM_DATABASE=PCI-6519 ++ ++pci:v00001093d00007137* ++ ID_MODEL_FROM_DATABASE=PXI-2575 ++ ++pci:v00001093d0000713C* ++ ID_MODEL_FROM_DATABASE=PXI-2585 ++ ++pci:v00001093d0000713D* ++ ID_MODEL_FROM_DATABASE=PXI-2586 ++ ++pci:v00001093d00007142* ++ ID_MODEL_FROM_DATABASE=PXI-4224 ++ + pci:v00001093d00007144* +- ID_MODEL_FROM_DATABASE=PXI-5124 (12-bit 200 MS/s Digitizer) ++ ID_MODEL_FROM_DATABASE=PXI-5124 + + pci:v00001093d00007145* + ID_MODEL_FROM_DATABASE=PCI-5124 + ++pci:v00001093d00007146* ++ ID_MODEL_FROM_DATABASE=PCI-6132 ++ ++pci:v00001093d00007147* ++ ID_MODEL_FROM_DATABASE=PXI-6132 ++ ++pci:v00001093d00007148* ++ ID_MODEL_FROM_DATABASE=PCI-6122 ++ ++pci:v00001093d00007149* ++ ID_MODEL_FROM_DATABASE=PXI-6122 ++ + pci:v00001093d0000714C* + ID_MODEL_FROM_DATABASE=PXI-5114 + + pci:v00001093d0000714D* + ID_MODEL_FROM_DATABASE=PCI-5114 + ++pci:v00001093d00007150* ++ ID_MODEL_FROM_DATABASE=PXI-2564 ++ + pci:v00001093d00007152* + ID_MODEL_FROM_DATABASE=PCI-5640R + ++pci:v00001093d00007156* ++ ID_MODEL_FROM_DATABASE=PXI-1044 Trigger Routing Module ++ ++pci:v00001093d0000715D* ++ ID_MODEL_FROM_DATABASE=PCI-1426 ++ ++pci:v00001093d00007167* ++ ID_MODEL_FROM_DATABASE=PXI-5412 ++ ++pci:v00001093d00007168* ++ ID_MODEL_FROM_DATABASE=PCI-5412 ++ ++pci:v00001093d0000716B* ++ ID_MODEL_FROM_DATABASE=PCI-6230 ++ + pci:v00001093d0000716C* + ID_MODEL_FROM_DATABASE=PCI-6225 + ++pci:v00001093d0000716D* ++ ID_MODEL_FROM_DATABASE=PXI-6225 ++ ++pci:v00001093d0000716F* ++ ID_MODEL_FROM_DATABASE=PCI-4461 ++ ++pci:v00001093d00007170* ++ ID_MODEL_FROM_DATABASE=PCI-4462 ++ ++pci:v00001093d00007171* ++ ID_MODEL_FROM_DATABASE=PCI-6010 ++ ++pci:v00001093d00007174* ++ ID_MODEL_FROM_DATABASE=PXI-8360 ++ ++pci:v00001093d00007177* ++ ID_MODEL_FROM_DATABASE=PXI-6230 ++ + pci:v00001093d0000717D* +- ID_MODEL_FROM_DATABASE=PCIE-6251 ++ ID_MODEL_FROM_DATABASE=PCIe-6251 + + pci:v00001093d0000717F* + ID_MODEL_FROM_DATABASE=PCIe-6259 + ++pci:v00001093d00007187* ++ ID_MODEL_FROM_DATABASE=PCI-1410 ++ ++pci:v00001093d0000718B* ++ ID_MODEL_FROM_DATABASE=PCI-6521 ++ ++pci:v00001093d0000718C* ++ ID_MODEL_FROM_DATABASE=PXI-6521 ++ ++pci:v00001093d00007191* ++ ID_MODEL_FROM_DATABASE=PCI-6154 ++ + pci:v00001093d00007193* + ID_MODEL_FROM_DATABASE=PXI-7813R + + pci:v00001093d00007194* + ID_MODEL_FROM_DATABASE=PCI-7813R + ++pci:v00001093d00007195* ++ ID_MODEL_FROM_DATABASE=PCI-8254R ++ ++pci:v00001093d00007197* ++ ID_MODEL_FROM_DATABASE=PXI-5402 ++ ++pci:v00001093d00007198* ++ ID_MODEL_FROM_DATABASE=PCI-5402 ++ ++pci:v00001093d0000719F* ++ ID_MODEL_FROM_DATABASE=PCIe-6535 ++ ++pci:v00001093d000071A0* ++ ID_MODEL_FROM_DATABASE=PCIe-6536 ++ ++pci:v00001093d000071A3* ++ ID_MODEL_FROM_DATABASE=PXI-5650 ++ ++pci:v00001093d000071A4* ++ ID_MODEL_FROM_DATABASE=PXI-5652 ++ ++pci:v00001093d000071A5* ++ ID_MODEL_FROM_DATABASE=PXI-2594 ++ ++pci:v00001093d000071A7* ++ ID_MODEL_FROM_DATABASE=PXI-2595 ++ ++pci:v00001093d000071A9* ++ ID_MODEL_FROM_DATABASE=PXI-2596 ++ ++pci:v00001093d000071AA* ++ ID_MODEL_FROM_DATABASE=PXI-2597 ++ ++pci:v00001093d000071AB* ++ ID_MODEL_FROM_DATABASE=PXI-2598 ++ ++pci:v00001093d000071AC* ++ ID_MODEL_FROM_DATABASE=PXI-2599 ++ ++pci:v00001093d000071AD* ++ ID_MODEL_FROM_DATABASE=PCI-GPIB+ ++ ++pci:v00001093d000071AE* ++ ID_MODEL_FROM_DATABASE=PCIe-1430 ++ ++pci:v00001093d000071B7* ++ ID_MODEL_FROM_DATABASE=PXI-1056 Trigger Routing Module ++ ++pci:v00001093d000071B8* ++ ID_MODEL_FROM_DATABASE=PXI-1045 Trigger Routing Module ++ ++pci:v00001093d000071B9* ++ ID_MODEL_FROM_DATABASE=PXI-1044 Trigger Routing Module ++ ++pci:v00001093d000071BB* ++ ID_MODEL_FROM_DATABASE=PXI-2584 ++ + pci:v00001093d000071BC* +- ID_MODEL_FROM_DATABASE=PCI-6221 (37pin) ++ ID_MODEL_FROM_DATABASE=PCI-6221 (37-pin) + +-pci:v00001093d000071D0* +- ID_MODEL_FROM_DATABASE=PXI-6143 ++pci:v00001093d000071BF* ++ ID_MODEL_FROM_DATABASE=PCIe-1427 ++ ++pci:v00001093d000071C5* ++ ID_MODEL_FROM_DATABASE=PCI-6520 ++ ++pci:v00001093d000071C6* ++ ID_MODEL_FROM_DATABASE=PXI-2576 ++ ++pci:v00001093d000071C7* ++ ID_MODEL_FROM_DATABASE=cRIO-9072 + + pci:v00001093d000071DC* + ID_MODEL_FROM_DATABASE=PCI-1588 + ++pci:v00001093d000071E0* ++ ID_MODEL_FROM_DATABASE=PCI-6255 ++ ++pci:v00001093d000071E1* ++ ID_MODEL_FROM_DATABASE=PXI-6255 ++ ++pci:v00001093d000071E2* ++ ID_MODEL_FROM_DATABASE=PXI-5406 ++ ++pci:v00001093d000071E3* ++ ID_MODEL_FROM_DATABASE=PCI-5406 ++ ++pci:v00001093d000071FC* ++ ID_MODEL_FROM_DATABASE=PXI-4022 ++ ++pci:v00001093d00007209* ++ ID_MODEL_FROM_DATABASE=PCI-6233 ++ ++pci:v00001093d0000720A* ++ ID_MODEL_FROM_DATABASE=PXI-6233 ++ ++pci:v00001093d0000720B* ++ ID_MODEL_FROM_DATABASE=PCI-6238 ++ ++pci:v00001093d0000720C* ++ ID_MODEL_FROM_DATABASE=PXI-6238 ++ + pci:v00001093d00007260* + ID_MODEL_FROM_DATABASE=PXI-5142 + + pci:v00001093d00007261* + ID_MODEL_FROM_DATABASE=PCI-5142 + ++pci:v00001093d0000726D* ++ ID_MODEL_FROM_DATABASE=PXI-5651 ++ ++pci:v00001093d00007273* ++ ID_MODEL_FROM_DATABASE=PXI-4461 ++ ++pci:v00001093d00007274* ++ ID_MODEL_FROM_DATABASE=PXI-4462 ++ ++pci:v00001093d00007279* ++ ID_MODEL_FROM_DATABASE=PCI-6232 ++ ++pci:v00001093d0000727A* ++ ID_MODEL_FROM_DATABASE=PXI-6232 ++ ++pci:v00001093d0000727B* ++ ID_MODEL_FROM_DATABASE=PCI-6239 ++ ++pci:v00001093d0000727C* ++ ID_MODEL_FROM_DATABASE=PXI-6239 ++ ++pci:v00001093d0000727E* ++ ID_MODEL_FROM_DATABASE=SMBus Controller ++ ++pci:v00001093d0000727Esv00001093sd000075AC* ++ ID_MODEL_FROM_DATABASE=SMBus Controller (PXIe-8388) ++ ++pci:v00001093d0000727Esv00001093sd000075AD* ++ ID_MODEL_FROM_DATABASE=SMBus Controller (PXIe-8389) ++ ++pci:v00001093d0000727Esv00001093sd00007650* ++ ID_MODEL_FROM_DATABASE=SMBus Controller (PXIe-8381) ++ ++pci:v00001093d0000727Esv00001093sd00008360* ++ ID_MODEL_FROM_DATABASE=SMBus Controller (PXIe-8360) ++ ++pci:v00001093d0000727Esv00001093sd00008370* ++ ID_MODEL_FROM_DATABASE=SMBus Controller (PXIe-8370) ++ ++pci:v00001093d0000727Esv00001093sd00008375* ++ ID_MODEL_FROM_DATABASE=SMBus Controller (PXIe-8375) ++ ++pci:v00001093d00007281* ++ ID_MODEL_FROM_DATABASE=PCI-6236 ++ ++pci:v00001093d00007282* ++ ID_MODEL_FROM_DATABASE=PXI-6236 ++ ++pci:v00001093d00007283* ++ ID_MODEL_FROM_DATABASE=PXI-2554 ++ ++pci:v00001093d00007288* ++ ID_MODEL_FROM_DATABASE=PXIe-5611 ++ ++pci:v00001093d00007293* ++ ID_MODEL_FROM_DATABASE=PCIe-8255R ++ ++pci:v00001093d0000729D* ++ ID_MODEL_FROM_DATABASE=cRIO-9074 ++ ++pci:v00001093d000072A4* ++ ID_MODEL_FROM_DATABASE=PCIe-4065 ++ ++pci:v00001093d000072A7* ++ ID_MODEL_FROM_DATABASE=PCIe-6537 ++ + pci:v00001093d000072A8* + ID_MODEL_FROM_DATABASE=PXI-5152 + +@@ -17741,21 +18482,117 @@ pci:v00001093d000072AB* + pci:v00001093d000072B8* + ID_MODEL_FROM_DATABASE=PXI-6682 + ++pci:v00001093d000072D0* ++ ID_MODEL_FROM_DATABASE=PXI-2545 ++ ++pci:v00001093d000072D1* ++ ID_MODEL_FROM_DATABASE=PXI-2546 ++ ++pci:v00001093d000072D2* ++ ID_MODEL_FROM_DATABASE=PXI-2547 ++ ++pci:v00001093d000072D3* ++ ID_MODEL_FROM_DATABASE=PXI-2548 ++ ++pci:v00001093d000072D4* ++ ID_MODEL_FROM_DATABASE=PXI-2549 ++ ++pci:v00001093d000072D5* ++ ID_MODEL_FROM_DATABASE=PXI-2555 ++ ++pci:v00001093d000072D6* ++ ID_MODEL_FROM_DATABASE=PXI-2556 ++ ++pci:v00001093d000072D7* ++ ID_MODEL_FROM_DATABASE=PXI-2557 ++ ++pci:v00001093d000072D8* ++ ID_MODEL_FROM_DATABASE=PXI-2558 ++ ++pci:v00001093d000072D9* ++ ID_MODEL_FROM_DATABASE=PXI-2559 ++ ++pci:v00001093d000072E8* ++ ID_MODEL_FROM_DATABASE=PXIe-6251 ++ ++pci:v00001093d000072E9* ++ ID_MODEL_FROM_DATABASE=PXIe-6259 ++ ++pci:v00001093d000072EF* ++ ID_MODEL_FROM_DATABASE=PXI-4498 ++ ++pci:v00001093d000072F0* ++ ID_MODEL_FROM_DATABASE=PXI-4496 ++ ++pci:v00001093d000072FB* ++ ID_MODEL_FROM_DATABASE=PXIe-6672 ++ ++pci:v00001093d0000730E* ++ ID_MODEL_FROM_DATABASE=PXI-4130 ++ + pci:v00001093d0000730F* + ID_MODEL_FROM_DATABASE=PXI-5922EX + + pci:v00001093d00007310* + ID_MODEL_FROM_DATABASE=PCI-5922EX + ++pci:v00001093d0000731C* ++ ID_MODEL_FROM_DATABASE=PXI-2535 ++ ++pci:v00001093d0000731D* ++ ID_MODEL_FROM_DATABASE=PXI-2536 ++ ++pci:v00001093d00007322* ++ ID_MODEL_FROM_DATABASE=PXIe-6124 ++ ++pci:v00001093d00007327* ++ ID_MODEL_FROM_DATABASE=PXI-6529 ++ ++pci:v00001093d00007331* ++ ID_MODEL_FROM_DATABASE=PXIe-5602 ++ ++pci:v00001093d00007332* ++ ID_MODEL_FROM_DATABASE=PXIe-5601 ++ + pci:v00001093d00007333* + ID_MODEL_FROM_DATABASE=PXI-5900 + ++pci:v00001093d00007335* ++ ID_MODEL_FROM_DATABASE=PXI-2533 ++ ++pci:v00001093d00007336* ++ ID_MODEL_FROM_DATABASE=PXI-2534 ++ ++pci:v00001093d00007342* ++ ID_MODEL_FROM_DATABASE=PXI-4461 ++ + pci:v00001093d00007349* + ID_MODEL_FROM_DATABASE=PXI-5154 + + pci:v00001093d0000734A* + ID_MODEL_FROM_DATABASE=PCI-5154 + ++pci:v00001093d00007357* ++ ID_MODEL_FROM_DATABASE=PXI-4065 ++ ++pci:v00001093d00007359* ++ ID_MODEL_FROM_DATABASE=PXI-4495 ++ ++pci:v00001093d00007370* ++ ID_MODEL_FROM_DATABASE=PXI-4461 ++ ++pci:v00001093d00007373* ++ ID_MODEL_FROM_DATABASE=sbRIO-9601 ++ ++pci:v00001093d00007374* ++ ID_MODEL_FROM_DATABASE=IOtech-9601 ++ ++pci:v00001093d00007375* ++ ID_MODEL_FROM_DATABASE=sbRIO-9602 ++ ++pci:v00001093d00007378* ++ ID_MODEL_FROM_DATABASE=sbRIO-9641 ++ + pci:v00001093d0000737D* + ID_MODEL_FROM_DATABASE=PXI-5124EX + +@@ -17786,9 +18623,126 @@ pci:v00001093d00007393* + pci:v00001093d00007394* + ID_MODEL_FROM_DATABASE=PCIe-7842R + ++pci:v00001093d00007397* ++ ID_MODEL_FROM_DATABASE=sbRIO-9611 ++ ++pci:v00001093d00007398* ++ ID_MODEL_FROM_DATABASE=sbRIO-9612 ++ ++pci:v00001093d00007399* ++ ID_MODEL_FROM_DATABASE=sbRIO-9631 ++ ++pci:v00001093d0000739A* ++ ID_MODEL_FROM_DATABASE=sbRIO-9632 ++ ++pci:v00001093d0000739B* ++ ID_MODEL_FROM_DATABASE=sbRIO-9642 ++ ++pci:v00001093d000073A1* ++ ID_MODEL_FROM_DATABASE=PXIe-4498 ++ ++pci:v00001093d000073A2* ++ ID_MODEL_FROM_DATABASE=PXIe-4496 ++ + pci:v00001093d000073A5* + ID_MODEL_FROM_DATABASE=PXIe-5641R + ++pci:v00001093d000073A7* ++ ID_MODEL_FROM_DATABASE=PXI-8250 Chassis Monitor Module ++ ++pci:v00001093d000073A8* ++ ID_MODEL_FROM_DATABASE=PXI-8511 CAN/LS ++ ++pci:v00001093d000073A9* ++ ID_MODEL_FROM_DATABASE=PXI-8511 CAN/LS ++ ++pci:v00001093d000073AA* ++ ID_MODEL_FROM_DATABASE=PXI-8512 CAN/HS ++ ++pci:v00001093d000073AB* ++ ID_MODEL_FROM_DATABASE=PXI-8512 CAN/HS ++ ++pci:v00001093d000073AC* ++ ID_MODEL_FROM_DATABASE=PXI-8513 CAN/XS ++ ++pci:v00001093d000073AD* ++ ID_MODEL_FROM_DATABASE=PXI-8513 CAN/XS ++ ++pci:v00001093d000073AF* ++ ID_MODEL_FROM_DATABASE=PXI-8516 LIN ++ ++pci:v00001093d000073B1* ++ ID_MODEL_FROM_DATABASE=PXI-8517 FlexRay ++ ++pci:v00001093d000073B2* ++ ID_MODEL_FROM_DATABASE=PXI-8531 CANopen ++ ++pci:v00001093d000073B3* ++ ID_MODEL_FROM_DATABASE=PXI-8531 CANopen ++ ++pci:v00001093d000073B4* ++ ID_MODEL_FROM_DATABASE=PXI-8532 DeviceNet ++ ++pci:v00001093d000073B5* ++ ID_MODEL_FROM_DATABASE=PXI-8532 DeviceNet ++ ++pci:v00001093d000073B6* ++ ID_MODEL_FROM_DATABASE=PCI-8511 CAN/LS ++ ++pci:v00001093d000073B7* ++ ID_MODEL_FROM_DATABASE=PCI-8511 CAN/LS ++ ++pci:v00001093d000073B8* ++ ID_MODEL_FROM_DATABASE=PCI-8512 CAN/HS ++ ++pci:v00001093d000073B9* ++ ID_MODEL_FROM_DATABASE=PCI-8512 CAN/HS ++ ++pci:v00001093d000073BA* ++ ID_MODEL_FROM_DATABASE=PCI-8513 CAN/XS ++ ++pci:v00001093d000073BB* ++ ID_MODEL_FROM_DATABASE=PCI-8513 CAN/XS ++ ++pci:v00001093d000073BD* ++ ID_MODEL_FROM_DATABASE=PCI-8516 LIN ++ ++pci:v00001093d000073BF* ++ ID_MODEL_FROM_DATABASE=PCI-8517 FlexRay ++ ++pci:v00001093d000073C0* ++ ID_MODEL_FROM_DATABASE=PCI-8531 CANopen ++ ++pci:v00001093d000073C1* ++ ID_MODEL_FROM_DATABASE=PCI-8531 CANopen ++ ++pci:v00001093d000073C2* ++ ID_MODEL_FROM_DATABASE=PCI-8532 DeviceNet ++ ++pci:v00001093d000073C3* ++ ID_MODEL_FROM_DATABASE=PCI-8532 DeviceNet ++ ++pci:v00001093d000073C5* ++ ID_MODEL_FROM_DATABASE=PXIe-2527 ++ ++pci:v00001093d000073C6* ++ ID_MODEL_FROM_DATABASE=PXIe-2529 ++ ++pci:v00001093d000073C8* ++ ID_MODEL_FROM_DATABASE=PXIe-2530 ++ ++pci:v00001093d000073C9* ++ ID_MODEL_FROM_DATABASE=PXIe-2532 ++ ++pci:v00001093d000073CA* ++ ID_MODEL_FROM_DATABASE=PXIe-2569 ++ ++pci:v00001093d000073CB* ++ ID_MODEL_FROM_DATABASE=PXIe-2575 ++ ++pci:v00001093d000073CC* ++ ID_MODEL_FROM_DATABASE=PXIe-2593 ++ + pci:v00001093d000073D5* + ID_MODEL_FROM_DATABASE=PXI-7951R + +@@ -17804,15 +18758,87 @@ pci:v00001093d000073E1* + pci:v00001093d000073EC* + ID_MODEL_FROM_DATABASE=PXI-7954R + ++pci:v00001093d000073ED* ++ ID_MODEL_FROM_DATABASE=cRIO-9073 ++ + pci:v00001093d000073F0* + ID_MODEL_FROM_DATABASE=PXI-5153 + + pci:v00001093d000073F1* + ID_MODEL_FROM_DATABASE=PCI-5153 + ++pci:v00001093d000073F4* ++ ID_MODEL_FROM_DATABASE=PXI-2515 ++ ++pci:v00001093d000073F6* ++ ID_MODEL_FROM_DATABASE=cRIO-9111 ++ ++pci:v00001093d000073F7* ++ ID_MODEL_FROM_DATABASE=cRIO-9112 ++ ++pci:v00001093d000073F8* ++ ID_MODEL_FROM_DATABASE=cRIO-9113 ++ ++pci:v00001093d000073F9* ++ ID_MODEL_FROM_DATABASE=cRIO-9114 ++ ++pci:v00001093d000073FA* ++ ID_MODEL_FROM_DATABASE=cRIO-9116 ++ ++pci:v00001093d000073FB* ++ ID_MODEL_FROM_DATABASE=cRIO-9118 ++ ++pci:v00001093d00007404* ++ ID_MODEL_FROM_DATABASE=PXI-4132 ++ + pci:v00001093d00007405* + ID_MODEL_FROM_DATABASE=PXIe-6674T + ++pci:v00001093d00007406* ++ ID_MODEL_FROM_DATABASE=PXIe-6674 ++ ++pci:v00001093d0000740E* ++ ID_MODEL_FROM_DATABASE=PCIe-8430/16 (RS-232) Interface ++ ++pci:v00001093d0000740F* ++ ID_MODEL_FROM_DATABASE=PCIe-8430/8 (RS-232) Interface ++ ++pci:v00001093d00007410* ++ ID_MODEL_FROM_DATABASE=PCIe-8431/16 (RS-485) Interface ++ ++pci:v00001093d00007411* ++ ID_MODEL_FROM_DATABASE=PCIe-8431/8 (RS-485) Interface ++ ++pci:v00001093d00007414* ++ ID_MODEL_FROM_DATABASE=PCIe-GPIB+ ++ ++pci:v00001093d0000741C* ++ ID_MODEL_FROM_DATABASE=PXI-5691 ++ ++pci:v00001093d0000741D* ++ ID_MODEL_FROM_DATABASE=PXI-5695 ++ ++pci:v00001093d0000743C* ++ ID_MODEL_FROM_DATABASE=CSC-3059 ++ ++pci:v00001093d00007448* ++ ID_MODEL_FROM_DATABASE=PXI-2510 ++ ++pci:v00001093d00007454* ++ ID_MODEL_FROM_DATABASE=PXI-2512 ++ ++pci:v00001093d00007455* ++ ID_MODEL_FROM_DATABASE=PXI-2514 ++ ++pci:v00001093d00007456* ++ ID_MODEL_FROM_DATABASE=PXIe-2512 ++ ++pci:v00001093d00007457* ++ ID_MODEL_FROM_DATABASE=PXIe-2514 ++ ++pci:v00001093d0000745A* ++ ID_MODEL_FROM_DATABASE=PXI-6682H ++ + pci:v00001093d0000745E* + ID_MODEL_FROM_DATABASE=PXI-5153EX + +@@ -17825,86 +18851,740 @@ pci:v00001093d00007460* + pci:v00001093d00007461* + ID_MODEL_FROM_DATABASE=PCI-5154EX + ++pci:v00001093d0000746D* ++ ID_MODEL_FROM_DATABASE=PXIe-5650 ++ ++pci:v00001093d0000746E* ++ ID_MODEL_FROM_DATABASE=PXIe-5651 ++ ++pci:v00001093d0000746F* ++ ID_MODEL_FROM_DATABASE=PXIe-5652 ++ ++pci:v00001093d00007472* ++ ID_MODEL_FROM_DATABASE=PXI-2800 ++ ++pci:v00001093d00007495* ++ ID_MODEL_FROM_DATABASE=PXIe-5603 ++ ++pci:v00001093d00007497* ++ ID_MODEL_FROM_DATABASE=PXIe-5605 ++ ++pci:v00001093d000074AE* ++ ID_MODEL_FROM_DATABASE=PXIe-2515 ++ ++pci:v00001093d000074B4* ++ ID_MODEL_FROM_DATABASE=PXI-2531 ++ ++pci:v00001093d000074B5* ++ ID_MODEL_FROM_DATABASE=PXIe-2531 ++ ++pci:v00001093d000074C1* ++ ID_MODEL_FROM_DATABASE=PXIe-8430/16 (RS-232) Interface ++ ++pci:v00001093d000074C2* ++ ID_MODEL_FROM_DATABASE=PXIe-8430/8 (RS-232) Interface ++ ++pci:v00001093d000074C3* ++ ID_MODEL_FROM_DATABASE=PXIe-8431/16 (RS-485) Interface ++ ++pci:v00001093d000074C4* ++ ID_MODEL_FROM_DATABASE=PXIe-8431/8 (RS-485) Interface ++ ++pci:v00001093d000074D5* ++ ID_MODEL_FROM_DATABASE=PXIe-5630 ++ ++pci:v00001093d000074D9* ++ ID_MODEL_FROM_DATABASE=PCIe-8432/2 (Isolated RS-232) Interface ++ ++pci:v00001093d000074DA* ++ ID_MODEL_FROM_DATABASE=PCIe-8433/2 (Isolated RS-485) Interface ++ ++pci:v00001093d000074DB* ++ ID_MODEL_FROM_DATABASE=PCIe-8432/4 (Isolated RS-232) Interface ++ ++pci:v00001093d000074DC* ++ ID_MODEL_FROM_DATABASE=PCIe-8433/4 (Isolated RS-485) Interface ++ ++pci:v00001093d000074E8* ++ ID_MODEL_FROM_DATABASE=NI 9148 ++ ++pci:v00001093d00007515* ++ ID_MODEL_FROM_DATABASE=PCIe-8430/2 (RS-232) Interface ++ ++pci:v00001093d00007516* ++ ID_MODEL_FROM_DATABASE=PCIe-8430/4 (RS-232) Interface ++ ++pci:v00001093d00007517* ++ ID_MODEL_FROM_DATABASE=PCIe-8431/2 (RS-485) Interface ++ ++pci:v00001093d00007518* ++ ID_MODEL_FROM_DATABASE=PCIe-8431/4 (RS-485) Interface ++ ++pci:v00001093d0000751B* ++ ID_MODEL_FROM_DATABASE=cRIO-9081 ++ ++pci:v00001093d0000751C* ++ ID_MODEL_FROM_DATABASE=cRIO-9082 ++ ++pci:v00001093d00007528* ++ ID_MODEL_FROM_DATABASE=PXIe-4497 ++ ++pci:v00001093d00007529* ++ ID_MODEL_FROM_DATABASE=PXIe-4499 ++ ++pci:v00001093d0000752A* ++ ID_MODEL_FROM_DATABASE=PXIe-4492 ++ + pci:v00001093d00007539* + ID_MODEL_FROM_DATABASE=NI 9157 + + pci:v00001093d0000753A* + ID_MODEL_FROM_DATABASE=NI 9159 + ++pci:v00001093d00007598* ++ ID_MODEL_FROM_DATABASE=PXI-2571 ++ ++pci:v00001093d000075A4* ++ ID_MODEL_FROM_DATABASE=PXI-4131A ++ ++pci:v00001093d000075B1* ++ ID_MODEL_FROM_DATABASE=PCIe-7854R ++ ++pci:v00001093d000075BA* ++ ID_MODEL_FROM_DATABASE=PXI-2543 ++ ++pci:v00001093d000075BB* ++ ID_MODEL_FROM_DATABASE=PXIe-2543 ++ + pci:v00001093d000075E5* + ID_MODEL_FROM_DATABASE=PXI-6683 + + pci:v00001093d000075E6* + ID_MODEL_FROM_DATABASE=PXI-6683H + ++pci:v00001093d000075EF* ++ ID_MODEL_FROM_DATABASE=PXIe-5632 ++ ++pci:v00001093d0000761F* ++ ID_MODEL_FROM_DATABASE=PXI-2540 ++ ++pci:v00001093d00007620* ++ ID_MODEL_FROM_DATABASE=PXIe-2540 ++ ++pci:v00001093d00007621* ++ ID_MODEL_FROM_DATABASE=PXI-2541 ++ ++pci:v00001093d00007622* ++ ID_MODEL_FROM_DATABASE=PXIe-2541 ++ + pci:v00001093d00007626* + ID_MODEL_FROM_DATABASE=NI 9154 + + pci:v00001093d00007627* + ID_MODEL_FROM_DATABASE=NI 9155 + ++pci:v00001093d00007638* ++ ID_MODEL_FROM_DATABASE=PXI-2720 ++ ++pci:v00001093d00007639* ++ ID_MODEL_FROM_DATABASE=PXI-2722 ++ ++pci:v00001093d0000763A* ++ ID_MODEL_FROM_DATABASE=PXIe-2725 ++ ++pci:v00001093d0000763B* ++ ID_MODEL_FROM_DATABASE=PXIe-2727 ++ ++pci:v00001093d0000763C* ++ ID_MODEL_FROM_DATABASE=PXI-4465 ++ ++pci:v00001093d0000764B* ++ ID_MODEL_FROM_DATABASE=PXIe-2790 ++ ++pci:v00001093d0000764C* ++ ID_MODEL_FROM_DATABASE=PXI-2520 ++ ++pci:v00001093d0000764D* ++ ID_MODEL_FROM_DATABASE=PXI-2521 ++ ++pci:v00001093d0000764E* ++ ID_MODEL_FROM_DATABASE=PXI-2522 ++ ++pci:v00001093d0000764F* ++ ID_MODEL_FROM_DATABASE=PXI-2523 ++ ++pci:v00001093d00007654* ++ ID_MODEL_FROM_DATABASE=PXI-2796 ++ ++pci:v00001093d00007655* ++ ID_MODEL_FROM_DATABASE=PXI-2797 ++ ++pci:v00001093d00007656* ++ ID_MODEL_FROM_DATABASE=PXI-2798 ++ ++pci:v00001093d00007657* ++ ID_MODEL_FROM_DATABASE=PXI-2799 ++ ++pci:v00001093d0000765D* ++ ID_MODEL_FROM_DATABASE=PXI-2542 ++ ++pci:v00001093d0000765E* ++ ID_MODEL_FROM_DATABASE=PXIe-2542 ++ ++pci:v00001093d0000765F* ++ ID_MODEL_FROM_DATABASE=PXI-2544 ++ ++pci:v00001093d00007660* ++ ID_MODEL_FROM_DATABASE=PXIe-2544 ++ ++pci:v00001093d0000766D* ++ ID_MODEL_FROM_DATABASE=PCIe-6535B ++ ++pci:v00001093d0000766E* ++ ID_MODEL_FROM_DATABASE=PCIe-6536B ++ ++pci:v00001093d0000766F* ++ ID_MODEL_FROM_DATABASE=PCIe-6537B ++ ++pci:v00001093d000076A3* ++ ID_MODEL_FROM_DATABASE=PXIe-6535B ++ ++pci:v00001093d000076A4* ++ ID_MODEL_FROM_DATABASE=PXIe-6536B ++ ++pci:v00001093d000076A5* ++ ID_MODEL_FROM_DATABASE=PXIe-6537B ++ ++pci:v00001093d00009020* ++ ID_MODEL_FROM_DATABASE=PXI-2501 ++ ++pci:v00001093d00009030* ++ ID_MODEL_FROM_DATABASE=PXI-2503 ++ ++pci:v00001093d00009040* ++ ID_MODEL_FROM_DATABASE=PXI-2527 ++ ++pci:v00001093d00009050* ++ ID_MODEL_FROM_DATABASE=PXI-2565 ++ ++pci:v00001093d00009060* ++ ID_MODEL_FROM_DATABASE=PXI-2590 ++ ++pci:v00001093d00009070* ++ ID_MODEL_FROM_DATABASE=PXI-2591 ++ ++pci:v00001093d00009080* ++ ID_MODEL_FROM_DATABASE=PXI-2580 ++ ++pci:v00001093d00009090* ++ ID_MODEL_FROM_DATABASE=PCI-4021 ++ ++pci:v00001093d000090A0* ++ ID_MODEL_FROM_DATABASE=PXI-4021 ++ + pci:v00001093d0000B001* +- ID_MODEL_FROM_DATABASE=IMAQ-PCI-1408 ++ ID_MODEL_FROM_DATABASE=PCI-1408 + + pci:v00001093d0000B011* +- ID_MODEL_FROM_DATABASE=IMAQ-PXI-1408 ++ ID_MODEL_FROM_DATABASE=PXI-1408 + + pci:v00001093d0000B021* +- ID_MODEL_FROM_DATABASE=IMAQ-PCI-1424 ++ ID_MODEL_FROM_DATABASE=PCI-1424 ++ ++pci:v00001093d0000B022* ++ ID_MODEL_FROM_DATABASE=PXI-1424 + + pci:v00001093d0000B031* +- ID_MODEL_FROM_DATABASE=IMAQ-PCI-1413 ++ ID_MODEL_FROM_DATABASE=PCI-1413 + + pci:v00001093d0000B041* +- ID_MODEL_FROM_DATABASE=IMAQ-PCI-1407 ++ ID_MODEL_FROM_DATABASE=PCI-1407 + + pci:v00001093d0000B051* +- ID_MODEL_FROM_DATABASE=IMAQ-PXI-1407 ++ ID_MODEL_FROM_DATABASE=PXI-1407 + + pci:v00001093d0000B061* +- ID_MODEL_FROM_DATABASE=IMAQ-PCI-1411 ++ ID_MODEL_FROM_DATABASE=PCI-1411 + + pci:v00001093d0000B071* +- ID_MODEL_FROM_DATABASE=IMAQ-PCI-1422 ++ ID_MODEL_FROM_DATABASE=PCI-1422 + + pci:v00001093d0000B081* +- ID_MODEL_FROM_DATABASE=IMAQ-PXI-1422 ++ ID_MODEL_FROM_DATABASE=PXI-1422 + + pci:v00001093d0000B091* +- ID_MODEL_FROM_DATABASE=IMAQ-PXI-1411 ++ ID_MODEL_FROM_DATABASE=PXI-1411 ++ ++pci:v00001093d0000B0B1* ++ ID_MODEL_FROM_DATABASE=PCI-1409 ++ ++pci:v00001093d0000B0C1* ++ ID_MODEL_FROM_DATABASE=PXI-1409 ++ ++pci:v00001093d0000B0E1* ++ ID_MODEL_FROM_DATABASE=PCI-1428 + + pci:v00001093d0000C4C4* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device + ++pci:v00001093d0000C4C4sv00001093sd0000728A* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5421) ++ ++pci:v00001093d0000C4C4sv00001093sd0000728B* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5442) ++ ++pci:v00001093d0000C4C4sv00001093sd0000728D* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5451) ++ ++pci:v00001093d0000C4C4sv00001093sd000072A2* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5122) ++ ++pci:v00001093d0000C4C4sv00001093sd000072DA* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5422) ++ ++pci:v00001093d0000C4C4sv00001093sd000072F7* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6535) ++ ++pci:v00001093d0000C4C4sv00001093sd000072F8* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6536) ++ ++pci:v00001093d0000C4C4sv00001093sd000072F9* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6537) ++ ++pci:v00001093d0000C4C4sv00001093sd00007326* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6509) ++ ++pci:v00001093d0000C4C4sv00001093sd0000736C* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4140) ++ ++pci:v00001093d0000C4C4sv00001093sd0000738B* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5622) ++ ++pci:v00001093d0000C4C4sv00001093sd000073C4* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5450) ++ ++pci:v00001093d0000C4C4sv00001093sd000073C7* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6545) ++ ++pci:v00001093d0000C4C4sv00001093sd000073D4* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6544) ++ ++pci:v00001093d0000C4C4sv00001093sd00007425* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6320) ++ ++pci:v00001093d0000C4C4sv00001093sd00007427* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6321) ++ ++pci:v00001093d0000C4C4sv00001093sd00007428* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6323) ++ ++pci:v00001093d0000C4C4sv00001093sd00007429* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6323) ++ ++pci:v00001093d0000C4C4sv00001093sd0000742A* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6341) ++ ++pci:v00001093d0000C4C4sv00001093sd0000742B* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6341) ++ ++pci:v00001093d0000C4C4sv00001093sd0000742C* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6343) ++ ++pci:v00001093d0000C4C4sv00001093sd0000742D* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6343) ++ ++pci:v00001093d0000C4C4sv00001093sd0000742F* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6351) ++ ++pci:v00001093d0000C4C4sv00001093sd00007431* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6353) ++ ++pci:v00001093d0000C4C4sv00001093sd00007432* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6361) ++ ++pci:v00001093d0000C4C4sv00001093sd00007433* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6361) ++ ++pci:v00001093d0000C4C4sv00001093sd00007434* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6363) ++ ++pci:v00001093d0000C4C4sv00001093sd00007435* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6363) ++ ++pci:v00001093d0000C4C4sv00001093sd00007436* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6356) ++ ++pci:v00001093d0000C4C4sv00001093sd00007437* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6358) ++ ++pci:v00001093d0000C4C4sv00001093sd00007438* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6366) ++ ++pci:v00001093d0000C4C4sv00001093sd00007439* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6368) ++ ++pci:v00001093d0000C4C4sv00001093sd00007468* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5185) ++ ++pci:v00001093d0000C4C4sv00001093sd00007469* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5186) ++ ++pci:v00001093d0000C4C4sv00001093sd00007492* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4300) ++ ++pci:v00001093d0000C4C4sv00001093sd00007498* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6548) ++ ++pci:v00001093d0000C4C4sv00001093sd00007499* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6547) ++ ++pci:v00001093d0000C4C4sv00001093sd000074A8* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4330) ++ ++pci:v00001093d0000C4C4sv00001093sd000074A9* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4331) ++ ++pci:v00001093d0000C4C4sv00001093sd000074B1* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4154) ++ + pci:v00001093d0000C4C4sv00001093sd000074B2* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4353) + ++pci:v00001093d0000C4C4sv00001093sd000074B6* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-1433) ++ ++pci:v00001093d0000C4C4sv00001093sd000074CD* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5643R) ++ + pci:v00001093d0000C4C4sv00001093sd000074D0* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7961R) + ++pci:v00001093d0000C4C4sv00001093sd000074DD* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6376) ++ ++pci:v00001093d0000C4C4sv00001093sd000074DE* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6378) ++ + pci:v00001093d0000C4C4sv00001093sd000074E2* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7962R) + + pci:v00001093d0000C4C4sv00001093sd000074E3* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7965R) + ++pci:v00001093d0000C4C4sv00001093sd000074E5* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4844) ++ ++pci:v00001093d0000C4C4sv00001093sd000074F3* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-5140) ++ ++pci:v00001093d0000C4C4sv00001093sd0000753C* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-1435) ++ ++pci:v00001093d0000C4C4sv00001093sd00007548* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5622 (25MHz DDC)) ++ ++pci:v00001093d0000C4C4sv00001093sd0000754D* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-5155) ++ ++pci:v00001093d0000C4C4sv00001093sd00007551* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6556) ++ + pci:v00001093d0000C4C4sv00001093sd00007553* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-1473R) + ++pci:v00001093d0000C4C4sv00001093sd00007570* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-1474R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007571* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-1475R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007572* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-1476R) ++ ++pci:v00001093d0000C4C4sv00001093sd000075A2* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5693) ++ ++pci:v00001093d0000C4C4sv00001093sd000075A3* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5694) ++ ++pci:v00001093d0000C4C4sv00001093sd000075A5* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4141) ++ + pci:v00001093d0000C4C4sv00001093sd000075CE* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7966R) + ++pci:v00001093d0000C4C4sv00001093sd000075CF* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4357) ++ ++pci:v00001093d0000C4C4sv00001093sd000075D2* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-RevB-5643R) ++ ++pci:v00001093d0000C4C4sv00001093sd000075D3* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5644R) ++ ++pci:v00001093d0000C4C4sv00001093sd000075EE* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5645R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007613* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6555) ++ ++pci:v00001093d0000C4C4sv00001093sd00007619* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5185) ++ ++pci:v00001093d0000C4C4sv00001093sd0000761A* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5186) ++ ++pci:v00001093d0000C4C4sv00001093sd00007629* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4142) ++ ++pci:v00001093d0000C4C4sv00001093sd0000762A* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4143) ++ ++pci:v00001093d0000C4C4sv00001093sd0000762B* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4138) ++ ++pci:v00001093d0000C4C4sv00001093sd0000762C* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4144) ++ ++pci:v00001093d0000C4C4sv00001093sd0000762D* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4145) ++ ++pci:v00001093d0000C4C4sv00001093sd00007644* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4841) ++ ++pci:v00001093d0000C4C4sv00001093sd00007658* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5162 (4CH)) ++ ++pci:v00001093d0000C4C4sv00001093sd000076AB* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4322) ++ ++pci:v00001093d0000C4C4sv00001093sd000076AD* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4112) ++ ++pci:v00001093d0000C4C4sv00001093sd000076AE* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4113) ++ ++pci:v00001093d0000C4C4sv00001093sd000076B5* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7971R) ++ ++pci:v00001093d0000C4C4sv00001093sd000076B6* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7972R) ++ + pci:v00001093d0000C4C4sv00001093sd000076B7* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7975R) + ++pci:v00001093d0000C4C4sv00001093sd000076C8* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6614) ++ ++pci:v00001093d0000C4C4sv00001093sd000076C9* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6612) ++ ++pci:v00001093d0000C4C4sv00001093sd000076CB* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5646R) ++ ++pci:v00001093d0000C4C4sv00001093sd000076CC* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5162 (2CH)) ++ + pci:v00001093d0000C4C4sv00001093sd000076D0* +- ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5160) ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5160 (2CH)) ++ ++pci:v00001093d0000C4C4sv00001093sd000076D1* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5160 (4CH)) ++ ++pci:v00001093d0000C4C4sv00001093sd000076DC* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4610) ++ ++pci:v00001093d0000C4C4sv00001093sd000076FB* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-1473R-LX110) ++ ++pci:v00001093d0000C4C4sv00001093sd000076FE* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5644R) ++ ++pci:v00001093d0000C4C4sv00001093sd000076FF* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5644R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007700* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5644R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007701* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5645R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007702* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5645R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007703* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5645R) ++ ++pci:v00001093d0000C4C4sv00001093sd0000770C* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4139) ++ ++pci:v00001093d0000C4C4sv00001093sd00007711* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4464) ++ ++pci:v00001093d0000C4C4sv00001093sd00007716* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6612) ++ ++pci:v00001093d0000C4C4sv00001093sd0000771E* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4339) ++ ++pci:v00001093d0000C4C4sv00001093sd00007735* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9033) ++ ++pci:v00001093d0000C4C4sv00001093sd0000774B* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9031) ++ ++pci:v00001093d0000C4C4sv00001093sd0000774D* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9034) ++ ++pci:v00001093d0000C4C4sv00001093sd00007755* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9030) ++ ++pci:v00001093d0000C4C4sv00001093sd00007777* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7976R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007782* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5646R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007783* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5646R) ++ ++pci:v00001093d0000C4C4sv00001093sd00007784* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5646R) ++ ++pci:v00001093d0000C4C4sv00001093sd000077A5* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6345) ++ ++pci:v00001093d0000C4C4sv00001093sd000077A6* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6355) ++ ++pci:v00001093d0000C4C4sv00001093sd000077A7* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6365) ++ ++pci:v00001093d0000C4C4sv00001093sd000077A8* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6375) ++ ++pci:v00001093d0000C4C4sv00001093sd000077B4* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7820R) ++ ++pci:v00001093d0000C4C4sv00001093sd000077B5* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7821R) ++ ++pci:v00001093d0000C4C4sv00001093sd000077B6* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7822R) ++ ++pci:v00001093d0000C4C4sv00001093sd000077B9* ++ ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9038) + + pci:v00001093d0000C801* + ID_MODEL_FROM_DATABASE=PCI-GPIB + ++pci:v00001093d0000C811* ++ ID_MODEL_FROM_DATABASE=PCI-GPIB+ ++ ++pci:v00001093d0000C821* ++ ID_MODEL_FROM_DATABASE=PXI-GPIB ++ + pci:v00001093d0000C831* +- ID_MODEL_FROM_DATABASE=PCI-GPIB bridge ++ ID_MODEL_FROM_DATABASE=PMC-GPIB ++ ++pci:v00001093d0000C840* ++ ID_MODEL_FROM_DATABASE=PCI-GPIB ++ ++pci:v00001093d0000D130* ++ ID_MODEL_FROM_DATABASE=PCI-232/2 Interface ++ ++pci:v00001093d0000D140* ++ ID_MODEL_FROM_DATABASE=PCI-232/4 Interface ++ ++pci:v00001093d0000D150* ++ ID_MODEL_FROM_DATABASE=PCI-232/8 Interface ++ ++pci:v00001093d0000D160* ++ ID_MODEL_FROM_DATABASE=PCI-485/2 Interface ++ ++pci:v00001093d0000D170* ++ ID_MODEL_FROM_DATABASE=PCI-485/4 Interface ++ ++pci:v00001093d0000D190* ++ ID_MODEL_FROM_DATABASE=PXI-8422/2 (Isolated RS-232) Interface ++ ++pci:v00001093d0000D1A0* ++ ID_MODEL_FROM_DATABASE=PXI-8422/4 (Isolated RS-232) Interface ++ ++pci:v00001093d0000D1B0* ++ ID_MODEL_FROM_DATABASE=PXI-8423/2 (Isolated RS-485) Interface ++ ++pci:v00001093d0000D1C0* ++ ID_MODEL_FROM_DATABASE=PXI-8423/4 (Isolated RS-485) Interface ++ ++pci:v00001093d0000D1D0* ++ ID_MODEL_FROM_DATABASE=PXI-8420/2 (RS-232) Interface ++ ++pci:v00001093d0000D1E0* ++ ID_MODEL_FROM_DATABASE=PXI-8420/4 (RS-232) Interface ++ ++pci:v00001093d0000D1F0* ++ ID_MODEL_FROM_DATABASE=PXI-8420/8 (RS-232) Interface ++ ++pci:v00001093d0000D1F1* ++ ID_MODEL_FROM_DATABASE=PXI-8420/16 (RS-232) Interface ++ ++pci:v00001093d0000D230* ++ ID_MODEL_FROM_DATABASE=PXI-8421/2 (RS-485) Interface ++ ++pci:v00001093d0000D240* ++ ID_MODEL_FROM_DATABASE=PXI-8421/4 (RS-485) Interface ++ ++pci:v00001093d0000D250* ++ ID_MODEL_FROM_DATABASE=PCI-232/2 (Isolated) Interface ++ ++pci:v00001093d0000D260* ++ ID_MODEL_FROM_DATABASE=PCI-485/2 (Isolated) Interface ++ ++pci:v00001093d0000D270* ++ ID_MODEL_FROM_DATABASE=PCI-232/4 (Isolated) Interface ++ ++pci:v00001093d0000D280* ++ ID_MODEL_FROM_DATABASE=PCI-485/4 (Isolated) Interface ++ ++pci:v00001093d0000D290* ++ ID_MODEL_FROM_DATABASE=PCI-485/8 Interface ++ ++pci:v00001093d0000D2A0* ++ ID_MODEL_FROM_DATABASE=PXI-8421/8 (RS-485) Interface ++ ++pci:v00001093d0000D2B0* ++ ID_MODEL_FROM_DATABASE=PCI-232/16 Interface ++ ++pci:v00001093d0000E111* ++ ID_MODEL_FROM_DATABASE=PCI-CAN ++ ++pci:v00001093d0000E131* ++ ID_MODEL_FROM_DATABASE=PXI-8461 (1 port) ++ ++pci:v00001093d0000E141* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/LS ++ ++pci:v00001093d0000E151* ++ ID_MODEL_FROM_DATABASE=PXI-8460 (1 port) ++ ++pci:v00001093d0000E211* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/2 ++ ++pci:v00001093d0000E231* ++ ID_MODEL_FROM_DATABASE=PXI-8461 (2 ports) ++ ++pci:v00001093d0000E241* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/LS2 ++ ++pci:v00001093d0000E251* ++ ID_MODEL_FROM_DATABASE=PXI-8460 (2 ports) ++ ++pci:v00001093d0000E261* ++ ID_MODEL_FROM_DATABASE=PCI-CAN/DS ++ ++pci:v00001093d0000E271* ++ ID_MODEL_FROM_DATABASE=PXI-8462 + + pci:v00001094* + ID_VENDOR_FROM_DATABASE=First International Computers [FIC] +@@ -23331,16 +25011,16 @@ pci:v000010DEd00000367* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + + pci:v000010DEd00000368* +- ID_MODEL_FROM_DATABASE=MCP55 SMBus ++ ID_MODEL_FROM_DATABASE=MCP55 SMBus Controller + + pci:v000010DEd00000368sv00001028sd0000020C* +- ID_MODEL_FROM_DATABASE=MCP55 SMBus (PowerEdge M605 MCP55 SMBus) ++ ID_MODEL_FROM_DATABASE=MCP55 SMBus Controller (PowerEdge M605 MCP55 SMBus) + + pci:v000010DEd00000368sv00001028sd00000221* +- ID_MODEL_FROM_DATABASE=MCP55 SMBus (PowerEdge R805 MCP55 SMBus) ++ ID_MODEL_FROM_DATABASE=MCP55 SMBus Controller (PowerEdge R805 MCP55 SMBus) + + pci:v000010DEd00000368sv0000147Bsd00001C24* +- ID_MODEL_FROM_DATABASE=MCP55 SMBus (KN9 series mainboard) ++ ID_MODEL_FROM_DATABASE=MCP55 SMBus Controller (KN9 series mainboard) + + pci:v000010DEd00000369* + ID_MODEL_FROM_DATABASE=MCP55 Memory Controller +@@ -24530,6 +26210,9 @@ pci:v000010DEd00000641* + pci:v000010DEd00000641sv00001682sd00004009* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9400 GT] (PV-T94G-ZAFG) + ++pci:v000010DEd00000642* ++ ID_MODEL_FROM_DATABASE=G96 [D9M-10] ++ + pci:v000010DEd00000643* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9500 GT] + +@@ -26522,6 +28205,9 @@ pci:v000010DEd0000100A* + pci:v000010DEd0000100C* + ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX Titan Black] + ++pci:v000010DEd0000101E* ++ ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20X] ++ + pci:v000010DEd0000101F* + ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20] + +@@ -26552,6 +28238,15 @@ pci:v000010DEd00001028* + pci:v000010DEd00001029* + ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40s] + ++pci:v000010DEd0000102A* ++ ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40t] ++ ++pci:v000010DEd0000102D* ++ ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K80] ++ ++pci:v000010DEd0000102E* ++ ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40d] ++ + pci:v000010DEd0000103A* + ID_MODEL_FROM_DATABASE=GK110GL [Quadro K6000] + +@@ -26582,6 +28277,9 @@ pci:v000010DEd0000104B* + pci:v000010DEd0000104C* + ID_MODEL_FROM_DATABASE=GF119 [GeForce GT 705] + ++pci:v000010DEd0000104D* ++ ID_MODEL_FROM_DATABASE=GF119 [GeForce GT 710] ++ + pci:v000010DEd00001050* + ID_MODEL_FROM_DATABASE=GF119M [GeForce GT 520M] + +@@ -27551,9 +29249,15 @@ pci:v000010DEd0000118E* + pci:v000010DEd0000118F* + ID_MODEL_FROM_DATABASE=GK104GL [Tesla K10] + ++pci:v000010DEd00001191* ++ ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760 Rev. 2] ++ + pci:v000010DEd00001193* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760 Ti OEM] + ++pci:v000010DEd00001194* ++ ID_MODEL_FROM_DATABASE=GK104GL [Tesla K8] ++ + pci:v000010DEd00001195* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 660 Rev. 2] + +@@ -27944,6 +29648,9 @@ pci:v000010DEd00001381* + pci:v000010DEd00001382* + ID_MODEL_FROM_DATABASE=GM107 [GeForce GTX 745] + ++pci:v000010DEd00001389* ++ ID_MODEL_FROM_DATABASE=GM107GL [GRID M3] ++ + pci:v000010DEd00001390* + ID_MODEL_FROM_DATABASE=GM107M [GeForce 845M] + +@@ -27971,6 +29678,9 @@ pci:v000010DEd000013BA* + pci:v000010DEd000013BB* + ID_MODEL_FROM_DATABASE=GM107GL [Quadro K620] + ++pci:v000010DEd000013BD* ++ ID_MODEL_FROM_DATABASE=GM107GL [Tesla M40] ++ + pci:v000010DF* + ID_VENDOR_FROM_DATABASE=Emulex Corporation + +@@ -31772,6 +33482,30 @@ pci:v0000111Dd0000806E* + pci:v0000111Dd0000806F* + ID_MODEL_FROM_DATABASE=HIO524G2 PCI Express Gen2 Switch + ++pci:v0000111Dd00008088* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch ++ ++pci:v0000111Dd00008088sv00001093sd0000752F* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8383mc Device) ++ ++pci:v0000111Dd00008088sv00001093sd00007543* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8383mc System Host) ++ ++pci:v0000111Dd00008088sv00001093sd0000755C* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8364) ++ ++pci:v0000111Dd00008088sv00001093sd0000755D* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8374) ++ ++pci:v0000111Dd00008088sv00001093sd000075FF* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8383mc DMA) ++ ++pci:v0000111Dd00008088sv00001093sd00007600* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8383mc DMA) ++ ++pci:v0000111Dd00008088sv00001093sd00007602* ++ ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8384) ++ + pci:v0000111E* + ID_VENDOR_FROM_DATABASE=Eldec + +@@ -42929,6 +44663,9 @@ pci:v00001425d00005084* + pci:v00001425d00005085* + ID_MODEL_FROM_DATABASE=T580-5085 Unified Wire Ethernet Controller + ++pci:v00001425d00005086* ++ ID_MODEL_FROM_DATABASE=T580-5086 Unified Wire Ethernet Controller ++ + pci:v00001425d00005401* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +@@ -43007,6 +44744,9 @@ pci:v00001425d00005484* + pci:v00001425d00005485* + ID_MODEL_FROM_DATABASE=T580-5085 Unified Wire Ethernet Controller + ++pci:v00001425d00005486* ++ ID_MODEL_FROM_DATABASE=T580-5086 Unified Wire Ethernet Controller ++ + pci:v00001425d00005501* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller + +@@ -43085,6 +44825,9 @@ pci:v00001425d00005584* + pci:v00001425d00005585* + ID_MODEL_FROM_DATABASE=T580-5085 Unified Wire Storage Controller + ++pci:v00001425d00005586* ++ ID_MODEL_FROM_DATABASE=T580-5086 Unified Wire Storage Controller ++ + pci:v00001425d00005601* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller + +@@ -43163,6 +44906,9 @@ pci:v00001425d00005684* + pci:v00001425d00005685* + ID_MODEL_FROM_DATABASE=T580-5085 Unified Wire Storage Controller + ++pci:v00001425d00005686* ++ ID_MODEL_FROM_DATABASE=T580-5086 Unified Wire Storage Controller ++ + pci:v00001425d00005701* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +@@ -43319,6 +45065,9 @@ pci:v00001425d00005884* + pci:v00001425d00005885* + ID_MODEL_FROM_DATABASE=T580-5085 Unified Wire Ethernet Controller [VF] + ++pci:v00001425d00005886* ++ ID_MODEL_FROM_DATABASE=T580-5086 Unified Wire Ethernet Controller [VF] ++ + pci:v00001425d0000A000* + ID_MODEL_FROM_DATABASE=PE10K Unified Wire Ethernet Controller + +@@ -49862,6 +51611,15 @@ pci:v000016ED* + pci:v000016EDd00001001* + ID_MODEL_FROM_DATABASE=UMIO communication card + ++pci:v000016F2* ++ ID_VENDOR_FROM_DATABASE=ETAS GmbH ++ ++pci:v000016F2d00000200* ++ ID_MODEL_FROM_DATABASE=I/O board ++ ++pci:v000016F2d00000200sv000016F2sd00000010* ++ ID_MODEL_FROM_DATABASE=I/O board (ES53xx I/O board) ++ + pci:v000016F3* + ID_VENDOR_FROM_DATABASE=Jetway Information Co., Ltd. + +@@ -50004,7 +51762,7 @@ pci:v00001775* + ID_VENDOR_FROM_DATABASE=GE Intelligent Platforms + + pci:v0000177D* +- ID_VENDOR_FROM_DATABASE=Cavium Networks ++ ID_VENDOR_FROM_DATABASE=Cavium, Inc. + + pci:v0000177Dd00000001* + ID_MODEL_FROM_DATABASE=Nitrox XL N1 +@@ -50063,6 +51821,147 @@ pci:v0000177Dd00000095* + pci:v0000177Dd00000096* + ID_MODEL_FROM_DATABASE=Octeon III CN70XX Network Processor + ++pci:v0000177Dd0000A001* ++ ID_MODEL_FROM_DATABASE=THUNDERX MRML Bridge ++ ++pci:v0000177Dd0000A002* ++ ID_MODEL_FROM_DATABASE=THUNDERX PCC Bridge ++ ++pci:v0000177Dd0000A002sv0000177Dsd0000A102* ++ ID_MODEL_FROM_DATABASE=THUNDERX PCC Bridge (CN88XX PCC Bridge) ++ ++pci:v0000177Dd0000A008* ++ ID_MODEL_FROM_DATABASE=THUNDERX SMMU ++ ++pci:v0000177Dd0000A008sv0000177Dsd0000A108* ++ ID_MODEL_FROM_DATABASE=THUNDERX SMMU (CN88XX SMMU) ++ ++pci:v0000177Dd0000A009* ++ ID_MODEL_FROM_DATABASE=THUNDERX Generic Interrupt Controller ++ ++pci:v0000177Dd0000A00A* ++ ID_MODEL_FROM_DATABASE=THUNDERX GPIO Controller ++ ++pci:v0000177Dd0000A00B* ++ ID_MODEL_FROM_DATABASE=THUNDERX MPI / SPI Controller ++ ++pci:v0000177Dd0000A00C* ++ ID_MODEL_FROM_DATABASE=THUNDERX MIO-PTP Controller ++ ++pci:v0000177Dd0000A00D* ++ ID_MODEL_FROM_DATABASE=THUNDERX MIX Network Controller ++ ++pci:v0000177Dd0000A00E* ++ ID_MODEL_FROM_DATABASE=THUNDERX Reset Controller ++ ++pci:v0000177Dd0000A00F* ++ ID_MODEL_FROM_DATABASE=THUNDERX UART Controller ++ ++pci:v0000177Dd0000A010* ++ ID_MODEL_FROM_DATABASE=THUNDERX eMMC/SD Controller ++ ++pci:v0000177Dd0000A011* ++ ID_MODEL_FROM_DATABASE=THUNDERX MIO-BOOT Controller ++ ++pci:v0000177Dd0000A012* ++ ID_MODEL_FROM_DATABASE=THUNDERX TWSI / I2C Controller ++ ++pci:v0000177Dd0000A013* ++ ID_MODEL_FROM_DATABASE=THUNDERX CCPI (Multi-node connect) ++ ++pci:v0000177Dd0000A014* ++ ID_MODEL_FROM_DATABASE=THUNDERX Voltage Regulator Module ++ ++pci:v0000177Dd0000A015* ++ ID_MODEL_FROM_DATABASE=THUNDERX PCIe Switch Logic Interface ++ ++pci:v0000177Dd0000A016* ++ ID_MODEL_FROM_DATABASE=THUNDERX Key Memory ++ ++pci:v0000177Dd0000A017* ++ ID_MODEL_FROM_DATABASE=THUNDERX GTI (Global System Timers) ++ ++pci:v0000177Dd0000A018* ++ ID_MODEL_FROM_DATABASE=THUNDERX Random Number Generator ++ ++pci:v0000177Dd0000A019* ++ ID_MODEL_FROM_DATABASE=THUNDERX DFA ++ ++pci:v0000177Dd0000A01A* ++ ID_MODEL_FROM_DATABASE=THUNDERX Zip Coprocessor ++ ++pci:v0000177Dd0000A01B* ++ ID_MODEL_FROM_DATABASE=THUNDERX xHCI USB Controller ++ ++pci:v0000177Dd0000A01C* ++ ID_MODEL_FROM_DATABASE=THUNDERX AHCI SATA Controller ++ ++pci:v0000177Dd0000A01Csv0000177Dsd0000A11C* ++ ID_MODEL_FROM_DATABASE=THUNDERX AHCI SATA Controller (CN88XX AHCI SATA Controller) ++ ++pci:v0000177Dd0000A01D* ++ ID_MODEL_FROM_DATABASE=THUNDERX RAID Coprocessor ++ ++pci:v0000177Dd0000A01E* ++ ID_MODEL_FROM_DATABASE=THUNDERX Network Interface Controller ++ ++pci:v0000177Dd0000A01F* ++ ID_MODEL_FROM_DATABASE=THUNDERX Traffic Network Switch ++ ++pci:v0000177Dd0000A020* ++ ID_MODEL_FROM_DATABASE=THUNDERX PEM (PCI Express Interface) ++ ++pci:v0000177Dd0000A021* ++ ID_MODEL_FROM_DATABASE=THUNDERX L2C (Level-2 Cache Controller) ++ ++pci:v0000177Dd0000A022* ++ ID_MODEL_FROM_DATABASE=THUNDERX LMC (DRAM Controller) ++ ++pci:v0000177Dd0000A023* ++ ID_MODEL_FROM_DATABASE=THUNDERX OCLA (On-Chip Logic Analyzer) ++ ++pci:v0000177Dd0000A024* ++ ID_MODEL_FROM_DATABASE=THUNDERX OSM ++ ++pci:v0000177Dd0000A025* ++ ID_MODEL_FROM_DATABASE=THUNDERX GSER (General Serializer/Deserializer) ++ ++pci:v0000177Dd0000A026* ++ ID_MODEL_FROM_DATABASE=THUNDERX BGX (Common Ethernet Interface) ++ ++pci:v0000177Dd0000A027* ++ ID_MODEL_FROM_DATABASE=THUNDERX IOBN ++ ++pci:v0000177Dd0000A029* ++ ID_MODEL_FROM_DATABASE=THUNDERX NCSI (Network Controller Sideband Interface) ++ ++pci:v0000177Dd0000A02A* ++ ID_MODEL_FROM_DATABASE=THUNDERX SGP ++ ++pci:v0000177Dd0000A02B* ++ ID_MODEL_FROM_DATABASE=THUNDERX SMI / MDIO Controller ++ ++pci:v0000177Dd0000A02C* ++ ID_MODEL_FROM_DATABASE=THUNDERX DAP (Debug Access Port) ++ ++pci:v0000177Dd0000A02D* ++ ID_MODEL_FROM_DATABASE=THUNDERX PCIERC (PCIe Root Complex) ++ ++pci:v0000177Dd0000A02E* ++ ID_MODEL_FROM_DATABASE=THUNDERX L2C-TAD ++ ++pci:v0000177Dd0000A02F* ++ ID_MODEL_FROM_DATABASE=THUNDERX L2C-CBC ++ ++pci:v0000177Dd0000A030* ++ ID_MODEL_FROM_DATABASE=THUNDERX L2C-MCI ++ ++pci:v0000177Dd0000A031* ++ ID_MODEL_FROM_DATABASE=THUNDERX MIO-FUS (Fuse Access Controller) ++ ++pci:v0000177Dd0000A032* ++ ID_MODEL_FROM_DATABASE=THUNDERX FUSF (Fuse Controller) ++ + pci:v00001787* + ID_VENDOR_FROM_DATABASE=Hightech Information System Ltd. + +@@ -53312,6 +55211,12 @@ pci:v00001BBFd00000003* + pci:v00001BBFd00000004* + ID_MODEL_FROM_DATABASE=MAX4 + ++pci:v00001BEE* ++ ID_VENDOR_FROM_DATABASE=IXXAT Automation GmbH ++ ++pci:v00001BEEd00000003* ++ ID_MODEL_FROM_DATABASE=CAN-IB200/PCIe ++ + pci:v00001BF4* + ID_VENDOR_FROM_DATABASE=VTI Instruments Corporation + +@@ -58271,6 +60176,9 @@ pci:v00008086d000010D3sv0000103Csd00003250* + pci:v00008086d000010D3sv00001043sd00008369* + ID_MODEL_FROM_DATABASE=82574L Gigabit Network Connection (Motherboard) + ++pci:v00008086d000010D3sv00001093sd000076E9* ++ ID_MODEL_FROM_DATABASE=82574L Gigabit Network Connection (PCIe-8233 Ethernet Adapter) ++ + pci:v00008086d000010D3sv000010A9sd00008029* + ID_MODEL_FROM_DATABASE=82574L Gigabit Network Connection (Prism XL Single Port Gigabit Ethernet) + +@@ -59339,6 +61247,18 @@ pci:v00008086d00001521sv0000108Esd00007B16* + pci:v00008086d00001521sv0000108Esd00007B18* + ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (Quad Port GbE PCIe 2.0 Low Profile Adapter, UTP) + ++pci:v00008086d00001521sv00001093sd00007648* ++ ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (PCIe-8237R Ethernet Adapter) ++ ++pci:v00008086d00001521sv00001093sd00007649* ++ ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (PCIe-8236 Ethernet Adapter) ++ ++pci:v00008086d00001521sv00001093sd000076B1* ++ ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (PCIe-8237R-S Ethernet Adapter) ++ ++pci:v00008086d00001521sv00001093sd0000775B* ++ ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (PCIe-8237 Ethernet Adapter) ++ + pci:v00008086d00001521sv000010A9sd0000802A* + ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (UV2-BaseIO dual-port GbE) + +@@ -59498,6 +61418,9 @@ pci:v00008086d00001533* + pci:v00008086d00001533sv0000103Csd00000003* + ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection (Ethernet I210-T1 GbE NIC) + ++pci:v00008086d00001533sv00001093sd00007706* ++ ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection (Compact Vision System Ethernet Adapter) ++ + pci:v00008086d00001533sv000010A9sd0000802C* + ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection (UV300 BaseIO single-port GbE) + +@@ -59703,10 +61626,10 @@ pci:v00008086d000015A3* + ID_MODEL_FROM_DATABASE=Ethernet Connection (3) I218-V + + pci:v00008086d000015B7* +- ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I219-V ++ ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I219-LM + + pci:v00008086d000015B8* +- ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I219-LM ++ ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I219-V + + pci:v00008086d00001600* + ID_MODEL_FROM_DATABASE=Broadwell-U Host Bridge -OPI +diff --git a/hwdb/20-usb-vendor-model.hwdb b/hwdb/20-usb-vendor-model.hwdb +index d87313cf87..ea1c3e3e61 100644 +--- a/hwdb/20-usb-vendor-model.hwdb ++++ b/hwdb/20-usb-vendor-model.hwdb +@@ -30222,7 +30222,7 @@ usb:v0930p6544* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler 2.0 Stick (2GB) + + usb:v0930p6545* +- ID_MODEL_FROM_DATABASE=Kingston DataTraveler 102 Flash Drive / HEMA Flash Drive 2 GB / PNY Attache 4GB Stick ++ ID_MODEL_FROM_DATABASE=Kingston DataTraveler 102/2.0 / HEMA Flash Drive 2 GB / PNY Attache 4GB Stick + + usb:v0931* + ID_VENDOR_FROM_DATABASE=Harmonic Data Systems, Ltd diff --git a/0204-build-sys-make-hibernation-support-configure-option-.patch b/0204-build-sys-make-hibernation-support-configure-option-.patch new file mode 100644 index 0000000..09b7e5e --- /dev/null +++ b/0204-build-sys-make-hibernation-support-configure-option-.patch @@ -0,0 +1,86 @@ +From 72ba9f04f95bc6eda1e32fdd21ea56476713a5bc Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Tue, 9 Sep 2014 01:40:51 +0400 +Subject: [PATCH] build-sys: make hibernation support configure option also + handle hybrid-sleep; fix indentation + +--- + Makefile.am | 27 +++++++++++++-------------- + 1 file changed, 13 insertions(+), 14 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 35c877fe2a..de40043c5b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -459,7 +459,6 @@ dist_systemunit_DATA = \ + units/network-online.target \ + units/nss-lookup.target \ + units/nss-user-lookup.target \ +- units/hybrid-sleep.target \ + units/poweroff.target \ + units/reboot.target \ + units/rescue.target \ +@@ -523,7 +522,6 @@ nodist_systemunit_DATA = \ + units/emergency.service \ + units/rescue.service \ + units/user@.service \ +- units/systemd-hybrid-sleep.service \ + units/systemd-suspend.service \ + units/systemd-halt.service \ + units/systemd-poweroff.service \ +@@ -579,7 +577,6 @@ EXTRA_DIST += \ + units/systemd-fsck-root.service.in \ + units/user@.service.in \ + units/debug-shell.service.in \ +- units/systemd-hybrid-sleep.service.in \ + units/systemd-suspend.service.in \ + units/quotaon.service.in \ + units/initrd-parse-etc.service.in \ +@@ -2159,17 +2156,17 @@ systemd_system_update_generator_LDADD = \ + # ------------------------------------------------------------------------------ + if ENABLE_HIBERNATE + systemgenerator_PROGRAMS += \ +- systemd-hibernate-resume-generator ++ systemd-hibernate-resume-generator + + rootlibexec_PROGRAMS += \ +- systemd-hibernate-resume ++ systemd-hibernate-resume + + systemd_hibernate_resume_SOURCES = \ +- src/hibernate-resume/hibernate-resume.c ++ src/hibernate-resume/hibernate-resume.c + + systemd_hibernate_resume_LDADD = \ +- libsystemd-internal.la \ +- libsystemd-shared.la ++ libsystemd-internal.la \ ++ libsystemd-shared.la + + systemd_hibernate_resume_generator_SOURCES = \ + src/hibernate-resume/hibernate-resume-generator.c +@@ -2179,16 +2176,18 @@ systemd_hibernate_resume_generator_LDADD = \ + libsystemd-shared.la + + EXTRA_DIST += \ +- units/systemd-hibernate.service.in \ +- units/systemd-hibernate-resume@.service.in ++ units/systemd-hibernate.service.in \ ++ units/systemd-hibernate-resume@.service.in \ ++ units/systemd-hybrid-sleep.service.in + + dist_systemunit_DATA += \ +- units/hibernate.target ++ units/hibernate.target \ ++ units/hybrid-sleep.target + + nodist_systemunit_DATA += \ +- units/systemd-hibernate.service \ +- units/systemd-hibernate-resume@.service +- ++ units/systemd-hibernate.service \ ++ units/systemd-hibernate-resume@.service \ ++ units/systemd-hybrid-sleep.service + endif + + # ------------------------------------------------------------------------------ diff --git a/0205-udev-import-the-full-db-on-MOVE-events-for-devices-w.patch b/0205-udev-import-the-full-db-on-MOVE-events-for-devices-w.patch new file mode 100644 index 0000000..3bd5a4e --- /dev/null +++ b/0205-udev-import-the-full-db-on-MOVE-events-for-devices-w.patch @@ -0,0 +1,51 @@ +From b081b27e1433cdc7ac72b25ae8b4db887d79187f Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 9 Sep 2014 12:23:19 +0200 +Subject: [PATCH] udev: import the full db on MOVE events for devices without + dev_t + +--- + rules/80-net-setup-link.rules | 2 -- + src/udev/udev-event.c | 16 ++++++++++++++++ + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/rules/80-net-setup-link.rules b/rules/80-net-setup-link.rules +index 420769497f..6e411a91f0 100644 +--- a/rules/80-net-setup-link.rules ++++ b/rules/80-net-setup-link.rules +@@ -4,8 +4,6 @@ SUBSYSTEM!="net", GOTO="net_setup_link_end" + + IMPORT{builtin}="path_id" + +-ACTION=="move", IMPORT{db}="ID_NET_DRIVER", IMPORT{db}="ID_NET_LINK_FILE", IMPORT{db}="ID_NET_NAME" +- + ACTION!="add", GOTO="net_setup_link_end" + + IMPORT{builtin}="net_setup_link" +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 00cd6d47db..18b92ca428 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -805,6 +805,22 @@ void udev_event_execute_rules(struct udev_event *event, + udev_watch_end(event->udev, event->dev_db); + } + ++ if (major(udev_device_get_devnum(dev)) == 0 && ++ streq(udev_device_get_action(dev), "move")) { ++ struct udev_list_entry *entry; ++ ++ for ((entry = udev_device_get_properties_list_entry(event->dev_db)); entry; entry = udev_list_entry_get_next(entry)) { ++ const char *key, *value; ++ struct udev_list_entry *property; ++ ++ key = udev_list_entry_get_name(entry); ++ value = udev_list_entry_get_value(entry); ++ ++ property = udev_device_add_property(event->dev, key, value); ++ udev_list_entry_set_num(property, true); ++ } ++ } ++ + udev_rules_apply_to_event(rules, event, timeout_usec, sigmask); + + /* rename a new network interface, if needed */ diff --git a/0206-udev-event-keep-one-rtnl-per-worker-rather-than-per-.patch b/0206-udev-event-keep-one-rtnl-per-worker-rather-than-per-.patch new file mode 100644 index 0000000..1c13f6d --- /dev/null +++ b/0206-udev-event-keep-one-rtnl-per-worker-rather-than-per-.patch @@ -0,0 +1,185 @@ +From 4c83d994566718043e61e568cc214bdc4587f869 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 9 Sep 2014 11:15:37 +0200 +Subject: [PATCH] udev: event - keep one rtnl per worker, rather than per event + +Creating the rtnl context is cheap, but freeing it may not be, due to +synchronous close(). + +Also drop some excessive logging. We now log about the changing ifname +exactly once. +--- + src/libsystemd/sd-rtnl/rtnl-util.c | 12 +++++++++--- + src/libsystemd/sd-rtnl/rtnl-util.h | 2 +- + src/udev/udev-event.c | 23 ++++++++--------------- + src/udev/udev.h | 2 ++ + src/udev/udevd.c | 8 ++++++++ + 5 files changed, 28 insertions(+), 19 deletions(-) + +diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c +index 0bc2c9b1f5..fe0f34e125 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-util.c ++++ b/src/libsystemd/sd-rtnl/rtnl-util.c +@@ -26,7 +26,7 @@ + #include "rtnl-util.h" + #include "rtnl-internal.h" + +-int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name) { ++int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL; + int r; + +@@ -34,7 +34,13 @@ int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name) { + assert(ifindex > 0); + assert(name); + +- r = sd_rtnl_message_new_link(rtnl, &message, RTM_SETLINK, ifindex); ++ if (!*rtnl) { ++ r = sd_rtnl_open(rtnl, 0); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex); + if (r < 0) + return r; + +@@ -42,7 +48,7 @@ int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name) { + if (r < 0) + return r; + +- r = sd_rtnl_call(rtnl, message, 0, NULL); ++ r = sd_rtnl_call(*rtnl, message, 0, NULL); + if (r < 0) + return r; + +diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h +index 2963f02d3e..94af3b1720 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-util.h ++++ b/src/libsystemd/sd-rtnl/rtnl-util.h +@@ -34,7 +34,7 @@ bool rtnl_message_type_is_link(uint16_t type); + bool rtnl_message_type_is_addr(uint16_t type); + bool rtnl_message_type_is_route(uint16_t type); + +-int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name); ++int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name); + int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu); + + int rtnl_log_parse_error(int r); +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 18b92ca428..1bbf41e757 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -53,6 +53,7 @@ struct udev_event *udev_event_new(struct udev_device *dev) { + void udev_event_unref(struct udev_event *event) { + if (event == NULL) + return; ++ sd_rtnl_unref(event->rtnl); + udev_list_cleanup(&event->run_list); + udev_list_cleanup(&event->seclabel_list); + free(event->program_result); +@@ -746,30 +747,24 @@ out: + + static int rename_netif(struct udev_event *event) { + struct udev_device *dev = event->dev; +- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + char name[IFNAMSIZ]; + const char *oldname; + int r; + + oldname = udev_device_get_sysname(dev); + +- log_debug("changing net interface name from '%s' to '%s'", +- oldname, event->name); +- + strscpy(name, IFNAMSIZ, event->name); + +- r = sd_rtnl_open(&rtnl, 0); +- if (r < 0) ++ r = rtnl_set_link_name(&event->rtnl, udev_device_get_ifindex(dev), name); ++ if (r < 0) { ++ log_error("error changing net interface name '%s' to '%s': %s", ++ oldname, name, strerror(-r)); + return r; ++ } + +- r = rtnl_set_link_name(rtnl, udev_device_get_ifindex(dev), name); +- if (r < 0) +- log_error("error changing net interface name %s to %s: %s", +- oldname, name, strerror(-r)); +- else +- print_kmsg("renamed network interface %s to %s\n", oldname, name); ++ print_kmsg("renamed network interface '%s' to '%s'\n", oldname, name); + +- return r; ++ return 0; + } + + void udev_event_execute_rules(struct udev_event *event, +@@ -832,8 +827,6 @@ void udev_event_execute_rules(struct udev_event *event, + + r = rename_netif(event); + if (r >= 0) { +- log_debug("renamed netif to '%s'", event->name); +- + /* remember old name */ + udev_device_add_property(dev, "INTERFACE_OLD", udev_device_get_sysname(dev)); + +diff --git a/src/udev/udev.h b/src/udev/udev.h +index faa8f566c2..ed01da30e4 100644 +--- a/src/udev/udev.h ++++ b/src/udev/udev.h +@@ -23,6 +23,7 @@ + #include + + #include "macro.h" ++#include "sd-rtnl.h" + #include "libudev.h" + #include "libudev-private.h" + #include "util.h" +@@ -44,6 +45,7 @@ struct udev_event { + int exec_delay; + usec_t birth_usec; + int fd_signal; ++ sd_rtnl *rtnl; + unsigned int builtin_run; + unsigned int builtin_ret; + bool sigterm; +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index e72c5b231e..be0acc3177 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -48,6 +48,7 @@ + + #include "udev.h" + #include "udev-util.h" ++#include "rtnl-util.h" + #include "sd-daemon.h" + #include "cgroup-util.h" + #include "dev-setup.h" +@@ -200,6 +201,7 @@ static void worker_new(struct event *event) { + case 0: { + struct udev_device *dev = NULL; + int fd_monitor; ++ _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + struct epoll_event ep_signal, ep_monitor; + sigset_t mask; + int rc = EXIT_SUCCESS; +@@ -301,11 +303,17 @@ static void worker_new(struct event *event) { + } + } + ++ /* needed for renaming netifs */ ++ udev_event->rtnl = rtnl; ++ + /* apply rules, create node, symlinks */ + udev_event_execute_rules(udev_event, event_timeout_usec, rules, &sigmask_orig); + + udev_event_execute_run(udev_event, event_timeout_usec, &sigmask_orig); + ++ /* in case rtnl was initialized */ ++ rtnl = sd_rtnl_ref(udev_event->rtnl); ++ + /* apply/restore inotify watch */ + if (udev_event->inotify_watch) { + udev_watch_begin(udev, dev); diff --git a/0207-udev-net_setup_link-open-ethtool-and-rtnl-connection.patch b/0207-udev-net_setup_link-open-ethtool-and-rtnl-connection.patch new file mode 100644 index 0000000..163a4d0 --- /dev/null +++ b/0207-udev-net_setup_link-open-ethtool-and-rtnl-connection.patch @@ -0,0 +1,303 @@ +From aedca89268ed4fd6be41e55a605f011033ad1fb5 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 9 Sep 2014 15:36:56 +0200 +Subject: [PATCH] udev: net_setup_link - open ethtool and rtnl connections + lazily + +--- + src/libsystemd/sd-rtnl/rtnl-util.c | 26 +++++++++++-------------- + src/libsystemd/sd-rtnl/rtnl-util.h | 2 +- + src/udev/net/ethtool-util.c | 40 ++++++++++++++++++++++++++++++-------- + src/udev/net/ethtool-util.h | 6 +++--- + src/udev/net/link-config.c | 40 ++++---------------------------------- + 5 files changed, 51 insertions(+), 63 deletions(-) + +diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c +index fe0f34e125..1ec1fa8d27 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-util.c ++++ b/src/libsystemd/sd-rtnl/rtnl-util.c +@@ -55,10 +55,9 @@ int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name) { + return 0; + } + +-int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, ++int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias, + const struct ether_addr *mac, unsigned mtu) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL; +- bool need_update = false; + int r; + + assert(rtnl); +@@ -67,7 +66,13 @@ int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, + if (!alias && !mac && mtu == 0) + return 0; + +- r = sd_rtnl_message_new_link(rtnl, &message, RTM_SETLINK, ifindex); ++ if (!*rtnl) { ++ r = sd_rtnl_open(rtnl, 0); ++ if (r < 0) ++ return r; ++ } ++ ++ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex); + if (r < 0) + return r; + +@@ -75,32 +80,23 @@ int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, + r = sd_rtnl_message_append_string(message, IFLA_IFALIAS, alias); + if (r < 0) + return r; +- +- need_update = true; +- + } + + if (mac) { + r = sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, mac); + if (r < 0) + return r; +- +- need_update = true; + } + + if (mtu > 0) { + r = sd_rtnl_message_append_u32(message, IFLA_MTU, mtu); + if (r < 0) + return r; +- +- need_update = true; + } + +- if (need_update) { +- r = sd_rtnl_call(rtnl, message, 0, NULL); +- if (r < 0) +- return r; +- } ++ r = sd_rtnl_call(*rtnl, message, 0, NULL); ++ if (r < 0) ++ return r; + + return 0; + } +diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h +index 94af3b1720..fa3592df9d 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-util.h ++++ b/src/libsystemd/sd-rtnl/rtnl-util.h +@@ -35,7 +35,7 @@ bool rtnl_message_type_is_addr(uint16_t type); + bool rtnl_message_type_is_route(uint16_t type); + + int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name); +-int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu); ++int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu); + + int rtnl_log_parse_error(int r); + int rtnl_log_create_error(int r); +diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c +index 3ec245ecab..54cb928091 100644 +--- a/src/udev/net/ethtool-util.c ++++ b/src/udev/net/ethtool-util.c +@@ -63,7 +63,7 @@ int ethtool_connect(int *ret) { + return 0; + } + +-int ethtool_get_driver(int fd, const char *ifname, char **ret) { ++int ethtool_get_driver(int *fd, const char *ifname, char **ret) { + struct ethtool_drvinfo ecmd = { + .cmd = ETHTOOL_GDRVINFO + }; +@@ -73,9 +73,17 @@ int ethtool_get_driver(int fd, const char *ifname, char **ret) { + char *d; + int r; + ++ if (*fd < 0) { ++ r = ethtool_connect(fd); ++ if (r < 0) { ++ log_warning("link_config: could not connect to ethtool: %s", strerror(-r)); ++ return r; ++ } ++ } ++ + strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + +- r = ioctl(fd, SIOCETHTOOL, &ifr); ++ r = ioctl(*fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + +@@ -87,7 +95,7 @@ int ethtool_get_driver(int fd, const char *ifname, char **ret) { + return 0; + } + +-int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex duplex) ++int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) + { + struct ethtool_cmd ecmd = { + .cmd = ETHTOOL_GSET +@@ -101,9 +109,17 @@ int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex dup + if (speed == 0 && duplex == _DUP_INVALID) + return 0; + ++ if (*fd < 0) { ++ r = ethtool_connect(fd); ++ if (r < 0) { ++ log_warning("link_config: could not connect to ethtool: %s", strerror(-r)); ++ return r; ++ } ++ } ++ + strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + +- r = ioctl(fd, SIOCETHTOOL, &ifr); ++ r = ioctl(*fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + +@@ -132,7 +148,7 @@ int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex dup + if (need_update) { + ecmd.cmd = ETHTOOL_SSET; + +- r = ioctl(fd, SIOCETHTOOL, &ifr); ++ r = ioctl(*fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + } +@@ -140,7 +156,7 @@ int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex dup + return 0; + } + +-int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol) { ++int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) { + struct ethtool_wolinfo ecmd = { + .cmd = ETHTOOL_GWOL + }; +@@ -153,9 +169,17 @@ int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol) { + if (wol == _WOL_INVALID) + return 0; + ++ if (*fd < 0) { ++ r = ethtool_connect(fd); ++ if (r < 0) { ++ log_warning("link_config: could not connect to ethtool: %s", strerror(-r)); ++ return r; ++ } ++ } ++ + strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + +- r = ioctl(fd, SIOCETHTOOL, &ifr); ++ r = ioctl(*fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + +@@ -185,7 +209,7 @@ int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol) { + if (need_update) { + ecmd.cmd = ETHTOOL_SWOL; + +- r = ioctl(fd, SIOCETHTOOL, &ifr); ++ r = ioctl(*fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + } +diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h +index f44de5076a..690b1a65aa 100644 +--- a/src/udev/net/ethtool-util.h ++++ b/src/udev/net/ethtool-util.h +@@ -42,9 +42,9 @@ typedef enum WakeOnLan { + + int ethtool_connect(int *ret); + +-int ethtool_get_driver(int fd, const char *ifname, char **ret); +-int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex duplex); +-int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol); ++int ethtool_get_driver(int *fd, const char *ifname, char **ret); ++int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex); ++int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol); + + const char *duplex_to_string(Duplex d) _const_; + Duplex duplex_from_string(const char *d) _pure_; +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index 64ff00dc0d..ee2865a863 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -88,30 +88,6 @@ int link_config_ctx_new(link_config_ctx **ret) { + return 0; + } + +-static int link_config_ctx_connect(link_config_ctx *ctx) { +- int r; +- +- if (ctx->ethtool_fd == -1) { +- r = ethtool_connect(&ctx->ethtool_fd); +- if (r < 0) { +- log_warning("link_config: could not connect to ethtool: %s", +- strerror(-r)); +- return r; +- } +- } +- +- if (!ctx->rtnl) { +- r = sd_rtnl_open(&ctx->rtnl, 0); +- if (r < 0) { +- log_warning("link_config: could not connect to rtnl: %s", +- strerror(-r)); +- return r; +- } +- } +- +- return 0; +-} +- + static void link_configs_free(link_config_ctx *ctx) { + link_config *link, *link_next; + +@@ -361,22 +337,18 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, + assert(device); + assert(name); + +- r = link_config_ctx_connect(ctx); +- if (r < 0) +- return r; +- + old_name = udev_device_get_sysname(device); + if (!old_name) + return -EINVAL; + +- r = ethtool_set_speed(ctx->ethtool_fd, old_name, config->speed / 1024, ++ r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024, + config->duplex); + if (r < 0) + log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s", + old_name, config->speed / 1024, + duplex_to_string(config->duplex), strerror(-r)); + +- r = ethtool_set_wol(ctx->ethtool_fd, old_name, config->wol); ++ r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol); + if (r < 0) + log_warning("Could not set WakeOnLan of %s to %s: %s", + old_name, wol_to_string(config->wol), strerror(-r)); +@@ -449,7 +421,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, ++ r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, + config->mtu); + if (r < 0) { + log_warning("Could not set Alias, MACAddress or MTU on %s: %s", +@@ -467,15 +439,11 @@ int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret + char *driver; + int r; + +- r = link_config_ctx_connect(ctx); +- if (r < 0) +- return r; +- + name = udev_device_get_sysname(device); + if (!name) + return -EINVAL; + +- r = ethtool_get_driver(ctx->ethtool_fd, name, &driver); ++ r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver); + if (r < 0) + return r; + diff --git a/0208-udev-netif_rename-don-t-log-to-kmsg.patch b/0208-udev-netif_rename-don-t-log-to-kmsg.patch new file mode 100644 index 0000000..bd50299 --- /dev/null +++ b/0208-udev-netif_rename-don-t-log-to-kmsg.patch @@ -0,0 +1,23 @@ +From 1187f20655de0c37337ea73e1e55823b83cd7c00 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 9 Sep 2014 22:45:03 +0200 +Subject: [PATCH] udev: netif_rename - don't log to kmsg + +As of 3.17, the kernel will do this on its own, so just do regular log_debug() logging from udev. +--- + src/udev/udev-event.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 1bbf41e757..a883edca07 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -762,7 +762,7 @@ static int rename_netif(struct udev_event *event) { + return r; + } + +- print_kmsg("renamed network interface '%s' to '%s'\n", oldname, name); ++ log_debug("renamed network interface '%s' to '%s'\n", oldname, name); + + return 0; + } diff --git a/0209-udev-drop-print_kmsg.patch b/0209-udev-drop-print_kmsg.patch new file mode 100644 index 0000000..2273cd1 --- /dev/null +++ b/0209-udev-drop-print_kmsg.patch @@ -0,0 +1,69 @@ +From 9d19a679f23c7a72c326cbbbf44e0c9f423dec5d Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 9 Sep 2014 22:48:07 +0200 +Subject: [PATCH] udev - drop print_kmsg + +The only remaining user was 'starting version XXX', which is now logged using log_info(). +--- + src/libudev/libudev-private.h | 1 - + src/libudev/libudev-util.c | 25 ------------------------- + src/udev/udevd.c | 2 +- + 3 files changed, 1 insertion(+), 27 deletions(-) + +diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h +index ae975575dc..cd1c1fb8b3 100644 +--- a/src/libudev/libudev-private.h ++++ b/src/libudev/libudev-private.h +@@ -170,6 +170,5 @@ int util_delete_path(struct udev *udev, const char *path); + uid_t util_lookup_user(struct udev *udev, const char *user); + gid_t util_lookup_group(struct udev *udev, const char *group); + int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); +-ssize_t print_kmsg(const char *fmt, ...) _printf_(1, 2); + + #endif +diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c +index d9cdde1751..9e19e31407 100644 +--- a/src/libudev/libudev-util.c ++++ b/src/libudev/libudev-util.c +@@ -415,28 +415,3 @@ uint64_t util_string_bloom64(const char *str) + bits |= 1LLU << ((hash >> 18) & 63); + return bits; + } +- +-ssize_t print_kmsg(const char *fmt, ...) +-{ +- _cleanup_close_ int fd = -1; +- va_list ap; +- char text[1024]; +- ssize_t len; +- ssize_t ret; +- +- fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); +- if (fd < 0) +- return -errno; +- +- len = snprintf(text, sizeof(text), "<30>systemd-udevd[%u]: ", getpid()); +- +- va_start(ap, fmt); +- len += vsnprintf(text + len, sizeof(text) - len, fmt, ap); +- va_end(ap); +- +- ret = write(fd, text, len); +- if (ret < 0) +- return -errno; +- +- return ret; +-} +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index be0acc3177..b023b6ee4c 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1200,7 +1200,7 @@ int main(int argc, char *argv[]) { + sd_notify(1, "READY=1"); + } + +- print_kmsg("starting version " VERSION "\n"); ++ log_info("starting version " VERSION "\n"); + + if (!debug) { + int fd; diff --git a/0210-sd-dhcp6-client-Implement-Elapsed-Time-option.patch b/0210-sd-dhcp6-client-Implement-Elapsed-Time-option.patch new file mode 100644 index 0000000..770f4d1 --- /dev/null +++ b/0210-sd-dhcp6-client-Implement-Elapsed-Time-option.patch @@ -0,0 +1,126 @@ +From 346e13a25dc6f76d3bc9d8decd40dc4782b02d2a Mon Sep 17 00:00:00 2001 +From: Patrik Flykt +Date: Mon, 1 Sep 2014 13:21:33 +0300 +Subject: [PATCH] sd-dhcp6-client: Implement Elapsed Time option + +Implement Elapsed Time option as it is defined as MUST in RFC 3315, +section 22.9. The elapsed time value is a 1/100th of a second with +a max value of 0xffff, i.e. 655.35 seconds. + +As the main loop might not be running yet when sd_dhcp6_client_start() is +called, fetch the monotonic time directly and not from the event loop +while in state DHCP6_STATE_STOPPED. +--- + src/libsystemd-network/sd-dhcp6-client.c | 40 ++++++++++++++++++++++++-------- + 1 file changed, 30 insertions(+), 10 deletions(-) + +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index 6860c66858..c190b560ea 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -49,6 +49,7 @@ struct sd_dhcp6_client { + struct ether_addr mac_addr; + DHCP6IA ia_na; + be32_t transaction_id; ++ usec_t transaction_start; + struct sd_dhcp6_lease *lease; + int fd; + be16_t *req_opts; +@@ -203,6 +204,7 @@ static int client_reset(sd_dhcp6_client *client) { + client->fd = safe_close(client->fd); + + client->transaction_id = 0; ++ client->transaction_start = 0; + + client->ia_na.timeout_t1 = + sd_event_source_unref(client->ia_na.timeout_t1); +@@ -230,13 +232,15 @@ static void client_stop(sd_dhcp6_client *client, int error) { + client_reset(client); + } + +-static int client_send_message(sd_dhcp6_client *client) { ++static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { + _cleanup_free_ DHCP6Message *message = NULL; + struct in6_addr all_servers = + IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT; + size_t len, optlen = 512; + uint8_t *opt; + int r; ++ usec_t elapsed_usec; ++ be16_t elapsed_time; + + len = sizeof(DHCP6Message) + optlen; + +@@ -308,6 +312,17 @@ static int client_send_message(sd_dhcp6_client *client) { + if (r < 0) + return r; + ++ elapsed_usec = time_now - client->transaction_start; ++ if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10) ++ elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10); ++ else ++ elapsed_time = 0xffff; ++ ++ r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ELAPSED_TIME, ++ sizeof(elapsed_time), &elapsed_time); ++ if (r < 0) ++ return r; ++ + r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message, + len - optlen); + if (r < 0) +@@ -455,15 +470,14 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, + return 0; + } + +- r = client_send_message(client); +- if (r >= 0) +- client->retransmit_count++; +- +- + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + goto error; + ++ r = client_send_message(client, time_now); ++ if (r >= 0) ++ client->retransmit_count++; ++ + if (!client->retransmit_time) { + client->retransmit_time = + client_timeout_compute_random(init_retransmit_time); +@@ -882,6 +896,15 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) + client->retransmit_time = 0; + client->retransmit_count = 0; + ++ if (client->state == DHCP6_STATE_STOPPED) { ++ time_now = now(clock_boottime_or_monotonic()); ++ } else { ++ r = sd_event_now(client->event, clock_boottime_or_monotonic(), ++ &time_now); ++ if (r < 0) ++ return r; ++ } ++ + switch (state) { + case DHCP6_STATE_STOPPED: + case DHCP6_STATE_SOLICITATION: +@@ -926,10 +949,6 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) + + case DHCP6_STATE_BOUND: + +- r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); +- if (r < 0) +- return r; +- + if (client->lease->ia.lifetime_t1 == 0xffffffff || + client->lease->ia.lifetime_t2 == 0xffffffff) { + +@@ -996,6 +1015,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) + } + + client->transaction_id = random_u32() & htobe32(0x00ffffff); ++ client->transaction_start = time_now; + + r = sd_event_add_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), 0, 0, client_timeout_resend, diff --git a/0211-test-dhcp6-client-Add-checks-for-Elapsed-Time-option.patch b/0211-test-dhcp6-client-Add-checks-for-Elapsed-Time-option.patch new file mode 100644 index 0000000..960b263 --- /dev/null +++ b/0211-test-dhcp6-client-Add-checks-for-Elapsed-Time-option.patch @@ -0,0 +1,89 @@ +From d63be95a306bf1e262c7e1c7ad4b2c12b49d371e Mon Sep 17 00:00:00 2001 +From: Patrik Flykt +Date: Mon, 1 Sep 2014 13:21:34 +0300 +Subject: [PATCH] test-dhcp6-client: Add checks for Elapsed Time option + +Verify that the Elapsed Time option is present. +--- + src/libsystemd-network/test-dhcp6-client.c | 32 ++++++++++++++++++++++++++---- + 1 file changed, 28 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c +index d102a796b4..37ddfc2cfa 100644 +--- a/src/libsystemd-network/test-dhcp6-client.c ++++ b/src/libsystemd-network/test-dhcp6-client.c +@@ -269,6 +269,11 @@ static int test_advertise_option(sd_event *e) { + *optval) >= 0); + break; + ++ case DHCP6_OPTION_ELAPSED_TIME: ++ assert_se(optlen == 2); ++ ++ break; ++ + default: + break; + } +@@ -361,7 +366,8 @@ static int test_client_verify_request(DHCP6Message *request, uint8_t *option, + uint8_t *optval; + uint16_t optcode; + size_t optlen; +- bool found_clientid = false, found_iana = false, found_serverid = false; ++ bool found_clientid = false, found_iana = false, found_serverid = false, ++ found_elapsed_time = false; + int r; + struct in6_addr addr; + be32_t val; +@@ -410,11 +416,20 @@ static int test_client_verify_request(DHCP6Message *request, uint8_t *option, + assert_se(!memcmp(&msg_advertise[179], optval, optlen)); + + break; ++ ++ case DHCP6_OPTION_ELAPSED_TIME: ++ assert_se(!found_elapsed_time); ++ found_elapsed_time = true; ++ ++ assert_se(optlen == 2); ++ ++ break; + } + } + + assert_se(r == -ENOMSG); +- assert_se(found_clientid && found_iana && found_serverid); ++ assert_se(found_clientid && found_iana && found_serverid && ++ found_elapsed_time); + + assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, <_pref, + <_valid) >= 0); +@@ -452,7 +467,8 @@ static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option, + uint8_t *optval; + uint16_t optcode; + size_t optlen; +- bool found_clientid = false, found_iana = false; ++ bool found_clientid = false, found_iana = false, ++ found_elapsed_time = false; + int r; + + assert_se(solicit->type == DHCP6_SOLICIT); +@@ -478,11 +494,19 @@ static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option, + memcpy(&test_iaid, optval, sizeof(test_iaid)); + + break; ++ ++ case DHCP6_OPTION_ELAPSED_TIME: ++ assert_se(!found_elapsed_time); ++ found_elapsed_time = true; ++ ++ assert_se(optlen == 2); ++ ++ break; + } + } + + assert_se(r == -ENOMSG); +- assert_se(found_clientid && found_iana); ++ assert_se(found_clientid && found_iana && found_elapsed_time); + + return 0; + } diff --git a/0212-TODO-Remove-Elapsed-Time-DHCPv6-option-as-it-is-done.patch b/0212-TODO-Remove-Elapsed-Time-DHCPv6-option-as-it-is-done.patch new file mode 100644 index 0000000..8132e35 --- /dev/null +++ b/0212-TODO-Remove-Elapsed-Time-DHCPv6-option-as-it-is-done.patch @@ -0,0 +1,21 @@ +From e9385929c8eb591b64e657a5d53d187af418a3f7 Mon Sep 17 00:00:00 2001 +From: Patrik Flykt +Date: Mon, 1 Sep 2014 13:21:35 +0300 +Subject: [PATCH] TODO: Remove Elapsed Time DHCPv6 option as it is done + +--- + TODO | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/TODO b/TODO +index f036430c43..9ac6fac8cf 100644 +--- a/TODO ++++ b/TODO +@@ -703,7 +703,6 @@ Features: + - implement reconfigure support, see 5.3., 15.11. and 22.20. + - implement information request, see 1.2. and 18.1.5. + - implement support for temporary adressess (IA_TA) +- - implement elapsed time option + - implement dhcpv6 authentication + - investigate the usefulness of Confirm messages; i.e. are there any + situations where the link changes without any loss in carrier detection diff --git a/0213-udev-fix-copy-paste-error-in-log-message.patch b/0213-udev-fix-copy-paste-error-in-log-message.patch new file mode 100644 index 0000000..7cee155 --- /dev/null +++ b/0213-udev-fix-copy-paste-error-in-log-message.patch @@ -0,0 +1,22 @@ +From ec3281d3b681b002dfe1a4bea0532a504e37557a Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 10 Sep 2014 07:59:22 +0200 +Subject: [PATCH] udev: fix copy-paste error in log message + +--- + src/udev/udev-rules.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index cc562156fa..6de7511c7d 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -1323,7 +1323,7 @@ static int add_rule(struct udev_rules *rules, char *line, + if (cmd < UDEV_BUILTIN_MAX) + rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); + else +- log_error("IMPORT{builtin}: '%s' unknown %s:%u", value, filename, lineno); ++ log_error("RUN{builtin}: '%s' unknown %s:%u", value, filename, lineno); + } else if (streq(attr, "program")) { + enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX; + diff --git a/0214-udev-timeout-increase-timeout.patch b/0214-udev-timeout-increase-timeout.patch new file mode 100644 index 0000000..5f6de10 --- /dev/null +++ b/0214-udev-timeout-increase-timeout.patch @@ -0,0 +1,25 @@ +From b5338a19864ac3f5632aee48069a669479621dca Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 10 Sep 2014 10:56:26 +0200 +Subject: [PATCH] udev: timeout - increase timeout + +Some kernel modules still take more than one minute to insmod, we no longer rely on the timeout +killing insmod within a given period of time, so just bump this to a much higher value. Its only +purpose is to make sure that nothing stays aronud forever. +--- + src/udev/udevd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index b023b6ee4c..a7f8cbdf5b 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -74,7 +74,7 @@ static bool reload; + static int children; + static int children_max; + static int exec_delay; +-static usec_t event_timeout_usec = 60 * USEC_PER_SEC; ++static usec_t event_timeout_usec = 180 * USEC_PER_SEC; + static sigset_t sigmask_orig; + static UDEV_LIST(event_list); + static UDEV_LIST(worker_list); diff --git a/0215-backlight-Avoid-error-when-state-restore-is-disabled.patch b/0215-backlight-Avoid-error-when-state-restore-is-disabled.patch new file mode 100644 index 0000000..9de0d0c --- /dev/null +++ b/0215-backlight-Avoid-error-when-state-restore-is-disabled.patch @@ -0,0 +1,30 @@ +From b76388e123e8d73ded1fd53937d816b314948517 Mon Sep 17 00:00:00 2001 +From: Michael Biebl +Date: Thu, 11 Sep 2014 00:49:36 +0200 +Subject: [PATCH] backlight: Avoid error when state restore is disabled + +When the state restore is disabled, we would print: +"Unknown verb: load" instead of simply skipping loading the +state. +--- + src/backlight/backlight.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c +index 4d94ebf58a..0a2bac6f16 100644 +--- a/src/backlight/backlight.c ++++ b/src/backlight/backlight.c +@@ -372,9 +372,12 @@ int main(int argc, char *argv[]) { + * device probing should be complete), so that the validity + * check at boot time doesn't have to be reliable. */ + +- if (streq(argv[1], "load") && shall_restore_state()) { ++ if (streq(argv[1], "load")) { + _cleanup_free_ char *value = NULL; + ++ if (!shall_restore_state()) ++ return EXIT_SUCCESS; ++ + if (!validate_device(udev, device)) + return EXIT_SUCCESS; + diff --git a/0216-terminal-discard-async-read-errors-for-evdev.patch b/0216-terminal-discard-async-read-errors-for-evdev.patch new file mode 100644 index 0000000..c1581cc --- /dev/null +++ b/0216-terminal-discard-async-read-errors-for-evdev.patch @@ -0,0 +1,26 @@ +From 98b7fe2ad4055a7978edc28caaadd5a0a9bd97a9 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 2 Sep 2014 14:17:59 +0200 +Subject: [PATCH] terminal: discard async read() errors for evdev + +If read() fails on evdev devices, we deal with this in idev_evdev_hup(). +It is very likely this is an async revoke, therefore, we must not abort. +Fix our io helper to discard such errors after passing them to +idev_evdev_hup(), so we don't bail out of the event loop. +--- + src/libsystemd-terminal/idev-evdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index c93ede8dc9..9e2dc811ef 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -217,7 +217,7 @@ static int idev_evdev_io(idev_evdev *evdev) { + + error: + idev_evdev_hup(evdev); +- return r; ++ return 0; /* idev_evdev_hup() handles the error so discard it */ + } + + static int idev_evdev_event_fn(sd_event_source *s, int fd, uint32_t revents, void *userdata) { diff --git a/0217-terminal-remove-redundant-struct-prefixes.patch b/0217-terminal-remove-redundant-struct-prefixes.patch new file mode 100644 index 0000000..20308c3 --- /dev/null +++ b/0217-terminal-remove-redundant-struct-prefixes.patch @@ -0,0 +1,39 @@ +From 2e1dd622ee7020a608c3397768ea245dcb6409d1 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 2 Sep 2014 14:19:38 +0200 +Subject: [PATCH] terminal: remove redundant "struct" prefixes + +We define typedefs for all internal types so drop the redundant "struct" +prefix. +--- + src/libsystemd-terminal/idev-evdev.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index 9e2dc811ef..be9b0301a4 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -41,7 +41,7 @@ typedef struct unmanaged_evdev unmanaged_evdev; + typedef struct managed_evdev managed_evdev; + + struct idev_evdev { +- struct idev_element element; ++ idev_element element; + struct libevdev *evdev; + int fd; + sd_event_source *fd_src; +@@ -52,12 +52,12 @@ struct idev_evdev { + }; + + struct unmanaged_evdev { +- struct idev_evdev evdev; ++ idev_evdev evdev; + char *devnode; + }; + + struct managed_evdev { +- struct idev_evdev evdev; ++ idev_evdev evdev; + dev_t devnum; + + sd_bus_slot *slot_pause_device; diff --git a/0218-udev-allow-removing-tags-via-TAG-foobar.patch b/0218-udev-allow-removing-tags-via-TAG-foobar.patch new file mode 100644 index 0000000..d607818 --- /dev/null +++ b/0218-udev-allow-removing-tags-via-TAG-foobar.patch @@ -0,0 +1,313 @@ +From 8e3ba3772cadf6a8292b0da533062dd4d377af67 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 11 Sep 2014 13:25:21 +0200 +Subject: [PATCH] udev: allow removing tags via TAG-="foobar" + +This extends the udev parser to support OP_REMOVE (-=) and adds support +for TAG-= to remove previously set tags. We don't fail if the tag didn't +exist. + +This is pretty handy if we ship default rules for seat-assignments and +users want to exclude specific devices from that. They can easily add +rules that drop any automatically added "seat" tags again. +--- + man/udev.xml | 7 ++++ + src/libudev/libudev-device.c | 21 +++++++++++- + src/libudev/libudev-private.h | 1 + + src/udev/udev-rules.c | 78 +++++++++++++++++++++++++++++++++++++++++-- + 4 files changed, 103 insertions(+), 4 deletions(-) + +diff --git a/man/udev.xml b/man/udev.xml +index 2948b9ce2b..d77cbb0e6e 100644 +--- a/man/udev.xml ++++ b/man/udev.xml +@@ -114,6 +114,13 @@ + + + ++ -= ++ ++ Remove the value from a key that holds a list of entries. ++ ++ ++ ++ + := + + Assign a value to a key finally; disallow any later changes. +diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c +index f26a4c44b5..d61a2ad8f4 100644 +--- a/src/libudev/libudev-device.c ++++ b/src/libudev/libudev-device.c +@@ -1732,9 +1732,14 @@ void udev_device_set_is_initialized(struct udev_device *udev_device) + udev_device->is_initialized = true; + } + ++static bool is_valid_tag(const char *tag) ++{ ++ return !strchr(tag, ':') && !strchr(tag, ' '); ++} ++ + int udev_device_add_tag(struct udev_device *udev_device, const char *tag) + { +- if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL) ++ if (!is_valid_tag(tag)) + return -EINVAL; + udev_device->tags_uptodate = false; + if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) +@@ -1742,6 +1747,20 @@ int udev_device_add_tag(struct udev_device *udev_device, const char *tag) + return -ENOMEM; + } + ++void udev_device_remove_tag(struct udev_device *udev_device, const char *tag) ++{ ++ struct udev_list_entry *e; ++ ++ if (!is_valid_tag(tag)) ++ return; ++ e = udev_list_get_entry(&udev_device->tags_list); ++ e = udev_list_entry_get_by_name(e, tag); ++ if (e) { ++ udev_device->tags_uptodate = false; ++ udev_list_entry_delete(e); ++ } ++} ++ + void udev_device_cleanup_tags_list(struct udev_device *udev_device) + { + udev_device->tags_uptodate = false; +diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h +index cd1c1fb8b3..35ea7ba44c 100644 +--- a/src/libudev/libudev-private.h ++++ b/src/libudev/libudev-private.h +@@ -73,6 +73,7 @@ const char *udev_device_get_devpath_old(struct udev_device *udev_device); + const char *udev_device_get_id_filename(struct udev_device *udev_device); + void udev_device_set_is_initialized(struct udev_device *udev_device); + int udev_device_add_tag(struct udev_device *udev_device, const char *tag); ++void udev_device_remove_tag(struct udev_device *udev_device, const char *tag); + void udev_device_cleanup_tags_list(struct udev_device *udev_device); + usec_t udev_device_get_usec_initialized(struct udev_device *udev_device); + void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t usec_initialized); +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index 6de7511c7d..9514dde751 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -82,7 +82,7 @@ static unsigned int rules_add_string(struct udev_rules *rules, const char *s) { + return strbuf_add_string(rules->strbuf, s, strlen(s)); + } + +-/* KEY=="", KEY!="", KEY+="", KEY="", KEY:="" */ ++/* KEY=="", KEY!="", KEY+="", KEY-="", KEY="", KEY:="" */ + enum operation_type { + OP_UNSET, + +@@ -91,6 +91,7 @@ enum operation_type { + OP_MATCH_MAX, + + OP_ADD, ++ OP_REMOVE, + OP_ASSIGN, + OP_ASSIGN_FINAL, + }; +@@ -224,6 +225,7 @@ static const char *operation_str(enum operation_type type) { + [OP_MATCH_MAX] = "MATCH_MAX", + + [OP_ADD] = "add", ++ [OP_REMOVE] = "remove", + [OP_ASSIGN] = "assign", + [OP_ASSIGN_FINAL] = "assign-final", + } ; +@@ -761,7 +763,7 @@ static int get_key(struct udev *udev, char **line, char **key, enum operation_ty + break; + if (linepos[0] == '=') + break; +- if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':')) ++ if ((linepos[0] == '+') || (linepos[0] == '-') || (linepos[0] == '!') || (linepos[0] == ':')) + if (linepos[1] == '=') + break; + } +@@ -785,6 +787,9 @@ static int get_key(struct udev *udev, char **line, char **key, enum operation_ty + } else if (linepos[0] == '+' && linepos[1] == '=') { + *op = OP_ADD; + linepos += 2; ++ } else if (linepos[0] == '-' && linepos[1] == '=') { ++ *op = OP_REMOVE; ++ linepos += 2; + } else if (linepos[0] == '=') { + *op = OP_ASSIGN; + linepos++; +@@ -1121,6 +1126,10 @@ static int add_rule(struct udev_rules *rules, char *line, + log_error("error parsing ATTR attribute"); + goto invalid; + } ++ if (op == OP_REMOVE) { ++ log_error("invalid ATTR operation"); ++ goto invalid; ++ } + if (op < OP_MATCH_MAX) { + rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); + } else { +@@ -1135,6 +1144,10 @@ static int add_rule(struct udev_rules *rules, char *line, + log_error("error parsing SECLABEL attribute"); + goto invalid; + } ++ if (op == OP_REMOVE) { ++ log_error("invalid SECLABEL operation"); ++ goto invalid; ++ } + + rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); + continue; +@@ -1202,6 +1215,10 @@ static int add_rule(struct udev_rules *rules, char *line, + log_error("error parsing ENV attribute"); + goto invalid; + } ++ if (op == OP_REMOVE) { ++ log_error("invalid ENV operation"); ++ goto invalid; ++ } + if (op < OP_MATCH_MAX) { + if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0) + goto invalid; +@@ -1242,6 +1259,10 @@ static int add_rule(struct udev_rules *rules, char *line, + } + + if (streq(key, "PROGRAM")) { ++ if (op == OP_REMOVE) { ++ log_error("invalid PROGRAM operation"); ++ goto invalid; ++ } + rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); + continue; + } +@@ -1261,6 +1282,10 @@ static int add_rule(struct udev_rules *rules, char *line, + log_error("IMPORT{} type missing, ignoring IMPORT %s:%u", filename, lineno); + continue; + } ++ if (op == OP_REMOVE) { ++ log_error("invalid IMPORT operation"); ++ goto invalid; ++ } + if (streq(attr, "program")) { + /* find known built-in command */ + if (value[0] != '/') { +@@ -1316,6 +1341,10 @@ static int add_rule(struct udev_rules *rules, char *line, + attr = get_key_attribute(rules->udev, key + strlen("RUN")); + if (attr == NULL) + attr = "program"; ++ if (op == OP_REMOVE) { ++ log_error("invalid RUN operation"); ++ goto invalid; ++ } + + if (streq(attr, "builtin")) { + enum udev_builtin_cmd cmd = udev_builtin_lookup(value); +@@ -1336,21 +1365,37 @@ static int add_rule(struct udev_rules *rules, char *line, + } + + if (streq(key, "WAIT_FOR") || streq(key, "WAIT_FOR_SYSFS")) { ++ if (op == OP_REMOVE) { ++ log_error("invalid WAIT_FOR/WAIT_FOR_SYSFS operation"); ++ goto invalid; ++ } + rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL); + continue; + } + + if (streq(key, "LABEL")) { ++ if (op == OP_REMOVE) { ++ log_error("invalid LABEL operation"); ++ goto invalid; ++ } + rule_tmp.rule.rule.label_off = rules_add_string(rules, value); + continue; + } + + if (streq(key, "GOTO")) { ++ if (op == OP_REMOVE) { ++ log_error("invalid GOTO operation"); ++ goto invalid; ++ } + rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); + continue; + } + + if (startswith(key, "NAME")) { ++ if (op == OP_REMOVE) { ++ log_error("invalid NAME operation"); ++ goto invalid; ++ } + if (op < OP_MATCH_MAX) { + rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); + } else { +@@ -1371,6 +1416,10 @@ static int add_rule(struct udev_rules *rules, char *line, + } + + if (streq(key, "SYMLINK")) { ++ if (op == OP_REMOVE) { ++ log_error("invalid SYMLINK operation"); ++ goto invalid; ++ } + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); + else +@@ -1383,6 +1432,11 @@ static int add_rule(struct udev_rules *rules, char *line, + uid_t uid; + char *endptr; + ++ if (op == OP_REMOVE) { ++ log_error("invalid OWNER operation"); ++ goto invalid; ++ } ++ + uid = strtoul(value, &endptr, 10); + if (endptr[0] == '\0') { + rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); +@@ -1400,6 +1454,11 @@ static int add_rule(struct udev_rules *rules, char *line, + gid_t gid; + char *endptr; + ++ if (op == OP_REMOVE) { ++ log_error("invalid GROUP operation"); ++ goto invalid; ++ } ++ + gid = strtoul(value, &endptr, 10); + if (endptr[0] == '\0') { + rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); +@@ -1417,6 +1476,11 @@ static int add_rule(struct udev_rules *rules, char *line, + mode_t mode; + char *endptr; + ++ if (op == OP_REMOVE) { ++ log_error("invalid MODE operation"); ++ goto invalid; ++ } ++ + mode = strtol(value, &endptr, 8); + if (endptr[0] == '\0') + rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); +@@ -1429,6 +1493,11 @@ static int add_rule(struct udev_rules *rules, char *line, + if (streq(key, "OPTIONS")) { + const char *pos; + ++ if (op == OP_REMOVE) { ++ log_error("invalid OPTIONS operation"); ++ goto invalid; ++ } ++ + pos = strstr(value, "link_priority="); + if (pos != NULL) { + int prio = atoi(&pos[strlen("link_priority=")]); +@@ -2320,7 +2389,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules, + log_error("ignoring invalid tag name '%s'", tag); + break; + } +- udev_device_add_tag(event->dev, tag); ++ if (cur->key.op == OP_REMOVE) ++ udev_device_remove_tag(event->dev, tag); ++ else ++ udev_device_add_tag(event->dev, tag); + break; + } + case TK_A_NAME: { diff --git a/0219-terminal-remove-unused-set.h-inclusion-in-idev.patch b/0219-terminal-remove-unused-set.h-inclusion-in-idev.patch new file mode 100644 index 0000000..4e08e5c --- /dev/null +++ b/0219-terminal-remove-unused-set.h-inclusion-in-idev.patch @@ -0,0 +1,24 @@ +From 1f3752c81ad5d746f90db751425c39c3ed0970ab Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 11 Sep 2014 15:27:56 +0200 +Subject: [PATCH] terminal: remove unused set.h inclusion in idev + +We don't use set.h so no need to include it. We used to include it for +temporary refs on all idev devices of a session, but that never was pushed +upstream. +--- + src/libsystemd-terminal/idev.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c +index 0ed518cded..d37e0313e4 100644 +--- a/src/libsystemd-terminal/idev.c ++++ b/src/libsystemd-terminal/idev.c +@@ -33,7 +33,6 @@ + #include "idev-internal.h" + #include "login-shared.h" + #include "macro.h" +-#include "set.h" + #include "udev-util.h" + #include "util.h" + diff --git a/0220-terminal-enable-sessions-in-evcat-after-taking-contr.patch b/0220-terminal-enable-sessions-in-evcat-after-taking-contr.patch new file mode 100644 index 0000000..2cd88dd --- /dev/null +++ b/0220-terminal-enable-sessions-in-evcat-after-taking-contr.patch @@ -0,0 +1,35 @@ +From c600022303a10155f48a8eab59c6c0ae1b797699 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 11 Sep 2014 15:28:37 +0200 +Subject: [PATCH] terminal: enable sessions in evcat after taking control + +If we enable a session, any probed device might get immediately enabled. +This might cause TakeDevice() messages to be sent before we call +TakeControl(). Therefore, enable sessions *after* sending TakeControl() so +we always succeed if TakeControl() succeeds. +--- + src/libsystemd-terminal/evcat.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c +index 590a30d873..8c27fb2c54 100644 +--- a/src/libsystemd-terminal/evcat.c ++++ b/src/libsystemd-terminal/evcat.c +@@ -313,8 +313,6 @@ static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *e + return r; + } + +- idev_session_enable(e->idev_session); +- + if (e->managed) { + r = sysview_session_take_control(ev->session_add.session); + if (r < 0) { +@@ -323,6 +321,8 @@ static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *e + } + } + ++ idev_session_enable(e->idev_session); ++ + break; + case SYSVIEW_EVENT_SESSION_REMOVE: + idev_session_disable(e->idev_session); diff --git a/0221-terminal-fix-wrong-return-value-in-idev-if-fcntl-fai.patch b/0221-terminal-fix-wrong-return-value-in-idev-if-fcntl-fai.patch new file mode 100644 index 0000000..fba3073 --- /dev/null +++ b/0221-terminal-fix-wrong-return-value-in-idev-if-fcntl-fai.patch @@ -0,0 +1,24 @@ +From 667b60341f404d8f18aa0909e34d39e7d6baa56b Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 11 Sep 2014 15:29:58 +0200 +Subject: [PATCH] terminal: fix wrong return value in idev if fcntl() fails + +This might cause >=0 to be returned, even though the method failed. Fix +this and return -errno. +--- + src/libsystemd-terminal/idev-evdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index be9b0301a4..241743c3fd 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -307,7 +307,7 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) +- return r; ++ return -errno; + + flags &= O_ACCMODE; + if (flags == O_WRONLY) diff --git a/0222-terminal-drop-redundant-assertion.patch b/0222-terminal-drop-redundant-assertion.patch new file mode 100644 index 0000000..f7ca018 --- /dev/null +++ b/0222-terminal-drop-redundant-assertion.patch @@ -0,0 +1,23 @@ +From 393a5ba09f7c5360d2e5066c23d43bb82d856173 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 11 Sep 2014 15:30:56 +0200 +Subject: [PATCH] terminal: drop redundant assertion + +This assertion is already there two lines down. Drop the redundant +assertion. +--- + src/libsystemd-terminal/idev-evdev.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index 241743c3fd..6509d1011e 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -858,7 +858,6 @@ static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_de + int r; + + assert_return(s, -EINVAL); +- assert_return(s->context->sysbus, -EINVAL); + assert_return(s->managed, -EINVAL); + assert_return(s->context->sysbus, -EINVAL); + assert_return(ud, -EINVAL); diff --git a/0223-bus-avoid-using-m-kdbus-after-freeing-it.patch b/0223-bus-avoid-using-m-kdbus-after-freeing-it.patch new file mode 100644 index 0000000..df8dbcb --- /dev/null +++ b/0223-bus-avoid-using-m-kdbus-after-freeing-it.patch @@ -0,0 +1,37 @@ +From fd989a0bc999d79719408ac28b126d9c9016bcb5 Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Wed, 10 Sep 2014 12:20:38 +0300 +Subject: [PATCH] bus: avoid using m->kdbus after freeing it + +m->kdbus could be freed before it is released. Changing the +order fixes the issue. + +Found with Coverity. Fixes: CID#1237798 +--- + src/libsystemd/sd-bus/bus-message.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index d00455a112..bfb14fcce6 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -127,9 +127,6 @@ static void message_free(sd_bus_message *m) { + + message_reset_parts(m); + +- if (m->free_kdbus) +- free(m->kdbus); +- + if (m->release_kdbus) { + uint64_t off; + +@@ -137,6 +134,9 @@ static void message_free(sd_bus_message *m) { + ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off); + } + ++ if (m->free_kdbus) ++ free(m->kdbus); ++ + sd_bus_unref(m->bus); + + if (m->free_fds) { diff --git a/0224-journal-do-not-dereference-already-freed-patterns.patch b/0224-journal-do-not-dereference-already-freed-patterns.patch new file mode 100644 index 0000000..525541c --- /dev/null +++ b/0224-journal-do-not-dereference-already-freed-patterns.patch @@ -0,0 +1,27 @@ +From 48d4c7468fb5003ae45ac834de1ca85624cdd56e Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Wed, 10 Sep 2014 12:20:39 +0300 +Subject: [PATCH] journal: do not dereference already freed patterns + +In case set_consume goes wrong, the pattern name has already been +freed. So we do not try to print it in the logs, assuming the pattern +addition print will be printed just before the failure anyway. Found +with coverity. Fixes: CID#1237798 +--- + src/journal/coredumpctl.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c +index f5cf85a765..34dcae87c0 100644 +--- a/src/journal/coredumpctl.c ++++ b/src/journal/coredumpctl.c +@@ -110,8 +110,7 @@ static int add_match(Set *set, const char *match) { + log_debug("Adding pattern: %s", pattern); + r = set_consume(set, pattern); + if (r < 0) { +- log_error("Failed to add pattern '%s': %s", +- pattern, strerror(-r)); ++ log_error("Failed to add pattern: %s", strerror(-r)); + goto fail; + } + diff --git a/0225-terminal-fix-uninitialized-variable-in-strerror-log-.patch b/0225-terminal-fix-uninitialized-variable-in-strerror-log-.patch new file mode 100644 index 0000000..baa0d91 --- /dev/null +++ b/0225-terminal-fix-uninitialized-variable-in-strerror-log-.patch @@ -0,0 +1,30 @@ +From 21978bc3c90ec192130a9ea9df62a75d1262b80c Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 11 Sep 2014 17:20:11 +0200 +Subject: [PATCH] terminal: fix uninitialized variable in strerror() log + message + +We currently print weird error-messages if xkbcommon fails (which cannot +fail so far, but might in the future). Fix the uninitialized variable +warnings by setting 'r' correctly. +Thanks to Philippe De Swert for catching this (via coverity). +--- + src/libsystemd-terminal/idev-keyboard.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c +index ab9e4811b3..d5936b7d23 100644 +--- a/src/libsystemd-terminal/idev-keyboard.c ++++ b/src/libsystemd-terminal/idev-keyboard.c +@@ -770,8 +770,10 @@ static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) { + /* TODO: update LEDs */ + } + +- if (num < 0) ++ if (num < 0) { ++ r = num; + goto error; ++ } + + r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms); + if (r < 0) diff --git a/0226-journal-do-not-leak-mmaps-on-OOM.patch b/0226-journal-do-not-leak-mmaps-on-OOM.patch new file mode 100644 index 0000000..478512e --- /dev/null +++ b/0226-journal-do-not-leak-mmaps-on-OOM.patch @@ -0,0 +1,47 @@ +From b67ddc7bbe31cde7f69f9814204d9bb1d4623c47 Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Wed, 10 Sep 2014 12:20:41 +0300 +Subject: [PATCH] journal: do not leak mmaps on OOM + +After a section of memory is succesfully allocated, some of the following +actions can still fail due to lack of memory. In this case -ENOMEM is +returned without actually freeing the already mapped memory. +Found with coverity. Fixes: CID#1237762 +--- + src/journal/mmap-cache.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c +index 7dbbb5ef38..908562da27 100644 +--- a/src/journal/mmap-cache.c ++++ b/src/journal/mmap-cache.c +@@ -496,15 +496,15 @@ static int add_mmap( + + c = context_add(m, context); + if (!c) +- return -ENOMEM; ++ goto outofmem; + + f = fd_add(m, fd); + if (!f) +- return -ENOMEM; ++ goto outofmem; + + w = window_add(m); + if (!w) +- return -ENOMEM; ++ goto outofmem; + + w->keep_always = keep_always; + w->ptr = d; +@@ -522,6 +522,10 @@ static int add_mmap( + if (ret) + *ret = (uint8_t*) w->ptr + (offset - w->offset); + return 1; ++ ++outofmem: ++ munmap(d, wsize); ++ return -ENOMEM; + } + + int mmap_cache_get( diff --git a/0227-bus-unref-buscreds-on-failure.patch b/0227-bus-unref-buscreds-on-failure.patch new file mode 100644 index 0000000..ef9fa08 --- /dev/null +++ b/0227-bus-unref-buscreds-on-failure.patch @@ -0,0 +1,29 @@ +From 2b347169b9046ff2d735ef23e62a8c74f5151600 Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Wed, 10 Sep 2014 12:20:42 +0300 +Subject: [PATCH] bus: unref buscreds on failure + +Actually unref the buscreds when we are not going to return a +pointer to them. As when bus_creds_add_more fails we immediately +return the error code otherwise and leak the new buscreds. +Found with coverity. Fixes: CID#1237761 +--- + src/libsystemd/sd-bus/sd-bus.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 78e91b9654..83b3aa1c3c 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -3339,8 +3339,10 @@ _public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **re + } + + r = bus_creds_add_more(c, mask, pid, 0); +- if (r < 0) ++ if (r < 0) { ++ sd_bus_creds_unref(c); + return r; ++ } + + *ret = c; + return 0; diff --git a/0228-test-fix-mem-leak-in-fdopen-test.patch b/0228-test-fix-mem-leak-in-fdopen-test.patch new file mode 100644 index 0000000..6ab6825 --- /dev/null +++ b/0228-test-fix-mem-leak-in-fdopen-test.patch @@ -0,0 +1,30 @@ +From 3f2e132a197ba3f5172cbbcd285e9aab021de8fc Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 11 Sep 2014 17:37:30 +0200 +Subject: [PATCH] test: fix mem-leak in fdopen() test + +We must free FILE* after function return to not leak resources. Note that +this also closes our fd as fdopen() takes ownership of it. +Reported by Philippe De Swert (via coverity). +--- + src/test/test-util.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 72a8a6b130..80425ca61a 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -918,11 +918,11 @@ static void test_readlink_and_make_absolute(void) { + } + + static void test_read_one_char(void) { ++ _cleanup_fclose_ FILE *file = NULL; + char r; + bool need_nl; + char name[] = "/tmp/test-read_one_char.XXXXXX"; +- _cleanup_close_ int fd = -1; +- FILE *file; ++ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); diff --git a/0229-activate-fix-fd-leak-in-do_accept.patch b/0229-activate-fix-fd-leak-in-do_accept.patch new file mode 100644 index 0000000..6edaa59 --- /dev/null +++ b/0229-activate-fix-fd-leak-in-do_accept.patch @@ -0,0 +1,23 @@ +From aa44499da15a8fa7026463555a7a27e55e4e24a8 Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Wed, 10 Sep 2014 22:14:41 +0300 +Subject: [PATCH] activate: fix fd leak in do_accept() + +Found with Coverity. +--- + src/activate/activate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/activate/activate.c b/src/activate/activate.c +index 8942773866..0a1df37f35 100644 +--- a/src/activate/activate.c ++++ b/src/activate/activate.c +@@ -242,7 +242,7 @@ static int launch1(const char* child, char** argv, char **env, int fd) { + + static int do_accept(const char* name, char **argv, char **envp, int fd) { + _cleanup_free_ char *local = NULL, *peer = NULL; +- int fd2; ++ _cleanup_close_ int fd2 = -1; + + fd2 = accept(fd, NULL, NULL); + if (fd2 < 0) { diff --git a/0230-manager-use-correct-cleanup-function.patch b/0230-manager-use-correct-cleanup-function.patch new file mode 100644 index 0000000..ea8bea2 --- /dev/null +++ b/0230-manager-use-correct-cleanup-function.patch @@ -0,0 +1,27 @@ +From 807d0cca2b0daf4cd725298c1b5e062b1126f15b Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Thu, 11 Sep 2014 21:14:53 +0200 +Subject: [PATCH] manager: use correct cleanup function + +Close the dir instead of attempt to free it. + +Introduced in 874310b7b68c4c0d36ff07397db30a959bb7dae5 + +Found with coverity. Fixes: CID#996368 +--- + 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 9abdf475cf..095111e8c6 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -896,7 +896,7 @@ static int manager_coldplug(Manager *m) { + + static void manager_build_unit_path_cache(Manager *m) { + char **i; +- _cleanup_free_ DIR *d = NULL; ++ _cleanup_closedir_ DIR *d = NULL; + int r; + + assert(m); diff --git a/0231-firstboot-silence-a-warning.patch b/0231-firstboot-silence-a-warning.patch new file mode 100644 index 0000000..e37d44a --- /dev/null +++ b/0231-firstboot-silence-a-warning.patch @@ -0,0 +1,25 @@ +From e926f6475d2f7063f8190076a0dc9ff7ecb227c8 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Thu, 11 Sep 2014 21:29:59 +0200 +Subject: [PATCH] firstboot: silence a warning + +No change in behavoir as the fallthrough from ARG_COPY had already +set arg_copy_locale to true. + +Found with coverity. Fixes: CID#1237622 +--- + src/firstboot/firstboot.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c +index fd73adbac8..215c059ee2 100644 +--- a/src/firstboot/firstboot.c ++++ b/src/firstboot/firstboot.c +@@ -856,6 +856,7 @@ static int parse_argv(int argc, char *argv[]) { + + case ARG_COPY: + arg_copy_locale = arg_copy_timezone = arg_copy_root_password = true; ++ break; + + case ARG_COPY_LOCALE: + arg_copy_locale = true; diff --git a/0232-udev-timeout-warn-after-a-third-of-the-timeout-befor.patch b/0232-udev-timeout-warn-after-a-third-of-the-timeout-befor.patch new file mode 100644 index 0000000..4dfb104 --- /dev/null +++ b/0232-udev-timeout-warn-after-a-third-of-the-timeout-befor.patch @@ -0,0 +1,349 @@ +From 671174136525ddf208cdbe75d6d6bd159afa961f Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 11 Sep 2014 18:49:04 +0200 +Subject: [PATCH] udev: timeout - warn after a third of the timeout before + killing + +--- + src/test/test-udev.c | 4 ++-- + src/udev/udev-event.c | 40 ++++++++++++++++++++++++++++++---------- + src/udev/udev-rules.c | 8 +++++--- + src/udev/udev.h | 9 ++++++--- + src/udev/udevadm-test.c | 2 +- + src/udev/udevd.c | 40 +++++++++++++++++++++++++++------------- + 6 files changed, 71 insertions(+), 32 deletions(-) + +diff --git a/src/test/test-udev.c b/src/test/test-udev.c +index 566a73a066..f085262b01 100644 +--- a/src/test/test-udev.c ++++ b/src/test/test-udev.c +@@ -153,8 +153,8 @@ int main(int argc, char *argv[]) { + } + } + +- udev_event_execute_rules(event, USEC_PER_SEC, rules, &sigmask_orig); +- udev_event_execute_run(event, USEC_PER_SEC, NULL); ++ udev_event_execute_rules(event, 3 * USEC_PER_SEC, USEC_PER_SEC, rules, &sigmask_orig); ++ udev_event_execute_run(event, 3 * USEC_PER_SEC, USEC_PER_SEC, NULL); + out: + if (event != NULL && event->fd_signal >= 0) + close(event->fd_signal); +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index a883edca07..e8d6676616 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -541,6 +541,7 @@ out: + + static int spawn_wait(struct udev_event *event, + usec_t timeout_usec, ++ usec_t timeout_warn_usec, + const char *cmd, pid_t pid) { + struct pollfd pfd[1]; + int err = 0; +@@ -550,6 +551,7 @@ static int spawn_wait(struct udev_event *event, + + while (pid > 0) { + int timeout; ++ int timeout_warn = 0; + int fdcount; + + if (timeout_usec > 0) { +@@ -558,13 +560,17 @@ static int spawn_wait(struct udev_event *event, + age_usec = now(CLOCK_MONOTONIC) - event->birth_usec; + if (age_usec >= timeout_usec) + timeout = 1000; +- else +- timeout = ((timeout_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC; ++ else { ++ if (timeout_warn_usec > 0) ++ timeout_warn = ((timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC; ++ ++ timeout = ((timeout_usec - timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC; ++ } + } else { + timeout = -1; + } + +- fdcount = poll(pfd, 1, timeout); ++ fdcount = poll(pfd, 1, timeout_warn); + if (fdcount < 0) { + if (errno == EINTR) + continue; +@@ -573,8 +579,20 @@ static int spawn_wait(struct udev_event *event, + goto out; + } + if (fdcount == 0) { +- log_error("timeout: killing '%s' [%u]", cmd, pid); +- kill(pid, SIGKILL); ++ log_warning("slow: '%s' [%u]", cmd, pid); ++ ++ fdcount = poll(pfd, 1, timeout); ++ if (fdcount < 0) { ++ if (errno == EINTR) ++ continue; ++ err = -errno; ++ log_error("failed to poll: %m"); ++ goto out; ++ } ++ if (fdcount == 0) { ++ log_error("timeout: killing '%s' [%u]", cmd, pid); ++ kill(pid, SIGKILL); ++ } + } + + if (pfd[0].revents & POLLIN) { +@@ -654,6 +672,7 @@ out: + + int udev_event_spawn(struct udev_event *event, + usec_t timeout_usec, ++ usec_t timeout_warn_usec, + const char *cmd, char **envp, const sigset_t *sigmask, + char *result, size_t ressize) { + struct udev *udev = event->udev; +@@ -730,7 +749,7 @@ int udev_event_spawn(struct udev_event *event, + outpipe[READ_END], errpipe[READ_END], + result, ressize); + +- err = spawn_wait(event, timeout_usec, cmd, pid); ++ err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid); + } + + out: +@@ -769,6 +788,7 @@ static int rename_netif(struct udev_event *event) { + + void udev_event_execute_rules(struct udev_event *event, + usec_t timeout_usec, ++ usec_t timeout_warn_usec, + struct udev_rules *rules, const sigset_t *sigmask) { + struct udev_device *dev = event->dev; + +@@ -783,7 +803,7 @@ void udev_event_execute_rules(struct udev_event *event, + if (major(udev_device_get_devnum(dev)) != 0) + udev_watch_end(event->udev, dev); + +- udev_rules_apply_to_event(rules, event, timeout_usec, sigmask); ++ udev_rules_apply_to_event(rules, event, timeout_usec, timeout_warn_usec, sigmask); + + if (major(udev_device_get_devnum(dev)) != 0) + udev_node_remove(dev); +@@ -816,7 +836,7 @@ void udev_event_execute_rules(struct udev_event *event, + } + } + +- udev_rules_apply_to_event(rules, event, timeout_usec, sigmask); ++ udev_rules_apply_to_event(rules, event, timeout_usec, timeout_warn_usec, sigmask); + + /* rename a new network interface, if needed */ + if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && +@@ -889,7 +909,7 @@ void udev_event_execute_rules(struct udev_event *event, + } + } + +-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, const sigset_t *sigmask) { ++void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigmask) { + struct udev_list_entry *list_entry; + + udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) { +@@ -912,7 +932,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, const + + udev_event_apply_format(event, cmd, program, sizeof(program)); + envp = udev_device_get_properties_envp(event->dev); +- udev_event_spawn(event, timeout_usec, program, envp, sigmask, NULL, 0); ++ udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, NULL, 0); + } + } + } +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index 9514dde751..db95442fda 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -615,6 +615,7 @@ static int import_file_into_properties(struct udev_device *dev, const char *file + + static int import_program_into_properties(struct udev_event *event, + usec_t timeout_usec, ++ usec_t timeout_warn_usec, + const char *program, const sigset_t *sigmask) { + struct udev_device *dev = event->dev; + char **envp; +@@ -623,7 +624,7 @@ static int import_program_into_properties(struct udev_event *event, + int err; + + envp = udev_device_get_properties_envp(dev); +- err = udev_event_spawn(event, timeout_usec, program, envp, sigmask, result, sizeof(result)); ++ err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result)); + if (err < 0) + return err; + +@@ -1862,6 +1863,7 @@ enum escape_type { + int udev_rules_apply_to_event(struct udev_rules *rules, + struct udev_event *event, + usec_t timeout_usec, ++ usec_t timeout_warn_usec, + const sigset_t *sigmask) { + struct token *cur; + struct token *rule; +@@ -2070,7 +2072,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + +- if (udev_event_spawn(event, timeout_usec, program, envp, sigmask, result, sizeof(result)) < 0) { ++ if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result)) < 0) { + if (cur->key.op != OP_NOMATCH) + goto nomatch; + } else { +@@ -2106,7 +2108,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + +- if (import_program_into_properties(event, timeout_usec, import, sigmask) != 0) ++ if (import_program_into_properties(event, timeout_usec, timeout_warn_usec, import, sigmask) != 0) + if (cur->key.op != OP_NOMATCH) + goto nomatch; + break; +diff --git a/src/udev/udev.h b/src/udev/udev.h +index ed01da30e4..765ba9e86d 100644 +--- a/src/udev/udev.h ++++ b/src/udev/udev.h +@@ -73,7 +73,8 @@ struct udev_rules; + struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names); + struct udev_rules *udev_rules_unref(struct udev_rules *rules); + bool udev_rules_check_timestamp(struct udev_rules *rules); +-int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, usec_t timeout_usec, const sigset_t *sigmask); ++int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, ++ const sigset_t *sigmask); + int udev_rules_apply_static_dev_perms(struct udev_rules *rules); + + /* udev-event.c */ +@@ -84,10 +85,12 @@ int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string, + char *result, size_t maxsize, int read_value); + int udev_event_spawn(struct udev_event *event, + usec_t timeout_usec, ++ usec_t timeout_warn_usec, + const char *cmd, char **envp, const sigset_t *sigmask, + char *result, size_t ressize); +-void udev_event_execute_rules(struct udev_event *event, usec_t timeout_usec, struct udev_rules *rules, const sigset_t *sigset); +-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, const sigset_t *sigset); ++void udev_event_execute_rules(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, ++ struct udev_rules *rules, const sigset_t *sigset); ++void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigset); + int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]); + + /* udev-watch.c */ +diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c +index 809adb6d9a..4738b611c3 100644 +--- a/src/udev/udevadm-test.c ++++ b/src/udev/udevadm-test.c +@@ -136,7 +136,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) { + goto out; + } + +- udev_event_execute_rules(event, 60 * USEC_PER_SEC, rules, &sigmask_orig); ++ udev_event_execute_rules(event, 60 * USEC_PER_SEC, 20 * USEC_PER_SEC, rules, &sigmask_orig); + + udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) + printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index a7f8cbdf5b..e54bfec3b3 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -75,6 +75,7 @@ static int children; + static int children_max; + static int exec_delay; + static usec_t event_timeout_usec = 180 * USEC_PER_SEC; ++static usec_t event_timeout_warn_usec = 180 * USEC_PER_SEC / 3; + static sigset_t sigmask_orig; + static UDEV_LIST(event_list); + static UDEV_LIST(worker_list); +@@ -125,6 +126,7 @@ struct worker { + enum worker_state state; + struct event *event; + usec_t event_start_usec; ++ bool event_warned; + }; + + /* passed from worker to main process */ +@@ -307,9 +309,9 @@ static void worker_new(struct event *event) { + udev_event->rtnl = rtnl; + + /* apply rules, create node, symlinks */ +- udev_event_execute_rules(udev_event, event_timeout_usec, rules, &sigmask_orig); ++ udev_event_execute_rules(udev_event, event_timeout_usec, event_timeout_warn_usec, rules, &sigmask_orig); + +- udev_event_execute_run(udev_event, event_timeout_usec, &sigmask_orig); ++ udev_event_execute_run(udev_event, event_timeout_usec, event_timeout_warn_usec, &sigmask_orig); + + /* in case rtnl was initialized */ + rtnl = sd_rtnl_ref(udev_event->rtnl); +@@ -403,6 +405,7 @@ out: + worker->pid = pid; + worker->state = WORKER_RUNNING; + worker->event_start_usec = now(CLOCK_MONOTONIC); ++ worker->event_warned = false; + worker->event = event; + event->state = EVENT_RUNNING; + udev_list_node_append(&worker->node, &worker_list); +@@ -433,6 +436,7 @@ static void event_run(struct event *event) { + worker->event = event; + worker->state = WORKER_RUNNING; + worker->event_start_usec = now(CLOCK_MONOTONIC); ++ worker->event_warned = false; + event->state = EVENT_RUNNING; + return; + } +@@ -986,6 +990,7 @@ static void kernel_cmdline_options(struct udev *udev) { + exec_delay = strtoul(opt + 16, NULL, 0); + } else if (startswith(opt, "udev.event-timeout=")) { + event_timeout_usec = strtoul(opt + 16, NULL, 0) * USEC_PER_SEC; ++ event_timeout_warn_usec = (event_timeout_usec / 3) ? : 1; + } + + free(s); +@@ -1048,6 +1053,7 @@ int main(int argc, char *argv[]) { + break; + case 't': + event_timeout_usec = strtoul(optarg, NULL, 0) * USEC_PER_SEC; ++ event_timeout_warn_usec = (event_timeout_usec / 3) ? : 1; + break; + case 'D': + debug = true; +@@ -1383,21 +1389,29 @@ int main(int argc, char *argv[]) { + /* check for hanging events */ + udev_list_node_foreach(loop, &worker_list) { + struct worker *worker = node_to_worker(loop); ++ usec_t ts; + + if (worker->state != WORKER_RUNNING) + continue; + +- if ((now(CLOCK_MONOTONIC) - worker->event_start_usec) > event_timeout_usec) { +- log_error("worker [%u] %s timeout; kill it", worker->pid, worker->event->devpath); +- kill(worker->pid, SIGKILL); +- worker->state = WORKER_KILLED; +- +- /* drop reference taken for state 'running' */ +- worker_unref(worker); +- log_error("seq %llu '%s' killed", udev_device_get_seqnum(worker->event->dev), worker->event->devpath); +- worker->event->exitcode = -64; +- event_queue_delete(worker->event); +- worker->event = NULL; ++ ts = now(CLOCK_MONOTONIC); ++ ++ if ((ts - worker->event_start_usec) > event_timeout_warn_usec) { ++ if ((ts - worker->event_start_usec) > event_timeout_usec) { ++ log_error("worker [%u] %s timeout; kill it", worker->pid, worker->event->devpath); ++ kill(worker->pid, SIGKILL); ++ worker->state = WORKER_KILLED; ++ ++ /* drop reference taken for state 'running' */ ++ worker_unref(worker); ++ log_error("seq %llu '%s' killed", udev_device_get_seqnum(worker->event->dev), worker->event->devpath); ++ worker->event->exitcode = -64; ++ event_queue_delete(worker->event); ++ worker->event = NULL; ++ } else if (!worker->event_warned) { ++ log_warning("worker [%u] %s is taking a long time", worker->pid, worker->event->devpath); ++ worker->event_warned = true; ++ } + } + } + diff --git a/0233-analyze-avoid-a-null-dereference.patch b/0233-analyze-avoid-a-null-dereference.patch new file mode 100644 index 0000000..6aa0d18 --- /dev/null +++ b/0233-analyze-avoid-a-null-dereference.patch @@ -0,0 +1,27 @@ +From d725a138c5c311ba06567d6841933aa5b7b6a435 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Thu, 11 Sep 2014 23:41:44 +0200 +Subject: [PATCH] analyze: avoid a null dereference + +If we have an error in the early sd_bus_* calls then unit_times +will still be null. + +Found with coverity. Fixes: CID#996464 +--- + src/analyze/analyze.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c +index d860a022b7..1281d6b9ea 100644 +--- a/src/analyze/analyze.c ++++ b/src/analyze/analyze.c +@@ -277,7 +277,8 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) { + return c; + + fail: +- free_unit_times(unit_times, (unsigned) c); ++ if (unit_times) ++ free_unit_times(unit_times, (unsigned) c); + return r; + } + diff --git a/0234-core-smack-setup-Actually-allow-for-succesfully-load.patch b/0234-core-smack-setup-Actually-allow-for-succesfully-load.patch new file mode 100644 index 0000000..d71c1b5 --- /dev/null +++ b/0234-core-smack-setup-Actually-allow-for-succesfully-load.patch @@ -0,0 +1,28 @@ +From b9289d4c6e13ec5fb67bfce69c826d93b004da6a Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Fri, 12 Sep 2014 16:49:48 +0300 +Subject: [PATCH] core: smack-setup: Actually allow for succesfully loading + CIPSO policy + +The line under the last switch statement *loaded_policy = true; +would never be executed. As all switch cases return 0. Thus the +policy would never be marked as loaded. + +Found with Coverity. Fixes: CID#1237785 +--- + src/core/smack-setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c +index 5f6dabf82a..5d8a26c61d 100644 +--- a/src/core/smack-setup.c ++++ b/src/core/smack-setup.c +@@ -158,7 +158,7 @@ int smack_setup(bool *loaded_policy) { + return 0; + case 0: + log_info("Successfully loaded Smack/CIPSO policies."); +- return 0; ++ break; + default: + log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.", + strerror(abs(r))); diff --git a/0235-analyze-fix-mem-leak.patch b/0235-analyze-fix-mem-leak.patch new file mode 100644 index 0000000..bc7411c --- /dev/null +++ b/0235-analyze-fix-mem-leak.patch @@ -0,0 +1,24 @@ +From 0ee9613d98cbe1f36ffc98c6bfa51dd2b798fc6d Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sat, 13 Sep 2014 12:29:43 +0200 +Subject: [PATCH] analyze: fix mem leak + +Found with Coverity. Fixes: CID#1237756 +--- + src/analyze/analyze.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c +index 1281d6b9ea..82f5cf3c57 100644 +--- a/src/analyze/analyze.c ++++ b/src/analyze/analyze.c +@@ -848,7 +848,8 @@ static int list_dependencies(sd_bus *bus, const char *name) { + char ts[FORMAT_TIMESPAN_MAX]; + struct unit_times *times; + int r; +- const char *path, *id; ++ const char *id; ++ _cleanup_free_ char *path = NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + struct boot_times *boot; diff --git a/0236-core-fix-a-potential-mem-leak.patch b/0236-core-fix-a-potential-mem-leak.patch new file mode 100644 index 0000000..1d4f142 --- /dev/null +++ b/0236-core-fix-a-potential-mem-leak.patch @@ -0,0 +1,27 @@ +From 4d5e13a125cf8d77d432225ab69826caa1d1cf59 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sat, 13 Sep 2014 12:35:06 +0200 +Subject: [PATCH] core: fix a potential mem leak + +Found with Coverity. Fixes: CID#996438 +--- + src/core/load-fragment.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 2f3acd7cbe..78da23ea57 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1367,8 +1367,11 @@ int config_parse_timer(const char *unit, + } + + v = new0(TimerValue, 1); +- if (!v) ++ if (!v) { ++ if (c) ++ free(c); + return log_oom(); ++ } + + v->base = b; + v->value = u; diff --git a/0237-core-use-correct-function-to-free-CalendarSpec.patch b/0237-core-use-correct-function-to-free-CalendarSpec.patch new file mode 100644 index 0000000..0b6baab --- /dev/null +++ b/0237-core-use-correct-function-to-free-CalendarSpec.patch @@ -0,0 +1,22 @@ +From eed9386748cb6bd7b1aecc62ea723db2e0c541ca Mon Sep 17 00:00:00 2001 +From: Dave Reisner +Date: Sat, 13 Sep 2014 11:18:26 -0400 +Subject: [PATCH] core: use correct function to free CalendarSpec + +--- + 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 78da23ea57..7cf19b93cc 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1369,7 +1369,7 @@ int config_parse_timer(const char *unit, + v = new0(TimerValue, 1); + if (!v) { + if (c) +- free(c); ++ calendar_spec_free(c); + return log_oom(); + } + diff --git a/0238-networkd-remove-vestigial-event-sources.patch b/0238-networkd-remove-vestigial-event-sources.patch new file mode 100644 index 0000000..a629c20 --- /dev/null +++ b/0238-networkd-remove-vestigial-event-sources.patch @@ -0,0 +1,38 @@ +From 124f09e8125e1eae5b058b1f287e72c85a46d557 Mon Sep 17 00:00:00 2001 +From: Dave Reisner +Date: Sat, 13 Sep 2014 14:10:33 -0400 +Subject: [PATCH] networkd: remove vestigial event sources + +187fe1db took advantage of floating events, but didn't remove pointers +it made superfluous. +--- + src/network/networkd-manager.c | 2 -- + src/network/networkd.h | 2 -- + 2 files changed, 4 deletions(-) + +diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c +index 5a4f93a06b..1614bc0091 100644 +--- a/src/network/networkd-manager.c ++++ b/src/network/networkd-manager.c +@@ -146,8 +146,6 @@ void manager_free(Manager *m) { + udev_unref(m->udev); + sd_bus_unref(m->bus); + sd_event_source_unref(m->udev_event_source); +- sd_event_source_unref(m->sigterm_event_source); +- sd_event_source_unref(m->sigint_event_source); + sd_event_unref(m->event); + + while ((link = hashmap_first(m->links))) +diff --git a/src/network/networkd.h b/src/network/networkd.h +index 7c5459b6ac..d4e79ab2f3 100644 +--- a/src/network/networkd.h ++++ b/src/network/networkd.h +@@ -174,8 +174,6 @@ struct Manager { + struct udev *udev; + struct udev_monitor *udev_monitor; + sd_event_source *udev_event_source; +- sd_event_source *sigterm_event_source; +- sd_event_source *sigint_event_source; + + char *state_file; + diff --git a/0239-resolved-fall-back-to-hardcoded-ifindex-when-checkin.patch b/0239-resolved-fall-back-to-hardcoded-ifindex-when-checkin.patch new file mode 100644 index 0000000..3b1ebc7 --- /dev/null +++ b/0239-resolved-fall-back-to-hardcoded-ifindex-when-checkin.patch @@ -0,0 +1,39 @@ +From d1c457badfce0dc86b54b2cac2c5eec99d7bc65e Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 13 Sep 2014 20:41:35 +0200 +Subject: [PATCH] resolved: fall back to hardcoded ifindex when checking if a + link is the loopback + +Reported by Philippe De Swert . + +Coverity CID#1237656 +--- + src/resolve/resolved-manager.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index f97989754d..00aaffe448 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -1687,6 +1687,9 @@ fail: + return r; + } + ++/* lo having ifindex 1 is hardcoded in the kernel */ ++#define LOOPBACK_IFINDEX 1 ++ + int manager_ifindex_is_loopback(Manager *m, int ifindex) { + Link *l; + assert(m); +@@ -1695,7 +1698,10 @@ int manager_ifindex_is_loopback(Manager *m, int ifindex) { + return -EINVAL; + + l = hashmap_get(m->links, INT_TO_PTR(ifindex)); +- if (l->flags & IFF_LOOPBACK) ++ if (!l) ++ /* in case we don't yet track the link, rely on the hardcoded value */ ++ return ifindex == LOOPBACK_IFINDEX; ++ else if (l->flags & IFF_LOOPBACK) + return 1; + + return 0; diff --git a/0240-sd-dhcp-fix-test-of-magic-cookie.patch b/0240-sd-dhcp-fix-test-of-magic-cookie.patch new file mode 100644 index 0000000..b548695 --- /dev/null +++ b/0240-sd-dhcp-fix-test-of-magic-cookie.patch @@ -0,0 +1,30 @@ +From 86be3e1e6558f4e7e20c537e644656eb6f37b7d0 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sun, 14 Sep 2014 22:06:37 +0200 +Subject: [PATCH] sd-dhcp: fix test of magic cookie + +The magic cookie is set in dhcp_message_init. Test the magic cookie +value intead of writing the last 3/4 of it directly. + +Found with Coverity. Fixes: CID#1237732 CID#1237734 CID#1237735 +--- + src/libsystemd-network/test-dhcp-option.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c +index 92c58e0d58..7a0fac8d33 100644 +--- a/src/libsystemd-network/test-dhcp-option.c ++++ b/src/libsystemd-network/test-dhcp-option.c +@@ -100,9 +100,9 @@ static void test_message_init(void) + magic = (uint8_t*)&message->magic; + + assert_se(magic[0] == 99); +- assert_se(magic[1] = 130); +- assert_se(magic[2] = 83); +- assert_se(magic[3] = 99); ++ assert_se(magic[1] == 130); ++ assert_se(magic[2] == 83); ++ assert_se(magic[3] == 99); + + assert_se(dhcp_option_parse(message, len, NULL, NULL) >= 0); + } diff --git a/0241-test-fix-test-of-uid-range.patch b/0241-test-fix-test-of-uid-range.patch new file mode 100644 index 0000000..dc982cc --- /dev/null +++ b/0241-test-fix-test-of-uid-range.patch @@ -0,0 +1,79 @@ +From 20755373b1494f1b718b1ac3a611c6f807905fe6 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sun, 14 Sep 2014 22:25:58 +0200 +Subject: [PATCH] test: fix test of uid-range + +The number of uid's in the range should be tested instead of written +directly. + +The test still passes with the fix checks. + +Found with Coverity. Fixes: CID#1237714 - 1237722 +--- + src/test/test-uid-range.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/test/test-uid-range.c b/src/test/test-uid-range.c +index 5f3d871b6c..06b4d43426 100644 +--- a/src/test/test-uid-range.c ++++ b/src/test/test-uid-range.c +@@ -32,7 +32,7 @@ int main(int argc, char *argv[]) { + assert_se(uid_range_add_str(&p, &n, "500-999") >= 0); + assert_se(n == 1); + assert_se(p[0].start == 500); +- assert_se(p[0].nr = 500); ++ assert_se(p[0].nr == 500); + + assert_se(!uid_range_contains(p, n, 499)); + assert_se(uid_range_contains(p, n, 500)); +@@ -52,40 +52,40 @@ int main(int argc, char *argv[]) { + assert_se(uid_range_add_str(&p, &n, "1000") >= 0); + assert_se(n == 1); + assert_se(p[0].start == 500); +- assert_se(p[0].nr = 501); ++ assert_se(p[0].nr == 501); + + assert_se(uid_range_add_str(&p, &n, "30-40") >= 0); + assert_se(n == 2); + assert_se(p[0].start == 30); +- assert_se(p[0].nr = 11); ++ assert_se(p[0].nr == 11); + assert_se(p[1].start == 500); +- assert_se(p[1].nr = 501); ++ assert_se(p[1].nr == 501); + + assert_se(uid_range_add_str(&p, &n, "60-70") >= 0); + assert_se(n == 3); + assert_se(p[0].start == 30); +- assert_se(p[0].nr = 11); ++ assert_se(p[0].nr == 11); + assert_se(p[1].start == 60); +- assert_se(p[1].nr = 11); ++ assert_se(p[1].nr == 11); + assert_se(p[2].start == 500); +- assert_se(p[2].nr = 501); ++ assert_se(p[2].nr == 501); + + assert_se(uid_range_add_str(&p, &n, "20-2000") >= 0); + assert_se(n == 1); + assert_se(p[0].start == 20); +- assert_se(p[0].nr = 1981); ++ assert_se(p[0].nr == 1981); + + assert_se(uid_range_add_str(&p, &n, "2002") >= 0); + assert_se(n == 2); + assert_se(p[0].start == 20); +- assert_se(p[0].nr = 1981); ++ assert_se(p[0].nr == 1981); + assert_se(p[1].start == 2002); +- assert_se(p[1].nr = 1); ++ assert_se(p[1].nr == 1); + + assert_se(uid_range_add_str(&p, &n, "2001") >= 0); + assert_se(n == 1); + assert_se(p[0].start == 20); +- assert_se(p[0].nr = 1983); ++ assert_se(p[0].nr == 1983); + + return 0; + } diff --git a/0242-build-colorize-gcc-only-if-on-tty.patch b/0242-build-colorize-gcc-only-if-on-tty.patch new file mode 100644 index 0000000..c1ec01c --- /dev/null +++ b/0242-build-colorize-gcc-only-if-on-tty.patch @@ -0,0 +1,42 @@ +From f44541bc934c6e2b02155559e9eeb17a13a09558 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Fri, 15 Aug 2014 16:33:03 +0200 +Subject: [PATCH] build: colorize gcc only if on tty + +Rather than forcing gcc to always produce colorized error messages +whether on tty or not, enable automatic colorization by ensuring +GCC_COLORS is set to a non-empty string. + +Doing it this way removes the need for workarounds in ~/.emacs or +~/.vimrc for "M-x compile" or ":make", respectively, to work. +--- + Makefile.am | 3 +++ + configure.ac | 1 - + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index de40043c5b..5dc17f8fe7 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -24,6 +24,9 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + AM_MAKEFLAGS = --no-print-directory + AUTOMAKE_OPTIONS = color-tests parallel-tests + ++GCC_COLORS ?= 'ooh, shiny!' ++export GCC_COLORS ++ + SUBDIRS = . po + + # remove targets if the command fails +diff --git a/configure.ac b/configure.ac +index 99c01d2487..fb169042d8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -190,7 +190,6 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ + -ffast-math \ + -fno-common \ + -fdiagnostics-show-option \ +- -fdiagnostics-color \ + -fno-strict-aliasing \ + -fvisibility=hidden \ + -ffunction-sections \ diff --git a/0243-hashmap-introduce-hash_ops-to-make-struct-Hashmap-sm.patch b/0243-hashmap-introduce-hash_ops-to-make-struct-Hashmap-sm.patch new file mode 100644 index 0000000..6200b89 --- /dev/null +++ b/0243-hashmap-introduce-hash_ops-to-make-struct-Hashmap-sm.patch @@ -0,0 +1,2245 @@ +From d5099efc47d4e6ac60816b5381a5f607ab03f06e Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Wed, 13 Aug 2014 01:00:18 +0200 +Subject: [PATCH] hashmap: introduce hash_ops to make struct Hashmap smaller + +It is redundant to store 'hash' and 'compare' function pointers in +struct Hashmap separately. The functions always comprise a pair. +Store a single pointer to struct hash_ops instead. + +systemd keeps hundreds of hashmaps, so this saves a little bit of +memory. +--- + src/analyze/analyze.c | 2 +- + src/bus-proxyd/bus-policy.c | 4 +-- + src/cgtop/cgtop.c | 4 +-- + src/core/automount.c | 4 +-- + src/core/bus-endpoint.c | 2 +- + src/core/dbus-manager.c | 2 +- + src/core/dbus.c | 2 +- + src/core/device.c | 4 +-- + src/core/killall.c | 2 +- + src/core/load-fragment.c | 10 +++---- + src/core/manager.c | 14 ++++----- + src/core/mount-setup.c | 2 +- + src/core/swap.c | 4 +-- + src/core/transaction.c | 2 +- + src/core/unit.c | 22 +++++++-------- + src/delta/delta.c | 8 +++--- + src/journal-remote/journal-remote.c | 18 ++++-------- + src/journal/catalog.c | 11 ++++++-- + src/journal/catalog.h | 3 +- + src/journal/coredump-vacuum.c | 2 +- + src/journal/coredumpctl.c | 2 +- + src/journal/journal-file.c | 2 +- + src/journal/journalctl.c | 2 +- + src/journal/journald-server.c | 2 +- + src/journal/mmap-cache.c | 4 +-- + src/journal/sd-journal.c | 8 +++--- + src/journal/test-catalog.c | 2 +- + src/libsystemd-network/sd-dhcp-server.c | 8 ++++-- + src/libsystemd/sd-bus/bus-match.c | 4 +-- + src/libsystemd/sd-bus/bus-objects.c | 13 ++++++--- + src/libsystemd/sd-bus/bus-track.c | 2 +- + src/libsystemd/sd-bus/bus-util.c | 2 +- + src/libsystemd/sd-bus/busctl.c | 2 +- + src/libsystemd/sd-bus/sd-bus.c | 2 +- + src/libsystemd/sd-event/sd-event.c | 4 +-- + src/libsystemd/sd-rtnl/sd-rtnl.c | 2 +- + src/locale/localectl.c | 2 +- + src/login/logind-acl.c | 2 +- + src/login/logind-session.c | 2 +- + src/login/logind.c | 18 ++++++------ + src/machine/machined.c | 6 ++-- + src/network/networkd-link.c | 2 +- + src/network/networkd-manager.c | 8 +++--- + src/network/networkd-network.c | 6 ++-- + src/network/networkd-wait-online-link.c | 5 ++-- + src/readahead/readahead-collect.c | 2 +- + src/remount-fs/remount-fs.c | 2 +- + src/resolve/resolved-dns-cache.c | 2 +- + src/resolve/resolved-dns-domain.c | 5 ++++ + src/resolve/resolved-dns-domain.h | 1 + + src/resolve/resolved-dns-packet.c | 4 +-- + src/resolve/resolved-dns-query.c | 4 +-- + src/resolve/resolved-dns-rr.c | 9 ++++-- + src/resolve/resolved-dns-rr.h | 4 +-- + src/resolve/resolved-dns-scope.c | 2 +- + src/resolve/resolved-dns-server.c | 9 ++++-- + src/resolve/resolved-dns-server.h | 3 +- + src/resolve/resolved-dns-transaction.c | 2 +- + src/resolve/resolved-dns-zone.c | 6 ++-- + src/resolve/resolved-link.c | 2 +- + src/resolve/resolved-manager.c | 4 +-- + src/shared/cgroup-util.c | 6 ++-- + src/shared/conf-files.c | 2 +- + src/shared/fdset.c | 2 +- + src/shared/hashmap.c | 42 +++++++++++++++++++-------- + src/shared/hashmap.h | 18 ++++++++++-- + src/shared/install.c | 8 +++--- + src/shared/locale-util.c | 2 +- + src/shared/logs-show.c | 2 +- + src/shared/set.c | 8 +++--- + src/shared/set.h | 4 +-- + src/shared/util.c | 6 ++-- + src/socket-proxy/socket-proxyd.c | 4 +-- + src/sysctl/sysctl.c | 2 +- + src/systemctl/systemctl.c | 6 ++-- + src/sysusers/sysusers.c | 22 +++++++-------- + src/sysv-generator/sysv-generator.c | 8 ++---- + src/test/test-hashmap.c | 50 ++++++++++++++++----------------- + src/test/test-install.c | 2 +- + src/test/test-prioq.c | 7 ++++- + src/test/test-unit-file.c | 2 +- + src/tmpfiles/tmpfiles.c | 6 ++-- + 82 files changed, 278 insertions(+), 226 deletions(-) + +diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c +index 82f5cf3c57..5e55988063 100644 +--- a/src/analyze/analyze.c ++++ b/src/analyze/analyze.c +@@ -907,7 +907,7 @@ static int analyze_critical_chain(sd_bus *bus, char *names[]) { + if (n <= 0) + return n; + +- h = hashmap_new(string_hash_func, string_compare_func); ++ h = hashmap_new(&string_hash_ops); + if (!h) + return -ENOMEM; + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 06c16a7eb6..d2eace9405 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -338,7 +338,7 @@ static int file_load(Policy *p, const char *path) { + + assert_cc(sizeof(uid_t) == sizeof(uint32_t)); + +- r = hashmap_ensure_allocated(&p->user_items, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&p->user_items, NULL); + if (r < 0) + return log_oom(); + +@@ -369,7 +369,7 @@ static int file_load(Policy *p, const char *path) { + + assert_cc(sizeof(gid_t) == sizeof(uint32_t)); + +- r = hashmap_ensure_allocated(&p->group_items, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&p->group_items, NULL); + if (r < 0) + return log_oom(); + +diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c +index 509fe4cdc8..ab8c4cfda1 100644 +--- a/src/cgtop/cgtop.c ++++ b/src/cgtop/cgtop.c +@@ -695,8 +695,8 @@ int main(int argc, char *argv[]) { + if (r <= 0) + goto finish; + +- a = hashmap_new(string_hash_func, string_compare_func); +- b = hashmap_new(string_hash_func, string_compare_func); ++ a = hashmap_new(&string_hash_ops); ++ b = hashmap_new(&string_hash_ops); + if (!a || !b) { + r = log_oom(); + goto finish; +diff --git a/src/core/automount.c b/src/core/automount.c +index 73a8ce17e4..f72aca2957 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -685,7 +685,7 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu + log_debug_unit(u->id, "Failed to parse token value %s", value); + else { + if (!a->tokens) +- if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) ++ if (!(a->tokens = set_new(NULL))) + return -ENOMEM; + + r = set_put(a->tokens, UINT_TO_PTR(token)); +@@ -762,7 +762,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo + } else + log_debug_unit(UNIT(a)->id, "Got direct mount request on %s", a->where); + +- r = set_ensure_allocated(&a->tokens, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&a->tokens, NULL); + if (r < 0) { + log_error_unit(UNIT(a)->id, "Failed to allocate token set."); + goto fail; +diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c +index 8d11974db4..1e8f07eb54 100644 +--- a/src/core/bus-endpoint.c ++++ b/src/core/bus-endpoint.c +@@ -55,7 +55,7 @@ int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess a + return 0; + } + } else { +- ep->policy_hash = hashmap_new(string_hash_func, string_compare_func); ++ ep->policy_hash = hashmap_new(&string_hash_ops); + if (!ep->policy_hash) + return -ENOMEM; + } +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 2fe9d193f6..533ce439a7 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1399,7 +1399,7 @@ static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *us + if (r < 0) + return r; + +- h = hashmap_new(string_hash_func, string_compare_func); ++ h = hashmap_new(&string_hash_ops); + if (!h) + return -ENOMEM; + +diff --git a/src/core/dbus.c b/src/core/dbus.c +index e7eee3c6d1..09b4a4ac6f 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -659,7 +659,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void + return 0; + } + +- r = set_ensure_allocated(&m->private_buses, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&m->private_buses, NULL); + if (r < 0) { + log_oom(); + return 0; +diff --git a/src/core/device.c b/src/core/device.c +index 0f28a16874..11c4261081 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -304,7 +304,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p + goto fail; + } + +- r = hashmap_ensure_allocated(&m->devices_by_sysfs, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&m->devices_by_sysfs, &string_hash_ops); + if (r < 0) + goto fail; + +@@ -517,7 +517,7 @@ static int device_following_set(Unit *u, Set **_set) { + return 0; + } + +- set = set_new(NULL, NULL); ++ set = set_new(NULL); + if (!set) + return -ENOMEM; + +diff --git a/src/core/killall.c b/src/core/killall.c +index 291e1f90ee..a6ff50a5a4 100644 +--- a/src/core/killall.c ++++ b/src/core/killall.c +@@ -205,7 +205,7 @@ void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) { + _cleanup_set_free_ Set *pids = NULL; + + if (wait_for_exit) +- pids = set_new(trivial_hash_func, trivial_compare_func); ++ pids = set_new(NULL); + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigaddset(&mask, SIGCHLD) == 0); +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 7cf19b93cc..0620882b4e 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -2276,7 +2276,7 @@ int config_parse_syscall_filter( + } + + if (!c->syscall_filter) { +- c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func); ++ c->syscall_filter = set_new(NULL); + if (!c->syscall_filter) + return log_oom(); + +@@ -2368,7 +2368,7 @@ int config_parse_syscall_archs( + return 0; + } + +- r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(archs, NULL); + if (r < 0) + return log_oom(); + +@@ -2474,7 +2474,7 @@ int config_parse_address_families( + } + + if (!c->address_families) { +- c->address_families = set_new(trivial_hash_func, trivial_compare_func); ++ c->address_families = set_new(NULL); + if (!c->address_families) + return log_oom(); + +@@ -3092,7 +3092,7 @@ int config_parse_set_status( + } + } + +- r = set_ensure_allocated(&status_set->status, NULL, NULL); ++ r = set_ensure_allocated(&status_set->status, NULL); + if (r < 0) + return log_oom(); + +@@ -3423,7 +3423,7 @@ static int load_from_path(Unit *u, const char *path) { + assert(u); + assert(path); + +- symlink_names = set_new(string_hash_func, string_compare_func); ++ symlink_names = set_new(&string_hash_ops); + if (!symlink_names) + return -ENOMEM; + +diff --git a/src/core/manager.c b/src/core/manager.c +index 095111e8c6..0770727cde 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -449,27 +449,27 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) { + if (r < 0) + goto fail; + +- r = hashmap_ensure_allocated(&m->units, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&m->units, &string_hash_ops); + if (r < 0) + goto fail; + +- r = hashmap_ensure_allocated(&m->jobs, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&m->jobs, NULL); + if (r < 0) + goto fail; + +- r = hashmap_ensure_allocated(&m->cgroup_unit, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&m->cgroup_unit, &string_hash_ops); + if (r < 0) + goto fail; + +- r = hashmap_ensure_allocated(&m->watch_bus, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&m->watch_bus, &string_hash_ops); + if (r < 0) + goto fail; + +- r = set_ensure_allocated(&m->startup_units, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&m->startup_units, NULL); + if (r < 0) + goto fail; + +- r = set_ensure_allocated(&m->failed_units, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&m->failed_units, NULL); + if (r < 0) + goto fail; + +@@ -903,7 +903,7 @@ static void manager_build_unit_path_cache(Manager *m) { + + set_free_free(m->unit_path_cache); + +- m->unit_path_cache = set_new(string_hash_func, string_compare_func); ++ m->unit_path_cache = set_new(&string_hash_ops); + if (!m->unit_path_cache) { + log_error("Failed to allocate unit path cache."); + return; +diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c +index cc2633e3bd..23a66d2e95 100644 +--- a/src/core/mount-setup.c ++++ b/src/core/mount-setup.c +@@ -235,7 +235,7 @@ int mount_cgroup_controllers(char ***join_controllers) { + return 0; + } + +- controllers = set_new(string_hash_func, string_compare_func); ++ controllers = set_new(&string_hash_ops); + if (!controllers) + return log_oom(); + +diff --git a/src/core/swap.c b/src/core/swap.c +index 019d32ed0d..b88a914f72 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -77,7 +77,7 @@ static int swap_set_devnode(Swap *s, const char *devnode) { + + assert(s); + +- r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, &string_hash_ops); + if (r < 0) + return r; + +@@ -1226,7 +1226,7 @@ static int swap_following_set(Unit *u, Set **_set) { + return 0; + } + +- set = set_new(NULL, NULL); ++ set = set_new(NULL); + if (!set) + return -ENOMEM; + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index 1f4c9ce416..dbb4133fe3 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -1143,7 +1143,7 @@ Transaction *transaction_new(bool irreversible) { + if (!tr) + return NULL; + +- tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func); ++ tr->jobs = hashmap_new(NULL); + if (!tr->jobs) { + free(tr); + return NULL; +diff --git a/src/core/unit.c b/src/core/unit.c +index b5c3182940..5978e21f56 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -81,7 +81,7 @@ Unit *unit_new(Manager *m, size_t size) { + if (!u) + return NULL; + +- u->names = set_new(string_hash_func, string_compare_func); ++ u->names = set_new(&string_hash_ops); + if (!u->names) { + free(u); + return NULL; +@@ -1843,17 +1843,17 @@ int unit_watch_pid(Unit *u, pid_t pid) { + /* Watch a specific PID. We only support one or two units + * watching each PID for now, not more. */ + +- r = set_ensure_allocated(&u->pids, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&u->pids, NULL); + if (r < 0) + return r; + +- r = hashmap_ensure_allocated(&u->manager->watch_pids1, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&u->manager->watch_pids1, NULL); + if (r < 0) + return r; + + r = hashmap_put(u->manager->watch_pids1, LONG_TO_PTR(pid), u); + if (r == -EEXIST) { +- r = hashmap_ensure_allocated(&u->manager->watch_pids2, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&u->manager->watch_pids2, NULL); + if (r < 0) + return r; + +@@ -2086,22 +2086,22 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen + return 0; + } + +- r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&u->dependencies[d], NULL); + if (r < 0) + return r; + + if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) { +- r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&other->dependencies[inverse_table[d]], NULL); + if (r < 0) + return r; + } + + if (add_reference) { +- r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], NULL); + if (r < 0) + return r; + +- r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], NULL); + if (r < 0) + return r; + } +@@ -2847,7 +2847,7 @@ static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) { + Set *pid_set; + int r; + +- pid_set = set_new(trivial_hash_func, trivial_compare_func); ++ pid_set = set_new(NULL); + if (!pid_set) + return NULL; + +@@ -3385,7 +3385,7 @@ int unit_require_mounts_for(Unit *u, const char *path) { + char *q; + + if (!u->manager->units_requiring_mounts_for) { +- u->manager->units_requiring_mounts_for = hashmap_new(string_hash_func, string_compare_func); ++ u->manager->units_requiring_mounts_for = hashmap_new(&string_hash_ops); + if (!u->manager->units_requiring_mounts_for) + return -ENOMEM; + } +@@ -3394,7 +3394,7 @@ int unit_require_mounts_for(Unit *u, const char *path) { + if (!q) + return -ENOMEM; + +- x = set_new(NULL, NULL); ++ x = set_new(NULL); + if (!x) { + free(q); + return -ENOMEM; +diff --git a/src/delta/delta.c b/src/delta/delta.c +index cd8bd35716..91f8592b40 100644 +--- a/src/delta/delta.c ++++ b/src/delta/delta.c +@@ -268,7 +268,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const + + h = hashmap_get(drops, unit); + if (!h) { +- h = hashmap_new(string_hash_func, string_compare_func); ++ h = hashmap_new(&string_hash_ops); + if (!h) + return -ENOMEM; + hashmap_put(drops, unit, h); +@@ -372,9 +372,9 @@ static int process_suffix(const char *suffix, const char *onlyprefix) { + + dropins = nulstr_contains(have_dropins, suffix); + +- top = hashmap_new(string_hash_func, string_compare_func); +- bottom = hashmap_new(string_hash_func, string_compare_func); +- drops = hashmap_new(string_hash_func, string_compare_func); ++ top = hashmap_new(&string_hash_ops); ++ bottom = hashmap_new(&string_hash_ops); ++ drops = hashmap_new(&string_hash_ops); + if (!top || !bottom || !drops) { + r = -ENOMEM; + goto finish; +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index 1cc86aeaf3..12de820330 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -222,20 +222,14 @@ static int open_output(Writer *w, const char* host) { + **********************************************************************/ + + static int init_writer_hashmap(RemoteServer *s) { +- static const struct { +- hash_func_t hash_func; +- compare_func_t compare_func; +- } functions[] = { +- [JOURNAL_WRITE_SPLIT_NONE] = {trivial_hash_func, +- trivial_compare_func}, +- [JOURNAL_WRITE_SPLIT_HOST] = {string_hash_func, +- string_compare_func}, ++ static const struct hash_ops *hash_ops[] = { ++ [JOURNAL_WRITE_SPLIT_NONE] = NULL, ++ [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops, + }; + +- assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(functions)); ++ assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops)); + +- s->writers = hashmap_new(functions[arg_split_mode].hash_func, +- functions[arg_split_mode].compare_func); ++ s->writers = hashmap_new(hash_ops[arg_split_mode]); + if (!s->writers) + return log_oom(); + +@@ -695,7 +689,7 @@ static int setup_microhttpd_server(RemoteServer *s, + goto error; + } + +- r = hashmap_ensure_allocated(&s->daemons, uint64_hash_func, uint64_compare_func); ++ r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops); + if (r < 0) { + log_oom(); + goto error; +diff --git a/src/journal/catalog.c b/src/journal/catalog.c +index f03357dedf..41d450b154 100644 +--- a/src/journal/catalog.c ++++ b/src/journal/catalog.c +@@ -64,7 +64,7 @@ typedef struct CatalogItem { + le64_t offset; + } CatalogItem; + +-unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { ++static unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + const CatalogItem *i = p; + uint64_t u; + size_t l, sz; +@@ -81,7 +81,7 @@ unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_S + return (unsigned long) u; + } + +-int catalog_compare_func(const void *a, const void *b) { ++static int catalog_compare_func(const void *a, const void *b) { + const CatalogItem *i = a, *j = b; + unsigned k; + +@@ -95,6 +95,11 @@ int catalog_compare_func(const void *a, const void *b) { + return strcmp(i->language, j->language); + } + ++const struct hash_ops catalog_hash_ops = { ++ .hash = catalog_hash_func, ++ .compare = catalog_compare_func ++}; ++ + static int finish_item( + Hashmap *h, + struct strbuf *sb, +@@ -407,7 +412,7 @@ int catalog_update(const char* database, const char* root, const char* const* di + unsigned n; + long r; + +- h = hashmap_new(catalog_hash_func, catalog_compare_func); ++ h = hashmap_new(&catalog_hash_ops); + sb = strbuf_new(); + + if (!h || !sb) { +diff --git a/src/journal/catalog.h b/src/journal/catalog.h +index fdde67aeed..a72ecf6de7 100644 +--- a/src/journal/catalog.h ++++ b/src/journal/catalog.h +@@ -28,11 +28,10 @@ + #include "strbuf.h" + + int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path); +-unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); +-int catalog_compare_func(const void *a, const void *b) _pure_; + int catalog_update(const char* database, const char* root, const char* const* dirs); + int catalog_get(const char* database, sd_id128_t id, char **data); + int catalog_list(FILE *f, const char* database, bool oneline); + int catalog_list_items(FILE *f, const char* database, bool oneline, char **items); + int catalog_file_lang(const char *filename, char **lang); + extern const char * const catalog_file_dirs[]; ++extern const struct hash_ops catalog_hash_ops; +diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c +index 125bb3a4b8..fec901e8e4 100644 +--- a/src/journal/coredump-vacuum.c ++++ b/src/journal/coredump-vacuum.c +@@ -194,7 +194,7 @@ int coredump_vacuum(int exclude_fd, off_t keep_free, off_t max_use) { + exclude_st.st_ino == st.st_ino) + continue; + +- r = hashmap_ensure_allocated(&h, NULL, NULL); ++ r = hashmap_ensure_allocated(&h, NULL); + if (r < 0) + return log_oom(); + +diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c +index 34dcae87c0..d4756fe67d 100644 +--- a/src/journal/coredumpctl.c ++++ b/src/journal/coredumpctl.c +@@ -58,7 +58,7 @@ static Set *new_matches(void) { + char *tmp; + int r; + +- set = set_new(trivial_hash_func, trivial_compare_func); ++ set = set_new(NULL); + if (!set) { + log_oom(); + return NULL; +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 7286e14ddb..f25cda6ddc 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -2498,7 +2498,7 @@ int journal_file_open( + goto fail; + } + +- f->chain_cache = hashmap_new(uint64_hash_func, uint64_compare_func); ++ f->chain_cache = hashmap_new(&uint64_hash_ops); + if (!f->chain_cache) { + r = -ENOMEM; + goto fail; +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index d00a815ba9..47206d383a 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1029,7 +1029,7 @@ static int get_possible_units(sd_journal *j, + const char *field; + int r; + +- found = set_new(string_hash_func, string_compare_func); ++ found = set_new(&string_hash_ops); + if (!found) + return log_oom(); + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 01da38b8d8..3df7416397 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1483,7 +1483,7 @@ int server_init(Server *s) { + + mkdir_p("/run/systemd/journal", 0755); + +- s->user_journals = hashmap_new(trivial_hash_func, trivial_compare_func); ++ s->user_journals = hashmap_new(NULL); + if (!s->user_journals) + return log_oom(); + +diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c +index 908562da27..2d268fc332 100644 +--- a/src/journal/mmap-cache.c ++++ b/src/journal/mmap-cache.c +@@ -227,7 +227,7 @@ static Context *context_add(MMapCache *m, unsigned id) { + if (c) + return c; + +- r = hashmap_ensure_allocated(&m->contexts, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&m->contexts, NULL); + if (r < 0) + return NULL; + +@@ -281,7 +281,7 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) { + if (f) + return f; + +- r = hashmap_ensure_allocated(&m->fds, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&m->fds, NULL); + if (r < 0) + return NULL; + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 693707cb34..1fc9f01d0a 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -70,7 +70,7 @@ static int set_put_error(sd_journal *j, int r) { + if (r >= 0) + return r; + +- k = set_ensure_allocated(&j->errors, trivial_hash_func, trivial_compare_func); ++ k = set_ensure_allocated(&j->errors, NULL); + if (k < 0) + return k; + +@@ -1662,7 +1662,7 @@ static int allocate_inotify(sd_journal *j) { + } + + if (!j->directories_by_wd) { +- j->directories_by_wd = hashmap_new(trivial_hash_func, trivial_compare_func); ++ j->directories_by_wd = hashmap_new(NULL); + if (!j->directories_by_wd) + return -ENOMEM; + } +@@ -1688,8 +1688,8 @@ static sd_journal *journal_new(int flags, const char *path) { + goto fail; + } + +- j->files = hashmap_new(string_hash_func, string_compare_func); +- j->directories_by_path = hashmap_new(string_hash_func, string_compare_func); ++ j->files = hashmap_new(&string_hash_ops); ++ j->directories_by_path = hashmap_new(&string_hash_ops); + j->mmap = mmap_cache_new(); + if (!j->files || !j->directories_by_path || !j->mmap) + goto fail; +diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c +index 967ab6756b..5fe2f6a269 100644 +--- a/src/journal/test-catalog.c ++++ b/src/journal/test-catalog.c +@@ -62,7 +62,7 @@ static void test_catalog_importing(void) { + Hashmap *h; + struct strbuf *sb; + +- assert_se(h = hashmap_new(catalog_hash_func, catalog_compare_func)); ++ assert_se(h = hashmap_new(&catalog_hash_ops)); + assert_se(sb = strbuf_new()); + + #define BUF "xxx" +diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c +index ab683228b4..a6d6178e72 100644 +--- a/src/libsystemd-network/sd-dhcp-server.c ++++ b/src/libsystemd-network/sd-dhcp-server.c +@@ -109,6 +109,11 @@ int client_id_compare_func(const void *_a, const void *_b) { + return memcmp(a->data, b->data, a->length); + } + ++static const struct hash_ops client_id_hash_ops = { ++ .hash = client_id_hash_func, ++ .compare = client_id_compare_func ++}; ++ + static void dhcp_lease_free(DHCPLease *lease) { + if (!lease) + return; +@@ -158,8 +163,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { + server->address = htobe32(INADDR_ANY); + server->netmask = htobe32(INADDR_ANY); + server->index = ifindex; +- server->leases_by_client_id = hashmap_new(client_id_hash_func, +- client_id_compare_func); ++ server->leases_by_client_id = hashmap_new(&client_id_hash_ops); + + *ret = server; + server = NULL; +diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c +index 88b61a75be..18afe0f12a 100644 +--- a/src/libsystemd/sd-bus/bus-match.c ++++ b/src/libsystemd/sd-bus/bus-match.c +@@ -450,13 +450,13 @@ static int bus_match_add_compare_value( + where->child = c; + + if (t == BUS_MATCH_MESSAGE_TYPE) { +- c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func); ++ c->compare.children = hashmap_new(NULL); + if (!c->compare.children) { + r = -ENOMEM; + goto fail; + } + } else if (BUS_MATCH_CAN_HASH(t)) { +- c->compare.children = hashmap_new(string_hash_func, string_compare_func); ++ c->compare.children = hashmap_new(&string_hash_ops); + if (!c->compare.children) { + r = -ENOMEM; + goto fail; +diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c +index 3a2de6520e..81c840f129 100644 +--- a/src/libsystemd/sd-bus/bus-objects.c ++++ b/src/libsystemd/sd-bus/bus-objects.c +@@ -225,7 +225,7 @@ static int get_child_nodes( + assert(n); + assert(_s); + +- s = set_new(string_hash_func, string_compare_func); ++ s = set_new(&string_hash_ops); + if (!s) + return -ENOMEM; + +@@ -1420,7 +1420,7 @@ static struct node *bus_node_allocate(sd_bus *bus, const char *path) { + if (n) + return n; + +- r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&bus->nodes, &string_hash_ops); + if (r < 0) + return NULL; + +@@ -1590,6 +1590,11 @@ static int vtable_member_compare_func(const void *a, const void *b) { + return strcmp(x->member, y->member); + } + ++static const struct hash_ops vtable_member_hash_ops = { ++ .hash = vtable_member_hash_func, ++ .compare = vtable_member_compare_func ++}; ++ + static int add_object_vtable_internal( + sd_bus *bus, + sd_bus_slot **slot, +@@ -1618,11 +1623,11 @@ static int add_object_vtable_internal( + !streq(interface, "org.freedesktop.DBus.Peer") && + !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL); + +- r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func); ++ r = hashmap_ensure_allocated(&bus->vtable_methods, &vtable_member_hash_ops); + if (r < 0) + return r; + +- r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func); ++ r = hashmap_ensure_allocated(&bus->vtable_properties, &vtable_member_hash_ops); + if (r < 0) + return r; + +diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c +index ffa2cf3d75..0a3322a4ee 100644 +--- a/src/libsystemd/sd-bus/bus-track.c ++++ b/src/libsystemd/sd-bus/bus-track.c +@@ -166,7 +166,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { + assert_return(track, -EINVAL); + assert_return(service_name_is_valid(name), -EINVAL); + +- r = hashmap_ensure_allocated(&track->names, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&track->names, &string_hash_ops); + if (r < 0) + return r; + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index a85d36180e..7c6da60cca 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -399,7 +399,7 @@ int bus_verify_polkit_async( + if (!sender) + return -EBADMSG; + +- r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(registry, NULL); + if (r < 0) + return r; + +diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c +index af71804410..f06b74505b 100644 +--- a/src/libsystemd/sd-bus/busctl.c ++++ b/src/libsystemd/sd-bus/busctl.c +@@ -76,7 +76,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { + + pager_open_if_enabled(); + +- names = hashmap_new(string_hash_func, string_compare_func); ++ names = hashmap_new(&string_hash_ops); + if (!names) + return log_oom(); + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 83b3aa1c3c..33b65aba72 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -1756,7 +1756,7 @@ _public_ int sd_bus_call_async( + if (!BUS_IS_OPEN(bus->state)) + return -ENOTCONN; + +- r = hashmap_ensure_allocated(&bus->reply_callbacks, uint64_hash_func, uint64_compare_func); ++ r = hashmap_ensure_allocated(&bus->reply_callbacks, &uint64_hash_ops); + if (r < 0) + return r; + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 985ff2829b..b56182dda7 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -1032,7 +1032,7 @@ _public_ int sd_event_add_child( + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + +- r = hashmap_ensure_allocated(&e->child_sources, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&e->child_sources, NULL); + if (r < 0) + return r; + +@@ -1123,7 +1123,7 @@ _public_ int sd_event_add_post( + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + +- r = set_ensure_allocated(&e->post_sources, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&e->post_sources, NULL); + if (r < 0) + return r; + +diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c +index a3f314b95b..b7f1afe905 100644 +--- a/src/libsystemd/sd-rtnl/sd-rtnl.c ++++ b/src/libsystemd/sd-rtnl/sd-rtnl.c +@@ -557,7 +557,7 @@ int sd_rtnl_call_async(sd_rtnl *nl, + assert_return(callback, -EINVAL); + assert_return(!rtnl_pid_changed(nl), -ECHILD); + +- r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func); ++ r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops); + if (r < 0) + return r; + +diff --git a/src/locale/localectl.c b/src/locale/localectl.c +index 2bb0d3b6be..bf8b7b2bef 100644 +--- a/src/locale/localectl.c ++++ b/src/locale/localectl.c +@@ -272,7 +272,7 @@ static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) { + _cleanup_strv_free_ char **l = NULL; + const char *dir; + +- keymaps = set_new(string_hash_func, string_compare_func); ++ keymaps = set_new(&string_hash_ops); + if (!keymaps) + return log_oom(); + +diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c +index b76e16d906..f7c6f3a4ef 100644 +--- a/src/login/logind-acl.c ++++ b/src/login/logind-acl.c +@@ -190,7 +190,7 @@ int devnode_acl_all(struct udev *udev, + + assert(udev); + +- nodes = set_new(string_hash_func, string_compare_func); ++ nodes = set_new(&string_hash_ops); + if (!nodes) + return -ENOMEM; + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 10a43a4a30..eeb58c9031 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -61,7 +61,7 @@ Session* session_new(Manager *m, const char *id) { + return NULL; + } + +- s->devices = hashmap_new(devt_hash_func, devt_compare_func); ++ s->devices = hashmap_new(&devt_hash_ops); + if (!s->devices) { + free(s->state_file); + free(s); +diff --git a/src/login/logind.c b/src/login/logind.c +index 1f94a97bd0..f1b6a86298 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -64,17 +64,17 @@ Manager *manager_new(void) { + + m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ + +- m->devices = hashmap_new(string_hash_func, string_compare_func); +- m->seats = hashmap_new(string_hash_func, string_compare_func); +- m->sessions = hashmap_new(string_hash_func, string_compare_func); +- m->users = hashmap_new(trivial_hash_func, trivial_compare_func); +- m->inhibitors = hashmap_new(string_hash_func, string_compare_func); +- m->buttons = hashmap_new(string_hash_func, string_compare_func); ++ m->devices = hashmap_new(&string_hash_ops); ++ m->seats = hashmap_new(&string_hash_ops); ++ m->sessions = hashmap_new(&string_hash_ops); ++ m->users = hashmap_new(NULL); ++ m->inhibitors = hashmap_new(&string_hash_ops); ++ m->buttons = hashmap_new(&string_hash_ops); + +- m->user_units = hashmap_new(string_hash_func, string_compare_func); +- m->session_units = hashmap_new(string_hash_func, string_compare_func); ++ m->user_units = hashmap_new(&string_hash_ops); ++ m->session_units = hashmap_new(&string_hash_ops); + +- m->busnames = set_new(string_hash_func, string_compare_func); ++ m->busnames = set_new(&string_hash_ops); + + if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames || + !m->user_units || !m->session_units) +diff --git a/src/machine/machined.c b/src/machine/machined.c +index aac670ba78..71c8189d5f 100644 +--- a/src/machine/machined.c ++++ b/src/machine/machined.c +@@ -44,9 +44,9 @@ Manager *manager_new(void) { + if (!m) + return NULL; + +- m->machines = hashmap_new(string_hash_func, string_compare_func); +- m->machine_units = hashmap_new(string_hash_func, string_compare_func); +- m->machine_leaders = hashmap_new(trivial_hash_func, trivial_compare_func); ++ m->machines = hashmap_new(&string_hash_ops); ++ m->machine_units = hashmap_new(&string_hash_ops); ++ m->machine_leaders = hashmap_new(NULL); + + if (!m->machines || !m->machine_units || !m->machine_leaders) { + manager_free(m); +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 11ac1307d8..9bf1a811c9 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -206,7 +206,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) { + if (r < 0) + return -ENOMEM; + +- r = hashmap_ensure_allocated(&manager->links, NULL, NULL); ++ r = hashmap_ensure_allocated(&manager->links, NULL); + if (r < 0) + return r; + +diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c +index 1614bc0091..2213ad717c 100644 +--- a/src/network/networkd-manager.c ++++ b/src/network/networkd-manager.c +@@ -115,7 +115,7 @@ int manager_new(Manager **ret) { + return -ENOMEM; + } + +- m->netdevs = hashmap_new(string_hash_func, string_compare_func); ++ m->netdevs = hashmap_new(&string_hash_ops); + if (!m->netdevs) + return -ENOMEM; + +@@ -485,15 +485,15 @@ int manager_save(Manager *m) { + assert(m->state_file); + + /* We add all NTP and DNS server to a set, to filter out duplicates */ +- dns = set_new(string_hash_func, string_compare_func); ++ dns = set_new(&string_hash_ops); + if (!dns) + return -ENOMEM; + +- ntp = set_new(string_hash_func, string_compare_func); ++ ntp = set_new(&string_hash_ops); + if (!ntp) + return -ENOMEM; + +- domains = set_new(string_hash_func, string_compare_func); ++ domains = set_new(&string_hash_ops); + if (!domains) + return -ENOMEM; + +diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c +index a2e27e0910..aad99236c4 100644 +--- a/src/network/networkd-network.c ++++ b/src/network/networkd-network.c +@@ -63,15 +63,15 @@ static int network_load_one(Manager *manager, const char *filename) { + LIST_HEAD_INIT(network->static_addresses); + LIST_HEAD_INIT(network->static_routes); + +- network->stacked_netdevs = hashmap_new(string_hash_func, string_compare_func); ++ network->stacked_netdevs = hashmap_new(&string_hash_ops); + if (!network->stacked_netdevs) + return log_oom(); + +- network->addresses_by_section = hashmap_new(NULL, NULL); ++ network->addresses_by_section = hashmap_new(NULL); + if (!network->addresses_by_section) + return log_oom(); + +- network->routes_by_section = hashmap_new(NULL, NULL); ++ network->routes_by_section = hashmap_new(NULL); + if (!network->routes_by_section) + return log_oom(); + +diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c +index f23c7ceb80..268ab676c9 100644 +--- a/src/network/networkd-wait-online-link.c ++++ b/src/network/networkd-wait-online-link.c +@@ -34,12 +34,11 @@ int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) { + assert(m); + assert(ifindex > 0); + +- r = hashmap_ensure_allocated(&m->links, NULL, NULL); ++ r = hashmap_ensure_allocated(&m->links, NULL); + if (r < 0) + return r; + +- r = hashmap_ensure_allocated(&m->links_by_name, +- string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&m->links_by_name, &string_hash_ops); + if (r < 0) + return r; + +diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c +index 1592cc8678..822a803a41 100644 +--- a/src/readahead/readahead-collect.c ++++ b/src/readahead/readahead-collect.c +@@ -282,7 +282,7 @@ static int collect(const char *root) { + goto finish; + } + +- files = hashmap_new(string_hash_func, string_compare_func); ++ files = hashmap_new(&string_hash_ops); + if (!files) { + log_error("Failed to allocate set."); + r = -ENOMEM; +diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c +index 847637a12c..cd7cfe7a47 100644 +--- a/src/remount-fs/remount-fs.c ++++ b/src/remount-fs/remount-fs.c +@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) { + return EXIT_FAILURE; + } + +- pids = hashmap_new(trivial_hash_func, trivial_compare_func); ++ pids = hashmap_new(NULL); + if (!pids) { + log_error("Failed to allocate set"); + goto finish; +diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c +index 733ef6348d..33ca4d1a45 100644 +--- a/src/resolve/resolved-dns-cache.c ++++ b/src/resolve/resolved-dns-cache.c +@@ -186,7 +186,7 @@ static int dns_cache_init(DnsCache *c) { + if (r < 0) + return r; + +- r = hashmap_ensure_allocated(&c->by_key, dns_resource_key_hash_func, dns_resource_key_compare_func); ++ r = hashmap_ensure_allocated(&c->by_key, &dns_resource_key_hash_ops); + if (r < 0) + return r; + +diff --git a/src/resolve/resolved-dns-domain.c b/src/resolve/resolved-dns-domain.c +index 8ed1ecf0a4..e1eb3ddfe5 100644 +--- a/src/resolve/resolved-dns-domain.c ++++ b/src/resolve/resolved-dns-domain.c +@@ -371,6 +371,11 @@ int dns_name_compare_func(const void *a, const void *b) { + } + } + ++const struct hash_ops dns_name_hash_ops = { ++ .hash = dns_name_hash_func, ++ .compare = dns_name_compare_func ++}; ++ + int dns_name_equal(const char *x, const char *y) { + int r, q, k, w; + +diff --git a/src/resolve/resolved-dns-domain.h b/src/resolve/resolved-dns-domain.h +index e674c5d9c5..0888a7846f 100644 +--- a/src/resolve/resolved-dns-domain.h ++++ b/src/resolve/resolved-dns-domain.h +@@ -37,6 +37,7 @@ int dns_name_normalize(const char *s, char **_ret); + + unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]); + int dns_name_compare_func(const void *a, const void *b); ++extern const struct hash_ops dns_name_hash_ops; + + int dns_name_equal(const char *x, const char *y); + int dns_name_endswith(const char *name, const char *suffix); +diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c +index 0d276df8c9..7375f77481 100644 +--- a/src/resolve/resolved-dns-packet.c ++++ b/src/resolve/resolved-dns-packet.c +@@ -433,9 +433,7 @@ int dns_packet_append_name(DnsPacket *p, const char *name, + goto fail; + + if (allow_compression) { +- r = hashmap_ensure_allocated(&p->names, +- dns_name_hash_func, +- dns_name_compare_func); ++ r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops); + if (r < 0) + goto fail; + +diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c +index 669595d7f9..f0483c9806 100644 +--- a/src/resolve/resolved-dns-query.c ++++ b/src/resolve/resolved-dns-query.c +@@ -144,7 +144,7 @@ static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *k + assert(q); + assert(s); + +- r = set_ensure_allocated(&q->transactions, NULL, NULL); ++ r = set_ensure_allocated(&q->transactions, NULL); + if (r < 0) + return r; + +@@ -166,7 +166,7 @@ static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *k + return r; + } + +- r = set_ensure_allocated(&t->queries, NULL, NULL); ++ r = set_ensure_allocated(&t->queries, NULL); + if (r < 0) + goto gc; + +diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c +index c5f7cb931e..fd5ecf413d 100644 +--- a/src/resolve/resolved-dns-rr.c ++++ b/src/resolve/resolved-dns-rr.c +@@ -133,7 +133,7 @@ int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRec + return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); + } + +-unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) { ++static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) { + const DnsResourceKey *k = i; + unsigned long ul; + +@@ -144,7 +144,7 @@ unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[H + return ul; + } + +-int dns_resource_key_compare_func(const void *a, const void *b) { ++static int dns_resource_key_compare_func(const void *a, const void *b) { + const DnsResourceKey *x = a, *y = b; + int ret; + +@@ -165,6 +165,11 @@ int dns_resource_key_compare_func(const void *a, const void *b) { + return 0; + } + ++const struct hash_ops dns_resource_key_hash_ops = { ++ .hash = dns_resource_key_hash_func, ++ .compare = dns_resource_key_compare_func ++}; ++ + int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) { + char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)]; + const char *c, *t; +diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h +index 3222f1f0ee..9d9a89d383 100644 +--- a/src/resolve/resolved-dns-rr.h ++++ b/src/resolve/resolved-dns-rr.h +@@ -159,8 +159,6 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key); + int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b); + int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr); + int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr); +-unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]); +-int dns_resource_key_compare_func(const void *a, const void *b); + int dns_resource_key_to_string(const DnsResourceKey *key, char **ret); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref); + +@@ -175,3 +173,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref); + + const char *dns_class_to_string(uint16_t type); + int dns_class_from_string(const char *name, uint16_t *class); ++ ++extern const struct hash_ops dns_resource_key_hash_ops; +diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c +index 039a754ff0..40d59922d1 100644 +--- a/src/resolve/resolved-dns-scope.c ++++ b/src/resolve/resolved-dns-scope.c +@@ -709,7 +709,7 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) { + + /* We don't send these queries immediately. Instead, we queue + * them, and send them after some jitter delay. */ +- r = hashmap_ensure_allocated(&scope->conflict_queue, dns_resource_key_hash_func, dns_resource_key_compare_func); ++ r = hashmap_ensure_allocated(&scope->conflict_queue, &dns_resource_key_hash_ops); + if (r < 0) { + log_oom(); + return r; +diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c +index c99768be4f..caf06fe450 100644 +--- a/src/resolve/resolved-dns-server.c ++++ b/src/resolve/resolved-dns-server.c +@@ -100,7 +100,7 @@ DnsServer* dns_server_free(DnsServer *s) { + return NULL; + } + +-unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { ++static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + const DnsServer *s = p; + uint64_t u; + +@@ -110,7 +110,7 @@ unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KE + return u; + } + +-int dns_server_compare_func(const void *a, const void *b) { ++static int dns_server_compare_func(const void *a, const void *b) { + const DnsServer *x = a, *y = b; + + if (x->family < y->family) +@@ -120,3 +120,8 @@ int dns_server_compare_func(const void *a, const void *b) { + + return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family)); + } ++ ++const struct hash_ops dns_server_hash_ops = { ++ .hash = dns_server_hash_func, ++ .compare = dns_server_compare_func ++}; +diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h +index f2361a8385..a438a27763 100644 +--- a/src/resolve/resolved-dns-server.h ++++ b/src/resolve/resolved-dns-server.h +@@ -60,5 +60,4 @@ int dns_server_new( + + DnsServer* dns_server_free(DnsServer *s); + +-unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); +-int dns_server_compare_func(const void *a, const void *b); ++extern const struct hash_ops dns_server_hash_ops; +diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c +index 990b1f2e43..74b0634142 100644 +--- a/src/resolve/resolved-dns-transaction.c ++++ b/src/resolve/resolved-dns-transaction.c +@@ -78,7 +78,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) { + assert(s); + assert(q); + +- r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL, NULL); ++ r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL); + if (r < 0) + return r; + +diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c +index b53e957d76..8098ff5e70 100644 +--- a/src/resolve/resolved-dns-zone.c ++++ b/src/resolve/resolved-dns-zone.c +@@ -126,11 +126,11 @@ static int dns_zone_init(DnsZone *z) { + + assert(z); + +- r = hashmap_ensure_allocated(&z->by_key, dns_resource_key_hash_func, dns_resource_key_compare_func); ++ r = hashmap_ensure_allocated(&z->by_key, &dns_resource_key_hash_ops); + if (r < 0) + return r; + +- r = hashmap_ensure_allocated(&z->by_name, dns_name_hash_func, dns_name_compare_func); ++ r = hashmap_ensure_allocated(&z->by_name, &dns_name_hash_ops); + if (r < 0) + return r; + +@@ -194,7 +194,7 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { + return r; + } + +- r = set_ensure_allocated(&t->zone_items, NULL, NULL); ++ r = set_ensure_allocated(&t->zone_items, NULL); + if (r < 0) + goto gc; + +diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c +index f47017ced8..4def672214 100644 +--- a/src/resolve/resolved-link.c ++++ b/src/resolve/resolved-link.c +@@ -33,7 +33,7 @@ int link_new(Manager *m, Link **ret, int ifindex) { + assert(m); + assert(ifindex > 0); + +- r = hashmap_ensure_allocated(&m->links, NULL, NULL); ++ r = hashmap_ensure_allocated(&m->links, NULL); + if (r < 0) + return r; + +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index 00aaffe448..63d7845387 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -737,11 +737,11 @@ int manager_write_resolv_conf(Manager *m) { + manager_read_resolv_conf(m); + + /* Add the full list to a set, to filter out duplicates */ +- dns = set_new(dns_server_hash_func, dns_server_compare_func); ++ dns = set_new(&dns_server_hash_ops); + if (!dns) + return -ENOMEM; + +- domains = set_new(dns_name_hash_func, dns_name_compare_func); ++ domains = set_new(&dns_name_hash_ops); + if (!domains) + return -ENOMEM; + +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index 00eac64236..da8e885226 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -161,7 +161,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo + * tasks list, to properly handle forking processes */ + + if (!s) { +- s = allocated_set = set_new(trivial_hash_func, trivial_compare_func); ++ s = allocated_set = set_new(NULL); + if (!s) + return -ENOMEM; + } +@@ -239,7 +239,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si + assert(sig >= 0); + + if (!s) { +- s = allocated_set = set_new(trivial_hash_func, trivial_compare_func); ++ s = allocated_set = set_new(NULL); + if (!s) + return -ENOMEM; + } +@@ -290,7 +290,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char + assert(cto); + assert(pto); + +- s = set_new(trivial_hash_func, trivial_compare_func); ++ s = set_new(NULL); + if (!s) + return -ENOMEM; + +diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c +index c72a099b5a..e6ee97a978 100644 +--- a/src/shared/conf-files.c ++++ b/src/shared/conf-files.c +@@ -109,7 +109,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const + if (!path_strv_resolve_uniq(dirs, root)) + return -ENOMEM; + +- fh = hashmap_new(string_hash_func, string_compare_func); ++ fh = hashmap_new(&string_hash_ops); + if (!fh) + return -ENOMEM; + +diff --git a/src/shared/fdset.c b/src/shared/fdset.c +index d2ea665016..37cbd8526c 100644 +--- a/src/shared/fdset.c ++++ b/src/shared/fdset.c +@@ -38,7 +38,7 @@ + #define PTR_TO_FD(p) (PTR_TO_INT(p)-1) + + FDSet *fdset_new(void) { +- return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func)); ++ return MAKE_FDSET(set_new(NULL)); + } + + void fdset_free(FDSet *s) { +diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c +index dbf91c439e..715484ce7c 100644 +--- a/src/shared/hashmap.c ++++ b/src/shared/hashmap.c +@@ -39,8 +39,7 @@ struct hashmap_entry { + }; + + struct Hashmap { +- hash_func_t hash_func; +- compare_func_t compare_func; ++ const struct hash_ops *hash_ops; + + struct hashmap_entry *iterate_list_head, *iterate_list_tail; + +@@ -141,6 +140,11 @@ int string_compare_func(const void *a, const void *b) { + return strcmp(a, b); + } + ++const struct hash_ops string_hash_ops = { ++ .hash = string_hash_func, ++ .compare = string_compare_func ++}; ++ + unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; + siphash24((uint8_t*) &u, &p, sizeof(p), hash_key); +@@ -151,6 +155,11 @@ int trivial_compare_func(const void *a, const void *b) { + return a < b ? -1 : (a > b ? 1 : 0); + } + ++const struct hash_ops trivial_hash_ops = { ++ .hash = trivial_hash_func, ++ .compare = trivial_compare_func ++}; ++ + unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; + siphash24((uint8_t*) &u, p, sizeof(uint64_t), hash_key); +@@ -164,6 +173,11 @@ int uint64_compare_func(const void *_a, const void *_b) { + return a < b ? -1 : (a > b ? 1 : 0); + } + ++const struct hash_ops uint64_hash_ops = { ++ .hash = uint64_hash_func, ++ .compare = uint64_compare_func ++}; ++ + #if SIZEOF_DEV_T != 8 + unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; +@@ -177,10 +191,15 @@ int devt_compare_func(const void *_a, const void *_b) { + b = *(const dev_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); + } ++ ++const struct hash_ops devt_hash_ops = { ++ .hash = devt_hash_func, ++ .compare = devt_compare_func ++}; + #endif + + static unsigned bucket_hash(Hashmap *h, const void *p) { +- return (unsigned) (h->hash_func(p, h->hash_key) % h->n_buckets); ++ return (unsigned) (h->hash_ops->hash(p, h->hash_key) % h->n_buckets); + } + + static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { +@@ -202,7 +221,7 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { + memcpy(hash_key, current, sizeof(current)); + } + +-Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { ++Hashmap *hashmap_new(const struct hash_ops *hash_ops) { + bool b; + Hashmap *h; + size_t size; +@@ -224,8 +243,7 @@ Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { + return NULL; + } + +- h->hash_func = hash_func ? hash_func : trivial_hash_func; +- h->compare_func = compare_func ? compare_func : trivial_compare_func; ++ h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; + + h->n_buckets = INITIAL_N_BUCKETS; + h->n_entries = 0; +@@ -240,7 +258,7 @@ Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { + return h; + } + +-int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) { ++int hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops) { + Hashmap *q; + + assert(h); +@@ -248,7 +266,7 @@ int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t + if (*h) + return 0; + +- q = hashmap_new(hash_func, compare_func); ++ q = hashmap_new(hash_ops); + if (!q) + return -ENOMEM; + +@@ -406,7 +424,7 @@ static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *ke + assert(hash < h->n_buckets); + + for (e = h->buckets[hash]; e; e = e->bucket_next) +- if (h->compare_func(e->key, key) == 0) ++ if (h->hash_ops->compare(e->key, key) == 0) + return e; + + return NULL; +@@ -438,7 +456,7 @@ static bool resize_buckets(Hashmap *h) { + for (i = h->iterate_list_head; i; i = i->iterate_next) { + unsigned long old_bucket, new_bucket; + +- old_bucket = h->hash_func(i->key, h->hash_key) % h->n_buckets; ++ old_bucket = h->hash_ops->hash(i->key, h->hash_key) % h->n_buckets; + + /* First, drop from old bucket table */ + if (i->bucket_next) +@@ -450,7 +468,7 @@ static bool resize_buckets(Hashmap *h) { + h->buckets[old_bucket] = i->bucket_next; + + /* Then, add to new backet table */ +- new_bucket = h->hash_func(i->key, nkey) % m; ++ new_bucket = h->hash_ops->hash(i->key, nkey) % m; + + i->bucket_next = n[new_bucket]; + i->bucket_previous = NULL; +@@ -949,7 +967,7 @@ Hashmap *hashmap_copy(Hashmap *h) { + + assert(h); + +- copy = hashmap_new(h->hash_func, h->compare_func); ++ copy = hashmap_new(h->hash_ops); + if (!copy) + return NULL; + +diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h +index f89e7e8fbc..7385ebc5fa 100644 +--- a/src/shared/hashmap.h ++++ b/src/shared/hashmap.h +@@ -43,38 +43,50 @@ typedef _IteratorStruct* Iterator; + typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); + typedef int (*compare_func_t)(const void *a, const void *b); + ++struct hash_ops { ++ hash_func_t hash; ++ compare_func_t compare; ++}; ++ + unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; + int string_compare_func(const void *a, const void *b) _pure_; ++extern const struct hash_ops string_hash_ops; + + /* This will compare the passed pointers directly, and will not + * dereference them. This is hence not useful for strings or + * suchlike. */ + unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; + int trivial_compare_func(const void *a, const void *b) _const_; ++extern const struct hash_ops trivial_hash_ops; + + /* 32bit values we can always just embedd in the pointer itself, but + * in order to support 32bit archs we need store 64bit values + * indirectly, since they don't fit in a pointer. */ + unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; + int uint64_compare_func(const void *a, const void *b) _pure_; ++extern const struct hash_ops uint64_hash_ops; + + /* On some archs dev_t is 32bit, and on others 64bit. And sometimes + * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ + #if SIZEOF_DEV_T != 8 + unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; + int devt_compare_func(const void *a, const void *b) _pure_; ++extern const struct hash_ops devt_hash_ops = { ++ .hash = devt_hash_func, ++ .compare = devt_compare_func ++}; + #else +-/* No need to define a second version of this... */ + #define devt_hash_func uint64_hash_func + #define devt_compare_func uint64_compare_func ++#define devt_hash_ops uint64_hash_ops + #endif + +-Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func); ++Hashmap *hashmap_new(const struct hash_ops *hash_ops); + void hashmap_free(Hashmap *h); + void hashmap_free_free(Hashmap *h); + void hashmap_free_free_free(Hashmap *h); + Hashmap *hashmap_copy(Hashmap *h); +-int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func); ++int hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops); + + int hashmap_put(Hashmap *h, const void *key, void *value); + int hashmap_update(Hashmap *h, const void *key, void *value); +diff --git a/src/shared/install.c b/src/shared/install.c +index 3ef995a928..5d3fcf5e32 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -179,7 +179,7 @@ static int mark_symlink_for_removal( + + assert(p); + +- r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func); ++ r = set_ensure_allocated(remove_symlinks_to, &string_hash_ops); + if (r < 0) + return r; + +@@ -884,7 +884,7 @@ static int install_info_add( + hashmap_get(c->will_install, name)) + return 0; + +- r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&c->will_install, &string_hash_ops); + if (r < 0) + return r; + +@@ -1393,7 +1393,7 @@ static int install_context_apply( + + while ((i = hashmap_first(c->will_install))) { + +- q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); ++ q = hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); + if (q < 0) + return q; + +@@ -1434,7 +1434,7 @@ static int install_context_mark_for_removal( + + while ((i = hashmap_first(c->will_install))) { + +- q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); ++ q = hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); + if (q < 0) + return q; + +diff --git a/src/shared/locale-util.c b/src/shared/locale-util.c +index 8d2c363036..68851ae13d 100644 +--- a/src/shared/locale-util.c ++++ b/src/shared/locale-util.c +@@ -160,7 +160,7 @@ int get_locales(char ***ret) { + _cleanup_strv_free_ char **l = NULL; + int r; + +- locales = set_new(string_hash_func, string_compare_func); ++ locales = set_new(&string_hash_ops); + if (!locales) + return -ENOMEM; + +diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c +index 5538dd3b9e..5a7bbaf03a 100644 +--- a/src/shared/logs-show.c ++++ b/src/shared/logs-show.c +@@ -695,7 +695,7 @@ static int output_json( + sd_id128_to_string(boot_id, sid)); + } + +- h = hashmap_new(string_hash_func, string_compare_func); ++ h = hashmap_new(&string_hash_ops); + if (!h) + return -ENOMEM; + +diff --git a/src/shared/set.c b/src/shared/set.c +index 02ea831593..d4ffe056d5 100644 +--- a/src/shared/set.c ++++ b/src/shared/set.c +@@ -30,8 +30,8 @@ + + /* For now this is not much more than a wrapper around a hashmap */ + +-Set *set_new(hash_func_t hash_func, compare_func_t compare_func) { +- return MAKE_SET(hashmap_new(hash_func, compare_func)); ++Set *set_new(const struct hash_ops *hash_ops) { ++ return MAKE_SET(hashmap_new(hash_ops)); + } + + void set_free(Set* s) { +@@ -42,8 +42,8 @@ void set_free_free(Set *s) { + hashmap_free_free(MAKE_HASHMAP(s)); + } + +-int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) { +- return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func); ++int set_ensure_allocated(Set **s, const struct hash_ops *hash_ops) { ++ return hashmap_ensure_allocated((Hashmap**) s, hash_ops); + } + + int set_put(Set *s, void *value) { +diff --git a/src/shared/set.h b/src/shared/set.h +index e0b9c9e0a8..e650b7e3fe 100644 +--- a/src/shared/set.h ++++ b/src/shared/set.h +@@ -32,12 +32,12 @@ + + typedef struct Set Set; + +-Set *set_new(hash_func_t hash_func, compare_func_t compare_func); ++Set *set_new(const struct hash_ops *hash_ops); + void set_free(Set* s); + void set_free_free(Set *s); + + Set* set_copy(Set *s); +-int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func); ++int set_ensure_allocated(Set **s, const struct hash_ops *hash_ops); + + int set_put(Set *s, void *value); + int set_consume(Set *s, void *value); +diff --git a/src/shared/util.c b/src/shared/util.c +index 502b3675b1..61d6680ddd 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3911,7 +3911,7 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv + } + } + +- pids = hashmap_new(NULL, NULL); ++ pids = hashmap_new(NULL); + if (!pids) { + log_oom(); + _exit(EXIT_FAILURE); +@@ -6694,7 +6694,7 @@ int bind_remount_recursive(const char *prefix, bool ro) { + + path_kill_slashes(cleaned); + +- done = set_new(string_hash_func, string_compare_func); ++ done = set_new(&string_hash_ops); + if (!done) + return -ENOMEM; + +@@ -6704,7 +6704,7 @@ int bind_remount_recursive(const char *prefix, bool ro) { + bool top_autofs = false; + char *x; + +- todo = set_new(string_hash_func, string_compare_func); ++ todo = set_new(&string_hash_ops); + if (!todo) + return -ENOMEM; + +diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c +index f6e6672cdf..81d8457fdd 100644 +--- a/src/socket-proxy/socket-proxyd.c ++++ b/src/socket-proxy/socket-proxyd.c +@@ -473,7 +473,7 @@ static int add_connection_socket(Context *context, int fd) { + return 0; + } + +- r = set_ensure_allocated(&context->connections, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&context->connections, NULL); + if (r < 0) { + log_oom(); + return 0; +@@ -543,7 +543,7 @@ static int add_listen_socket(Context *context, int fd) { + assert(context); + assert(fd >= 0); + +- r = set_ensure_allocated(&context->listen, trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&context->listen, NULL); + if (r < 0) { + log_oom(); + return r; +diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c +index 8ce9870432..4f9530baf8 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -292,7 +292,7 @@ int main(int argc, char *argv[]) { + + umask(0022); + +- sysctl_options = hashmap_new(string_hash_func, string_compare_func); ++ sysctl_options = hashmap_new(&string_hash_ops); + if (!sysctl_options) { + r = log_oom(); + goto finish; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index de43c879a7..88be871f32 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -594,7 +594,7 @@ static int get_unit_list_recursive( + assert(_unit_infos); + assert(_machines); + +- replies = set_new(NULL, NULL); ++ replies = set_new(NULL); + if (!replies) + return log_oom(); + +@@ -1338,7 +1338,7 @@ static int list_unit_files(sd_bus *bus, char **args) { + Iterator i; + unsigned n_units; + +- h = hashmap_new(string_hash_func, string_compare_func); ++ h = hashmap_new(&string_hash_ops); + if (!h) + return log_oom(); + +@@ -2746,7 +2746,7 @@ static int start_unit(sd_bus *bus, char **args) { + return r; + } + +- s = set_new(string_hash_func, string_compare_func); ++ s = set_new(&string_hash_ops); + if (!s) + return log_oom(); + } +diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c +index b889ed0536..ba20d949dc 100644 +--- a/src/sysusers/sysusers.c ++++ b/src/sysusers/sysusers.c +@@ -107,11 +107,11 @@ static int load_user_database(void) { + if (!f) + return errno == ENOENT ? 0 : -errno; + +- r = hashmap_ensure_allocated(&database_user, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&database_user, &string_hash_ops); + if (r < 0) + return r; + +- r = hashmap_ensure_allocated(&database_uid, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&database_uid, NULL); + if (r < 0) + return r; + +@@ -159,11 +159,11 @@ static int load_group_database(void) { + if (!f) + return errno == ENOENT ? 0 : -errno; + +- r = hashmap_ensure_allocated(&database_group, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&database_group, &string_hash_ops); + if (r < 0) + return r; + +- r = hashmap_ensure_allocated(&database_gid, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&database_gid, NULL); + if (r < 0) + return r; + +@@ -969,7 +969,7 @@ static int add_user(Item *i) { + i->uid = search_uid; + } + +- r = hashmap_ensure_allocated(&todo_uids, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&todo_uids, NULL); + if (r < 0) + return log_oom(); + +@@ -1122,7 +1122,7 @@ static int add_group(Item *i) { + i->gid = search_uid; + } + +- r = hashmap_ensure_allocated(&todo_gids, trivial_hash_func, trivial_compare_func); ++ r = hashmap_ensure_allocated(&todo_gids, NULL); + if (r < 0) + return log_oom(); + +@@ -1210,7 +1210,7 @@ static int add_implicit(void) { + if (!i) { + _cleanup_(item_freep) Item *j = NULL; + +- r = hashmap_ensure_allocated(&groups, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&groups, &string_hash_ops); + if (r < 0) + return log_oom(); + +@@ -1237,7 +1237,7 @@ static int add_implicit(void) { + if (!i) { + _cleanup_(item_freep) Item *j = NULL; + +- r = hashmap_ensure_allocated(&users, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&users, &string_hash_ops); + if (r < 0) + return log_oom(); + +@@ -1542,7 +1542,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + return -EINVAL; + } + +- r = hashmap_ensure_allocated(&members, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&members, &string_hash_ops); + if (r < 0) + return log_oom(); + +@@ -1584,7 +1584,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + return -EINVAL; + } + +- r = hashmap_ensure_allocated(&users, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&users, &string_hash_ops); + if (r < 0) + return log_oom(); + +@@ -1634,7 +1634,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + return -EINVAL; + } + +- r = hashmap_ensure_allocated(&groups, string_hash_func, string_compare_func); ++ r = hashmap_ensure_allocated(&groups, &string_hash_ops); + if (r < 0) + return log_oom(); + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 368d420df3..6c3281ff15 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -824,8 +824,7 @@ static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) { + MAX(a*10 + b, service->sysv_start_priority); + } + +- r = set_ensure_allocated(&runlevel_services[i], +- trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&runlevel_services[i], NULL); + if (r < 0) + goto finish; + +@@ -836,8 +835,7 @@ static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) { + } else if (de->d_name[0] == 'K' && + (rcnd_table[i].type == RUNLEVEL_DOWN)) { + +- r = set_ensure_allocated(&shutdown_services, +- trivial_hash_func, trivial_compare_func); ++ r = set_ensure_allocated(&shutdown_services, NULL); + if (r < 0) + goto finish; + +@@ -905,7 +903,7 @@ int main(int argc, char *argv[]) { + return EXIT_FAILURE; + } + +- all_services = hashmap_new(string_hash_func, string_compare_func); ++ all_services = hashmap_new(&string_hash_ops); + if (!all_services) { + log_oom(); + return EXIT_FAILURE; +diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c +index ccef61f55c..95a7f8379d 100644 +--- a/src/test/test-hashmap.c ++++ b/src/test/test-hashmap.c +@@ -26,7 +26,7 @@ static void test_hashmap_replace(void) { + Hashmap *m; + char *val1, *val2, *val3, *val4, *val5, *r; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + val1 = strdup("val1"); + assert_se(val1); +@@ -73,7 +73,7 @@ static void test_hashmap_copy(void) { + val4 = strdup("val4"); + assert_se(val4); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); +@@ -109,7 +109,7 @@ static void test_hashmap_get_strv(void) { + val4 = strdup("val4"); + assert_se(val4); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); +@@ -141,8 +141,8 @@ static void test_hashmap_move_one(void) { + val4 = strdup("val4"); + assert_se(val4); + +- m = hashmap_new(string_hash_func, string_compare_func); +- n = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); ++ n = hashmap_new(&string_hash_ops); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); +@@ -168,7 +168,7 @@ static void test_hashmap_next(void) { + Hashmap *m; + char *val1, *val2, *val3, *val4, *r; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + val1 = strdup("val1"); + assert_se(val1); + val2 = strdup("val2"); +@@ -199,7 +199,7 @@ static void test_hashmap_update(void) { + Hashmap *m; + char *val1, *val2, *r; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + val1 = strdup("old_value"); + assert_se(val1); + val2 = strdup("new_value"); +@@ -222,7 +222,7 @@ static void test_hashmap_put(void) { + Hashmap *m; + int valid_hashmap_put; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + valid_hashmap_put = hashmap_put(m, "key 1", (void*) (const char *) "val 1"); + assert_se(valid_hashmap_put == 1); +@@ -236,7 +236,7 @@ static void test_hashmap_remove_and_put(void) { + int valid; + char *r; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + assert_se(m); + + valid = hashmap_remove_and_put(m, "unvalid key", "new key", NULL); +@@ -261,9 +261,9 @@ static void test_hashmap_ensure_allocated(void) { + Hashmap *m; + int valid_hashmap; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + +- valid_hashmap = hashmap_ensure_allocated(&m, string_hash_func, string_compare_func); ++ valid_hashmap = hashmap_ensure_allocated(&m, &string_hash_ops); + assert_se(valid_hashmap == 0); + + assert_se(m); +@@ -282,7 +282,7 @@ static void test_hashmap_foreach_key(void) { + "key 3\0" + "key 4\0"; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + NULSTR_FOREACH(key, key_table) + hashmap_put(m, key, (void*) (const char*) "my dummy val"); +@@ -319,7 +319,7 @@ static void test_hashmap_foreach(void) { + val4 = strdup("my val4"); + assert_se(val4); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); +@@ -358,7 +358,7 @@ static void test_hashmap_foreach_backwards(void) { + val4 = strdup("my val4"); + assert_se(val4); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); + hashmap_put(m, "Key 3", val3); +@@ -395,8 +395,8 @@ static void test_hashmap_merge(void) { + val4 = strdup("my val4"); + assert_se(val4); + +- n = hashmap_new(string_hash_func, string_compare_func); +- m = hashmap_new(string_hash_func, string_compare_func); ++ n = hashmap_new(&string_hash_ops); ++ m = hashmap_new(&string_hash_ops); + + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); +@@ -422,7 +422,7 @@ static void test_hashmap_contains(void) { + val1 = strdup("my val"); + assert_se(val1); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + assert_se(!hashmap_contains(m, "Key 1")); + hashmap_put(m, "Key 1", val1); +@@ -439,7 +439,7 @@ static void test_hashmap_isempty(void) { + val1 = strdup("my val"); + assert_se(val1); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + assert_se(hashmap_isempty(m)); + hashmap_put(m, "Key 1", val1); +@@ -462,7 +462,7 @@ static void test_hashmap_size(void) { + val4 = strdup("my val"); + assert_se(val4); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); +@@ -482,7 +482,7 @@ static void test_hashmap_get(void) { + val = strdup("my val"); + assert_se(val); + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + + hashmap_put(m, "Key 1", val); + +@@ -499,7 +499,7 @@ static void test_hashmap_many(void) { + + #define N_ENTRIES 100000 + +- assert_se(h = hashmap_new(NULL, NULL)); ++ assert_se(h = hashmap_new(NULL)); + + for (i = 1; i < N_ENTRIES*3; i+=3) { + assert_se(hashmap_put(h, UINT_TO_PTR(i), UINT_TO_PTR(i)) >= 0); +@@ -520,7 +520,7 @@ static void test_hashmap_many(void) { + static void test_hashmap_first_key(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + assert_se(m); + + assert_se(!hashmap_first_key(m)); +@@ -535,7 +535,7 @@ static void test_hashmap_first_key(void) { + static void test_hashmap_last(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + assert_se(m); + + assert_se(!hashmap_last(m)); +@@ -550,7 +550,7 @@ static void test_hashmap_last(void) { + static void test_hashmap_steal_first_key(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + assert_se(m); + + assert_se(!hashmap_steal_first_key(m)); +@@ -563,7 +563,7 @@ static void test_hashmap_steal_first_key(void) { + static void test_hashmap_clear_free_free(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + +- m = hashmap_new(string_hash_func, string_compare_func); ++ m = hashmap_new(&string_hash_ops); + assert_se(m); + + assert_se(hashmap_put(m, strdup("key 1"), NULL) == 1); +diff --git a/src/test/test-install.c b/src/test/test-install.c +index 099eb401d7..b0f77a18f3 100644 +--- a/src/test/test-install.c ++++ b/src/test/test-install.c +@@ -51,7 +51,7 @@ int main(int argc, char* argv[]) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + +- h = hashmap_new(string_hash_func, string_compare_func); ++ h = hashmap_new(&string_hash_ops); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + assert_se(r == 0); + +diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c +index cdb1e4ad52..dfedc9b8dc 100644 +--- a/src/test/test-prioq.c ++++ b/src/test/test-prioq.c +@@ -98,6 +98,11 @@ static unsigned long test_hash(const void *a, const uint8_t hash_key[HASH_KEY_SI + return (unsigned long) u; + } + ++static const struct hash_ops test_hash_ops = { ++ .hash = test_hash, ++ .compare = test_compare ++}; ++ + static void test_struct(void) { + Prioq *q; + Set *s; +@@ -109,7 +114,7 @@ static void test_struct(void) { + q = prioq_new(test_compare); + assert_se(q); + +- s = set_new(test_hash, test_compare); ++ s = set_new(&test_hash_ops); + assert_se(s); + + for (i = 0; i < SET_SIZE; i++) { +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 34865729f2..89f5bdd4ed 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -44,7 +44,7 @@ static int test_unit_file_get_set(void) { + Iterator i; + UnitFileList *p; + +- h = hashmap_new(string_hash_func, string_compare_func); ++ h = hashmap_new(&string_hash_ops); + assert(h); + + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 3bab7ac137..f9830c431d 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -165,7 +165,7 @@ static void load_unix_sockets(void) { + /* We maintain a cache of the sockets we found in + * /proc/net/unix to speed things up a little. */ + +- unix_sockets = set_new(string_hash_func, string_compare_func); ++ unix_sockets = set_new(&string_hash_ops); + if (!unix_sockets) + return; + +@@ -1608,8 +1608,8 @@ int main(int argc, char *argv[]) { + + label_init(NULL); + +- items = hashmap_new(string_hash_func, string_compare_func); +- globs = hashmap_new(string_hash_func, string_compare_func); ++ items = hashmap_new(&string_hash_ops); ++ globs = hashmap_new(&string_hash_ops); + + if (!items || !globs) { + r = log_oom(); diff --git a/0244-hashmap-set-remove-unused-functions.patch b/0244-hashmap-set-remove-unused-functions.patch new file mode 100644 index 0000000..87ac48d --- /dev/null +++ b/0244-hashmap-set-remove-unused-functions.patch @@ -0,0 +1,281 @@ +From 631b9deefbef76c5f69b165f33cb46690c938c95 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Thu, 31 Jul 2014 18:04:20 +0200 +Subject: [PATCH] hashmap, set: remove unused functions + +The following hashmap_* and set_* functions/macros have never had any +users in systemd's history: + + *_iterate_backwards + *_iterate_skip + *_last + *_FOREACH_BACKWARDS + +Remove this dead code. +--- + src/shared/hashmap.c | 64 ------------------------------------------------- + src/shared/hashmap.h | 6 ----- + src/shared/set.c | 12 ---------- + src/shared/set.h | 6 ----- + src/test/test-hashmap.c | 55 ------------------------------------------ + 5 files changed, 143 deletions(-) + +diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c +index 715484ce7c..1eadeced5c 100644 +--- a/src/shared/hashmap.c ++++ b/src/shared/hashmap.c +@@ -753,59 +753,6 @@ at_end: + return NULL; + } + +-void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) { +- struct hashmap_entry *e; +- +- assert(i); +- +- if (!h) +- goto at_beginning; +- +- if (*i == ITERATOR_FIRST) +- goto at_beginning; +- +- if (*i == ITERATOR_LAST && !h->iterate_list_tail) +- goto at_beginning; +- +- e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i; +- +- if (e->iterate_previous) +- *i = (Iterator) e->iterate_previous; +- else +- *i = ITERATOR_FIRST; +- +- if (key) +- *key = e->key; +- +- return e->value; +- +-at_beginning: +- *i = ITERATOR_FIRST; +- +- if (key) +- *key = NULL; +- +- return NULL; +-} +- +-void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) { +- unsigned hash; +- struct hashmap_entry *e; +- +- if (!h) +- return NULL; +- +- hash = bucket_hash(h, key); +- +- e = hash_scan(h, hash, key); +- if (!e) +- return NULL; +- +- *i = (Iterator) e; +- +- return e->value; +-} +- + void* hashmap_first(Hashmap *h) { + + if (!h) +@@ -828,17 +775,6 @@ void* hashmap_first_key(Hashmap *h) { + return (void*) h->iterate_list_head->key; + } + +-void* hashmap_last(Hashmap *h) { +- +- if (!h) +- return NULL; +- +- if (!h->iterate_list_tail) +- return NULL; +- +- return h->iterate_list_tail->value; +-} +- + void* hashmap_steal_first(Hashmap *h) { + void *data; + +diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h +index 7385ebc5fa..e25840f47f 100644 +--- a/src/shared/hashmap.h ++++ b/src/shared/hashmap.h +@@ -109,8 +109,6 @@ bool hashmap_isempty(Hashmap *h) _pure_; + unsigned hashmap_buckets(Hashmap *h) _pure_; + + void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key); +-void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key); +-void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i); + + void hashmap_clear(Hashmap *h); + void hashmap_clear_free(Hashmap *h); +@@ -120,7 +118,6 @@ void *hashmap_steal_first(Hashmap *h); + void *hashmap_steal_first_key(Hashmap *h); + void *hashmap_first(Hashmap *h) _pure_; + void *hashmap_first_key(Hashmap *h) _pure_; +-void *hashmap_last(Hashmap *h) _pure_; + + void *hashmap_next(Hashmap *h, const void *key); + +@@ -132,9 +129,6 @@ char **hashmap_get_strv(Hashmap *h); + #define HASHMAP_FOREACH_KEY(e, k, h, i) \ + for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k))) + +-#define HASHMAP_FOREACH_BACKWARDS(e, h, i) \ +- for ((i) = ITERATOR_LAST, (e) = hashmap_iterate_backwards((h), &(i), NULL); (e); (e) = hashmap_iterate_backwards((h), &(i), NULL)) +- + DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); + DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); + DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); +diff --git a/src/shared/set.c b/src/shared/set.c +index d4ffe056d5..ed16067bdc 100644 +--- a/src/shared/set.c ++++ b/src/shared/set.c +@@ -125,14 +125,6 @@ void *set_iterate(Set *s, Iterator *i) { + return hashmap_iterate(MAKE_HASHMAP(s), i, NULL); + } + +-void *set_iterate_backwards(Set *s, Iterator *i) { +- return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL); +-} +- +-void *set_iterate_skip(Set *s, void *value, Iterator *i) { +- return hashmap_iterate_skip(MAKE_HASHMAP(s), value, i); +-} +- + void *set_steal_first(Set *s) { + return hashmap_steal_first(MAKE_HASHMAP(s)); + } +@@ -141,10 +133,6 @@ void* set_first(Set *s) { + return hashmap_first(MAKE_HASHMAP(s)); + } + +-void* set_last(Set *s) { +- return hashmap_last(MAKE_HASHMAP(s)); +-} +- + int set_merge(Set *s, Set *other) { + return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other)); + } +diff --git a/src/shared/set.h b/src/shared/set.h +index e650b7e3fe..840ee0a7e4 100644 +--- a/src/shared/set.h ++++ b/src/shared/set.h +@@ -57,24 +57,18 @@ unsigned set_size(Set *s); + bool set_isempty(Set *s); + + void *set_iterate(Set *s, Iterator *i); +-void *set_iterate_backwards(Set *s, Iterator *i); +-void *set_iterate_skip(Set *s, void *value, Iterator *i); + + void set_clear(Set *s); + void set_clear_free(Set *s); + + void *set_steal_first(Set *s); + void* set_first(Set *s); +-void* set_last(Set *s); + + char **set_get_strv(Set *s); + + #define SET_FOREACH(e, s, i) \ + for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i))) + +-#define SET_FOREACH_BACKWARDS(e, s, i) \ +- for ((i) = ITERATOR_LAST, (e) = set_iterate_backwards((s), &(i)); (e); (e) = set_iterate_backwards((s), &(i))) +- + DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); + DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); + #define _cleanup_set_free_ _cleanup_(set_freep) +diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c +index 95a7f8379d..d9863f8dab 100644 +--- a/src/test/test-hashmap.c ++++ b/src/test/test-hashmap.c +@@ -343,44 +343,6 @@ static void test_hashmap_foreach(void) { + hashmap_free_free(m); + } + +-static void test_hashmap_foreach_backwards(void) { +- Hashmap *m; +- Iterator i; +- char *val1, *val2, *val3, *val4, *s; +- bool value_found[] = { false, false, false, false }; +- +- val1 = strdup("my val1"); +- assert_se(val1); +- val2 = strdup("my val2"); +- assert_se(val2); +- val3 = strdup("my val3"); +- assert_se(val3); +- val4 = strdup("my val4"); +- assert_se(val4); +- +- m = hashmap_new(&string_hash_ops); +- hashmap_put(m, "Key 1", val1); +- hashmap_put(m, "Key 2", val2); +- hashmap_put(m, "Key 3", val3); +- hashmap_put(m, "Key 4", val4); +- +- HASHMAP_FOREACH_BACKWARDS(s, m, i) { +- if (!value_found[0] && streq(s, val1)) +- value_found[0] = true; +- else if (!value_found[1] && streq(s, val2)) +- value_found[1] = true; +- else if (!value_found[2] && streq(s, val3)) +- value_found[2] = true; +- else if (!value_found[3] && streq(s, val4)) +- value_found[3] = true; +- } +- +- assert_se(m); +- assert_se(value_found[0] && value_found[1] && value_found[2] && value_found[3]); +- +- hashmap_free_free(m); +-} +- + static void test_hashmap_merge(void) { + Hashmap *m; + Hashmap *n; +@@ -532,21 +494,6 @@ static void test_hashmap_first_key(void) { + assert_se(streq(hashmap_first_key(m), "key 2")); + } + +-static void test_hashmap_last(void) { +- _cleanup_hashmap_free_ Hashmap *m = NULL; +- +- m = hashmap_new(&string_hash_ops); +- assert_se(m); +- +- assert_se(!hashmap_last(m)); +- assert_se(hashmap_put(m, "key 1", (void *) (const char *) "val 1") == 1); +- assert_se(streq(hashmap_last(m), "val 1")); +- assert_se(hashmap_put(m, "key 2", (void *) (const char *) "bar") == 1); +- assert_se(streq(hashmap_last(m), "bar")); +- assert_se(hashmap_remove(m, "key 2")); +- assert_se(streq(hashmap_last(m), "val 1")); +-} +- + static void test_hashmap_steal_first_key(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + +@@ -604,7 +551,6 @@ int main(int argc, const char *argv[]) { + test_hashmap_remove_and_put(); + test_hashmap_ensure_allocated(); + test_hashmap_foreach(); +- test_hashmap_foreach_backwards(); + test_hashmap_foreach_key(); + test_hashmap_contains(); + test_hashmap_merge(); +@@ -613,7 +559,6 @@ int main(int argc, const char *argv[]) { + test_hashmap_size(); + test_hashmap_many(); + test_hashmap_first_key(); +- test_hashmap_last(); + test_hashmap_steal_first_key(); + test_hashmap_clear_free_free(); + test_uint64_compare_func(); diff --git a/0245-hashmap-minor-hashmap_replace-optimization.patch b/0245-hashmap-minor-hashmap_replace-optimization.patch new file mode 100644 index 0000000..9dd9363 --- /dev/null +++ b/0245-hashmap-minor-hashmap_replace-optimization.patch @@ -0,0 +1,72 @@ +From 923041cb0ab7c1795e74fa1ce4b38a6114727a3c Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Sun, 10 Aug 2014 23:35:27 +0200 +Subject: [PATCH] hashmap: minor hashmap_replace optimization + +When hashmap_replace detects no such key exists yet, it calls hashmap_put that +performs the same check again. Avoid that by splitting the core of hashmap_put +into a separate function. +--- + src/shared/hashmap.c | 34 +++++++++++++++++++++------------- + 1 file changed, 21 insertions(+), 13 deletions(-) + +diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c +index 1eadeced5c..4c517059f6 100644 +--- a/src/shared/hashmap.c ++++ b/src/shared/hashmap.c +@@ -488,19 +488,10 @@ static bool resize_buckets(Hashmap *h) { + return true; + } + +-int hashmap_put(Hashmap *h, const void *key, void *value) { +- struct hashmap_entry *e; +- unsigned hash; +- +- assert(h); ++static int __hashmap_put(Hashmap *h, const void *key, void *value, unsigned hash) { ++ /* For when we know no such entry exists yet */ + +- hash = bucket_hash(h, key); +- e = hash_scan(h, hash, key); +- if (e) { +- if (e->value == value) +- return 0; +- return -EEXIST; +- } ++ struct hashmap_entry *e; + + if (resize_buckets(h)) + hash = bucket_hash(h, key); +@@ -521,6 +512,23 @@ int hashmap_put(Hashmap *h, const void *key, void *value) { + return 1; + } + ++int hashmap_put(Hashmap *h, const void *key, void *value) { ++ struct hashmap_entry *e; ++ unsigned hash; ++ ++ assert(h); ++ ++ hash = bucket_hash(h, key); ++ e = hash_scan(h, hash, key); ++ if (e) { ++ if (e->value == value) ++ return 0; ++ return -EEXIST; ++ } ++ ++ return __hashmap_put(h, key, value, hash); ++} ++ + int hashmap_replace(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; +@@ -535,7 +543,7 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) { + return 0; + } + +- return hashmap_put(h, key, value); ++ return __hashmap_put(h, key, value, hash); + } + + int hashmap_update(Hashmap *h, const void *key, void *value) { diff --git a/0246-sd-bus-use-proper-ITERATOR_FIRST-abstraction.patch b/0246-sd-bus-use-proper-ITERATOR_FIRST-abstraction.patch new file mode 100644 index 0000000..2678ff1 --- /dev/null +++ b/0246-sd-bus-use-proper-ITERATOR_FIRST-abstraction.patch @@ -0,0 +1,24 @@ +From 4dd6c5726d87a336888c0d871b9260c98f689016 Mon Sep 17 00:00:00 2001 +From: Michal Schmidt +Date: Mon, 4 Aug 2014 22:54:10 +0200 +Subject: [PATCH] sd-bus: use proper ITERATOR_FIRST abstraction + +Do not assume hashmap iterators are pointers. +They may be structs in an alternative hashmap implementation. +--- + src/libsystemd/sd-bus/bus-track.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c +index 0a3322a4ee..4b6a8bfee9 100644 +--- a/src/libsystemd/sd-bus/bus-track.c ++++ b/src/libsystemd/sd-bus/bus-track.c +@@ -245,7 +245,7 @@ _public_ const char* sd_bus_track_first(sd_bus_track *track) { + return NULL; + + track->modified = false; +- track->iterator = NULL; ++ track->iterator = ITERATOR_FIRST; + + hashmap_iterate(track->names, &track->iterator, (const void**) &n); + return n; diff --git a/0247-remove-unneeded-error.h-includes.patch b/0247-remove-unneeded-error.h-includes.patch new file mode 100644 index 0000000..fc8857d --- /dev/null +++ b/0247-remove-unneeded-error.h-includes.patch @@ -0,0 +1,37 @@ +From 1acf16634912d8a35690fff9d7ad2bd0a91ce576 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Mon, 15 Sep 2014 15:29:18 +0200 +Subject: [PATCH] remove unneeded error.h includes + +These are the only two places where this glibc-specific +header is included. However none of the definitions in it +seem to be used, so just remove the includes. +--- + src/notify/notify.c | 1 - + src/path/path.c | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/src/notify/notify.c b/src/notify/notify.c +index 6f1c52e3fb..33933e4bf6 100644 +--- a/src/notify/notify.c ++++ b/src/notify/notify.c +@@ -21,7 +21,6 @@ + + #include + #include +-#include + #include + #include + #include +diff --git a/src/path/path.c b/src/path/path.c +index 347921a07e..37f2571fab 100644 +--- a/src/path/path.c ++++ b/src/path/path.c +@@ -21,7 +21,6 @@ + + #include + #include +-#include + #include + #include + #include diff --git a/0248-terminal-fix-missing-hashmap_new-conversions.patch b/0248-terminal-fix-missing-hashmap_new-conversions.patch new file mode 100644 index 0000000..7eeaa50 --- /dev/null +++ b/0248-terminal-fix-missing-hashmap_new-conversions.patch @@ -0,0 +1,81 @@ +From 440046e9220aa418ac0ffbdf126512b3341dce23 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 15 Sep 2014 17:12:41 +0200 +Subject: [PATCH] terminal: fix missing hashmap_new() conversions + +hashmap_new() now takes *_ops instead of individual functions. Fix up any +missing invokations of it that haven't been converted already. +--- + src/libsystemd-terminal/idev.c | 8 ++++---- + src/libsystemd-terminal/sysview.c | 10 +++++----- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c +index d37e0313e4..8592930662 100644 +--- a/src/libsystemd-terminal/idev.c ++++ b/src/libsystemd-terminal/idev.c +@@ -454,11 +454,11 @@ int idev_session_new(idev_session **out, + return r; + } + +- s->element_map = hashmap_new(string_hash_func, string_compare_func); ++ s->element_map = hashmap_new(&string_hash_ops); + if (!s->element_map) + return -ENOMEM; + +- s->device_map = hashmap_new(string_hash_func, string_compare_func); ++ s->device_map = hashmap_new(&string_hash_ops); + if (!s->device_map) + return -ENOMEM; + +@@ -647,11 +647,11 @@ int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus) { + if (sysbus) + c->sysbus = sd_bus_ref(sysbus); + +- c->session_map = hashmap_new(string_hash_func, string_compare_func); ++ c->session_map = hashmap_new(&string_hash_ops); + if (!c->session_map) + return -ENOMEM; + +- c->data_map = hashmap_new(string_hash_func, string_compare_func); ++ c->data_map = hashmap_new(&string_hash_ops); + if (!c->data_map) + return -ENOMEM; + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index bd345fa22e..2083f5a7e0 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -368,11 +368,11 @@ int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *name) { + if (!seat->name) + return -ENOMEM; + +- seat->session_map = hashmap_new(string_hash_func, string_compare_func); ++ seat->session_map = hashmap_new(&string_hash_ops); + if (!seat->session_map) + return -ENOMEM; + +- seat->device_map = hashmap_new(string_hash_func, string_compare_func); ++ seat->device_map = hashmap_new(&string_hash_ops); + if (!seat->device_map) + return -ENOMEM; + +@@ -767,15 +767,15 @@ int sysview_context_new(sysview_context **out, + return errno > 0 ? -errno : -EFAULT; + } + +- c->seat_map = hashmap_new(string_hash_func, string_compare_func); ++ c->seat_map = hashmap_new(&string_hash_ops); + if (!c->seat_map) + return -ENOMEM; + +- c->session_map = hashmap_new(string_hash_func, string_compare_func); ++ c->session_map = hashmap_new(&string_hash_ops); + if (!c->session_map) + return -ENOMEM; + +- c->device_map = hashmap_new(string_hash_func, string_compare_func); ++ c->device_map = hashmap_new(&string_hash_ops); + if (!c->device_map) + return -ENOMEM; + diff --git a/0249-man-sd_bus_error-typo-fix.patch b/0249-man-sd_bus_error-typo-fix.patch new file mode 100644 index 0000000..3537b6a --- /dev/null +++ b/0249-man-sd_bus_error-typo-fix.patch @@ -0,0 +1,22 @@ +From f70ca25ae05a92265b59bfb975cc935968d759aa Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Mon, 15 Sep 2014 23:17:57 +0200 +Subject: [PATCH] man: sd_bus_error typo fix + +--- + man/sd_bus_error.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml +index 7f4160753e..7144f4ba32 100644 +--- a/man/sd_bus_error.xml ++++ b/man/sd_bus_error.xml +@@ -296,7 +296,7 @@ along with systemd; If not, see . + name will be generated from + format and the arguments. + +- sd_bus_error_get_errno is will convert ++ sd_bus_error_get_errno will convert + e->name to an errno-like value using the + same rules as sd_bus_error_set. If + e is NULL, 0 will be diff --git a/0250-udev-split-out-help-and-modernise-a-bit.patch b/0250-udev-split-out-help-and-modernise-a-bit.patch new file mode 100644 index 0000000..93ff3d3 --- /dev/null +++ b/0250-udev-split-out-help-and-modernise-a-bit.patch @@ -0,0 +1,52 @@ +From ed216e1ff0fdd7950b662b9ce7cbb5ca40b575a1 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 12 Sep 2014 14:18:06 +0200 +Subject: [PATCH] udev: split out help and modernise a bit + +--- + src/udev/udevd.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index e54bfec3b3..f0ecbf83ef 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -997,6 +997,20 @@ static void kernel_cmdline_options(struct udev *udev) { + } + } + ++static void help(void) { ++ printf("%s [OPTIONS...]\n\n" ++ "Manages devices.\n\n" ++ " --daemon\n" ++ " --debug\n" ++ " --children-max=\n" ++ " --exec-delay=\n" ++ " --event-timeout=\n" ++ " --resolve-names=early|late|never\n" ++ " --version\n" ++ " --help\n" ++ , program_invocation_short_name); ++} ++ + int main(int argc, char *argv[]) { + struct udev *udev; + sigset_t mask; +@@ -1074,16 +1088,7 @@ int main(int argc, char *argv[]) { + } + break; + case 'h': +- printf("Usage: udevd OPTIONS\n" +- " --daemon\n" +- " --debug\n" +- " --children-max=\n" +- " --exec-delay=\n" +- " --event-timeout=\n" +- " --resolve-names=early|late|never\n" +- " --version\n" +- " --help\n" +- "\n"); ++ help(); + goto exit; + case 'V': + printf("%s\n", VERSION); diff --git a/0251-udev-split-out-parse_argv.patch b/0251-udev-split-out-parse_argv.patch new file mode 100644 index 0000000..4188c24 --- /dev/null +++ b/0251-udev-split-out-parse_argv.patch @@ -0,0 +1,340 @@ +From bba7a48439e63defa20641b140522eac55fc1a1e Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 12 Sep 2014 14:42:59 +0200 +Subject: [PATCH] udev: split out parse_argv() + +Also rename some global variables to arg_* to make it clearer where they come from. +--- + src/udev/udevd.c | 175 ++++++++++++++++++++++++++++++------------------------- + 1 file changed, 95 insertions(+), 80 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index f0ecbf83ef..8cdcbd8fb0 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -54,8 +54,6 @@ + #include "dev-setup.h" + #include "fileio.h" + +-static bool debug; +- + void udev_main_log(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) { +@@ -72,10 +70,13 @@ static int fd_inotify = -1; + static bool stop_exec_queue; + static bool reload; + static int children; +-static int children_max; +-static int exec_delay; +-static usec_t event_timeout_usec = 180 * USEC_PER_SEC; +-static usec_t event_timeout_warn_usec = 180 * USEC_PER_SEC / 3; ++static bool arg_debug = false; ++static int arg_daemonize = false; ++static int arg_resolve_names = 1; ++static int arg_children_max; ++static int arg_exec_delay; ++static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC; ++static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3; + static sigset_t sigmask_orig; + static UDEV_LIST(event_list); + static UDEV_LIST(worker_list); +@@ -274,8 +275,8 @@ static void worker_new(struct event *event) { + /* needed for SIGCHLD/SIGTERM in spawn() */ + udev_event->fd_signal = fd_signal; + +- if (exec_delay > 0) +- udev_event->exec_delay = exec_delay; ++ if (arg_exec_delay > 0) ++ udev_event->exec_delay = arg_exec_delay; + + /* + * Take a shared lock on the device node; this establishes +@@ -309,9 +310,9 @@ static void worker_new(struct event *event) { + udev_event->rtnl = rtnl; + + /* apply rules, create node, symlinks */ +- udev_event_execute_rules(udev_event, event_timeout_usec, event_timeout_warn_usec, rules, &sigmask_orig); ++ udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_event_timeout_warn_usec, rules, &sigmask_orig); + +- udev_event_execute_run(udev_event, event_timeout_usec, event_timeout_warn_usec, &sigmask_orig); ++ udev_event_execute_run(udev_event, arg_event_timeout_usec, arg_event_timeout_warn_usec, &sigmask_orig); + + /* in case rtnl was initialized */ + rtnl = sd_rtnl_ref(udev_event->rtnl); +@@ -441,8 +442,8 @@ static void event_run(struct event *event) { + return; + } + +- if (children >= children_max) { +- if (children_max > 1) ++ if (children >= arg_children_max) { ++ if (arg_children_max > 1) + log_debug("maximum number (%i) of children reached", children); + return; + } +@@ -692,7 +693,7 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) { + i = udev_ctrl_get_set_children_max(ctrl_msg); + if (i >= 0) { + log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i); +- children_max = i; ++ arg_children_max = i; + } + + if (udev_ctrl_get_ping(ctrl_msg) > 0) +@@ -985,12 +986,12 @@ static void kernel_cmdline_options(struct udev *udev) { + log_set_max_level(prio); + udev_set_log_priority(udev, prio); + } else if (startswith(opt, "udev.children-max=")) { +- children_max = strtoul(opt + 18, NULL, 0); ++ arg_children_max = strtoul(opt + 18, NULL, 0); + } else if (startswith(opt, "udev.exec-delay=")) { +- exec_delay = strtoul(opt + 16, NULL, 0); ++ arg_exec_delay = strtoul(opt + 16, NULL, 0); + } else if (startswith(opt, "udev.event-timeout=")) { +- event_timeout_usec = strtoul(opt + 16, NULL, 0) * USEC_PER_SEC; +- event_timeout_warn_usec = (event_timeout_usec / 3) ? : 1; ++ arg_event_timeout_usec = strtoul(opt + 16, NULL, 0) * USEC_PER_SEC; ++ arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; + } + + free(s); +@@ -1011,95 +1012,109 @@ static void help(void) { + , program_invocation_short_name); + } + +-int main(int argc, char *argv[]) { +- struct udev *udev; +- sigset_t mask; +- int daemonize = false; +- int resolve_names = 1; ++static int parse_argv(int argc, char *argv[]) { + static const struct option options[] = { +- { "daemon", no_argument, NULL, 'd' }, +- { "debug", no_argument, NULL, 'D' }, +- { "children-max", required_argument, NULL, 'c' }, +- { "exec-delay", required_argument, NULL, 'e' }, +- { "event-timeout", required_argument, NULL, 't' }, +- { "resolve-names", required_argument, NULL, 'N' }, +- { "help", no_argument, NULL, 'h' }, +- { "version", no_argument, NULL, 'V' }, ++ { "daemon", no_argument, NULL, 'd' }, ++ { "debug", no_argument, NULL, 'D' }, ++ { "children-max", required_argument, NULL, 'c' }, ++ { "exec-delay", required_argument, NULL, 'e' }, ++ { "event-timeout", required_argument, NULL, 't' }, ++ { "resolve-names", required_argument, NULL, 'N' }, ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, 'V' }, + {} + }; +- int fd_ctrl = -1; +- int fd_netlink = -1; +- int fd_worker = -1; +- struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker; +- struct udev_ctrl_connection *ctrl_conn = NULL; +- int rc = 1; +- +- udev = udev_new(); +- if (udev == NULL) +- goto exit; +- +- log_set_target(LOG_TARGET_AUTO); +- log_parse_environment(); +- log_open(); + +- udev_set_log_fn(udev, udev_main_log); +- log_set_max_level(udev_get_log_priority(udev)); ++ int c; + +- log_debug("version %s", VERSION); +- label_init("/dev"); ++ assert(argc >= 0); ++ assert(argv); + +- for (;;) { +- int option; ++ while ((c = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL)) >= 0) { + +- option = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL); +- if (option == -1) +- break; ++ switch (c) { + +- switch (option) { + case 'd': +- daemonize = true; ++ arg_daemonize = true; + break; + case 'c': +- children_max = strtoul(optarg, NULL, 0); ++ arg_children_max = strtoul(optarg, NULL, 0); + break; + case 'e': +- exec_delay = strtoul(optarg, NULL, 0); ++ arg_exec_delay = strtoul(optarg, NULL, 0); + break; + case 't': +- event_timeout_usec = strtoul(optarg, NULL, 0) * USEC_PER_SEC; +- event_timeout_warn_usec = (event_timeout_usec / 3) ? : 1; ++ arg_event_timeout_usec = strtoul(optarg, NULL, 0) * USEC_PER_SEC; ++ arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; + break; + case 'D': +- debug = true; +- log_set_max_level(LOG_DEBUG); +- udev_set_log_priority(udev, LOG_DEBUG); ++ arg_debug = true; + break; + case 'N': + if (streq(optarg, "early")) { +- resolve_names = 1; ++ arg_resolve_names = 1; + } else if (streq(optarg, "late")) { +- resolve_names = 0; ++ arg_resolve_names = 0; + } else if (streq(optarg, "never")) { +- resolve_names = -1; ++ arg_resolve_names = -1; + } else { + fprintf(stderr, "resolve-names must be early, late or never\n"); + log_error("resolve-names must be early, late or never"); +- goto exit; ++ return 0; + } + break; + case 'h': + help(); +- goto exit; ++ return 0; + case 'V': + printf("%s\n", VERSION); +- goto exit; ++ return 0; ++ case '?': ++ return -EINVAL; + default: +- goto exit; ++ assert_not_reached("Unhandled option"); ++ + } + } + ++ return 1; ++} ++ ++int main(int argc, char *argv[]) { ++ struct udev *udev; ++ sigset_t mask; ++ int fd_ctrl = -1; ++ int fd_netlink = -1; ++ int fd_worker = -1; ++ struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker; ++ struct udev_ctrl_connection *ctrl_conn = NULL; ++ int rc = 1, r; ++ ++ udev = udev_new(); ++ if (udev == NULL) ++ goto exit; ++ ++ log_set_target(LOG_TARGET_AUTO); ++ log_parse_environment(); ++ log_open(); ++ ++ udev_set_log_fn(udev, udev_main_log); ++ log_set_max_level(udev_get_log_priority(udev)); ++ ++ log_debug("version %s", VERSION); ++ label_init("/dev"); ++ ++ r = parse_argv(argc, argv); ++ if (r <= 0) ++ goto exit; ++ + kernel_cmdline_options(udev); + ++ if (arg_debug) { ++ log_set_max_level(LOG_DEBUG); ++ udev_set_log_priority(udev, LOG_DEBUG); ++ } ++ + if (getuid() != 0) { + fprintf(stderr, "root privileges required\n"); + log_error("root privileges required"); +@@ -1115,7 +1130,7 @@ int main(int argc, char *argv[]) { + dev_setup(NULL); + + /* before opening new files, make sure std{in,out,err} fds are in a sane state */ +- if (daemonize) { ++ if (arg_daemonize) { + int fd; + + fd = open("/dev/null", O_RDWR); +@@ -1188,7 +1203,7 @@ int main(int argc, char *argv[]) { + + udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024); + +- if (daemonize) { ++ if (arg_daemonize) { + pid_t pid; + + pid = fork(); +@@ -1213,7 +1228,7 @@ int main(int argc, char *argv[]) { + + log_info("starting version " VERSION "\n"); + +- if (!debug) { ++ if (!arg_debug) { + int fd; + + fd = open("/dev/null", O_RDWR); +@@ -1256,7 +1271,7 @@ int main(int argc, char *argv[]) { + + udev_builtin_init(udev); + +- rules = udev_rules_new(udev, resolve_names); ++ rules = udev_rules_new(udev, arg_resolve_names); + if (rules == NULL) { + log_error("error reading rules"); + goto exit; +@@ -1296,16 +1311,16 @@ int main(int argc, char *argv[]) { + goto exit; + } + +- if (children_max <= 0) { ++ if (arg_children_max <= 0) { + cpu_set_t cpu_set; + +- children_max = 8; ++ arg_children_max = 8; + + if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) { +- children_max += CPU_COUNT(&cpu_set) * 2; ++ arg_children_max += CPU_COUNT(&cpu_set) * 2; + } + } +- log_debug("set children_max to %u", children_max); ++ log_debug("set children_max to %u", arg_children_max); + + rc = udev_rules_apply_static_dev_perms(rules); + if (rc < 0) +@@ -1401,8 +1416,8 @@ int main(int argc, char *argv[]) { + + ts = now(CLOCK_MONOTONIC); + +- if ((ts - worker->event_start_usec) > event_timeout_warn_usec) { +- if ((ts - worker->event_start_usec) > event_timeout_usec) { ++ if ((ts - worker->event_start_usec) > arg_event_timeout_warn_usec) { ++ if ((ts - worker->event_start_usec) > arg_event_timeout_usec) { + log_error("worker [%u] %s timeout; kill it", worker->pid, worker->event->devpath); + kill(worker->pid, SIGKILL); + worker->state = WORKER_KILLED; +@@ -1473,7 +1488,7 @@ int main(int argc, char *argv[]) { + if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) { + udev_builtin_init(udev); + if (rules == NULL) +- rules = udev_rules_new(udev, resolve_names); ++ rules = udev_rules_new(udev, arg_resolve_names); + if (rules != NULL) + event_queue_start(udev); + } diff --git a/0252-udev-drop-duplicate-logging.patch b/0252-udev-drop-duplicate-logging.patch new file mode 100644 index 0000000..e876d31 --- /dev/null +++ b/0252-udev-drop-duplicate-logging.patch @@ -0,0 +1,94 @@ +From 959d654105c1303d0c475868a51834db2f7b6099 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 12 Sep 2014 16:17:00 +0200 +Subject: [PATCH] udev: drop duplicate logging + +Once upon a time logging during early boot was unreliable, so extra logging messages were +sent by udev to stderr. That is no longer a concern, so drop all fprintf() calls from udved. +--- + src/udev/udevd.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 8cdcbd8fb0..8922ff9f8e 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1058,7 +1058,6 @@ static int parse_argv(int argc, char *argv[]) { + } else if (streq(optarg, "never")) { + arg_resolve_names = -1; + } else { +- fprintf(stderr, "resolve-names must be early, late or never\n"); + log_error("resolve-names must be early, late or never"); + return 0; + } +@@ -1116,7 +1115,6 @@ int main(int argc, char *argv[]) { + } + + if (getuid() != 0) { +- fprintf(stderr, "root privileges required\n"); + log_error("root privileges required"); + goto exit; + } +@@ -1142,7 +1140,6 @@ int main(int argc, char *argv[]) { + if (fd > STDERR_FILENO) + close(fd); + } else { +- fprintf(stderr, "cannot open /dev/null\n"); + log_error("cannot open /dev/null"); + } + } +@@ -1170,7 +1167,6 @@ int main(int argc, char *argv[]) { + /* open control and netlink socket */ + udev_ctrl = udev_ctrl_new(udev); + if (udev_ctrl == NULL) { +- fprintf(stderr, "error initializing udev control socket"); + log_error("error initializing udev control socket"); + rc = 1; + goto exit; +@@ -1179,7 +1175,6 @@ int main(int argc, char *argv[]) { + + monitor = udev_monitor_new_from_netlink(udev, "kernel"); + if (monitor == NULL) { +- fprintf(stderr, "error initializing netlink socket\n"); + log_error("error initializing netlink socket"); + rc = 3; + goto exit; +@@ -1188,14 +1183,12 @@ int main(int argc, char *argv[]) { + } + + if (udev_monitor_enable_receiving(monitor) < 0) { +- fprintf(stderr, "error binding netlink socket\n"); + log_error("error binding netlink socket"); + rc = 3; + goto exit; + } + + if (udev_ctrl_enable_receiving(udev_ctrl) < 0) { +- fprintf(stderr, "error binding udev control socket\n"); + log_error("error binding udev control socket"); + rc = 1; + goto exit; +@@ -1242,7 +1235,6 @@ int main(int argc, char *argv[]) { + + fd_inotify = udev_watch_init(udev); + if (fd_inotify < 0) { +- fprintf(stderr, "error initializing inotify\n"); + log_error("error initializing inotify"); + rc = 4; + goto exit; +@@ -1254,7 +1246,6 @@ int main(int argc, char *argv[]) { + sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); + fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (fd_signal < 0) { +- fprintf(stderr, "error creating signalfd\n"); + log_error("error creating signalfd"); + rc = 5; + goto exit; +@@ -1262,7 +1253,6 @@ int main(int argc, char *argv[]) { + + /* unnamed socket from workers to the main daemon */ + if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) { +- fprintf(stderr, "error creating socketpair\n"); + log_error("error creating socketpair"); + rc = 6; + goto exit; diff --git a/0253-udev-don-t-close-std-in-out-err.patch b/0253-udev-don-t-close-std-in-out-err.patch new file mode 100644 index 0000000..0cc0f73 --- /dev/null +++ b/0253-udev-don-t-close-std-in-out-err.patch @@ -0,0 +1,34 @@ +From 5c67cf2774a8b964f4d7cd92a4c447da81ac6087 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 12 Sep 2014 16:22:44 +0200 +Subject: [PATCH] udev: don't close std{in,out,err} + +Rather than printing debug output to stderr and redirecting this to /dev/null when not wanted, +use the correct log_*() function in the first place. +--- + src/udev/udevd.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 8922ff9f8e..e90d9dacb0 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1221,18 +1221,6 @@ int main(int argc, char *argv[]) { + + log_info("starting version " VERSION "\n"); + +- if (!arg_debug) { +- int fd; +- +- fd = open("/dev/null", O_RDWR); +- if (fd >= 0) { +- dup2(fd, STDIN_FILENO); +- dup2(fd, STDOUT_FILENO); +- dup2(fd, STDERR_FILENO); +- close(fd); +- } +- } +- + fd_inotify = udev_watch_init(udev); + if (fd_inotify < 0) { + log_error("error initializing inotify"); diff --git a/0254-udevd-initialize-epoll_event-structs-on-allocation.patch b/0254-udevd-initialize-epoll_event-structs-on-allocation.patch new file mode 100644 index 0000000..b5f23a8 --- /dev/null +++ b/0254-udevd-initialize-epoll_event-structs-on-allocation.patch @@ -0,0 +1,118 @@ +From 3f56f784b98a4b0ad45409a9a19fd787cd7ae455 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 12 Sep 2014 16:45:19 +0200 +Subject: [PATCH] udevd: initialize epoll_event structs on allocation + +Also move the rest of event initialization next to the event loop (no functional change). +--- + src/udev/udevd.c | 72 ++++++++++++++++++++++++-------------------------------- + 1 file changed, 31 insertions(+), 41 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index e90d9dacb0..04014b468a 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1085,7 +1085,11 @@ int main(int argc, char *argv[]) { + int fd_ctrl = -1; + int fd_netlink = -1; + int fd_worker = -1; +- struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker; ++ struct epoll_event ep_ctrl = { .events = EPOLLIN }; ++ struct epoll_event ep_inotify = { .events = EPOLLIN }; ++ struct epoll_event ep_signal = { .events = EPOLLIN }; ++ struct epoll_event ep_netlink = { .events = EPOLLIN }; ++ struct epoll_event ep_worker = { .events = EPOLLIN }; + struct udev_ctrl_connection *ctrl_conn = NULL; + int rc = 1, r; + +@@ -1221,6 +1225,32 @@ int main(int argc, char *argv[]) { + + log_info("starting version " VERSION "\n"); + ++ udev_builtin_init(udev); ++ ++ rules = udev_rules_new(udev, arg_resolve_names); ++ if (rules == NULL) { ++ log_error("error reading rules"); ++ goto exit; ++ } ++ ++ rc = udev_rules_apply_static_dev_perms(rules); ++ if (rc < 0) ++ log_error("failed to apply permissions on static device nodes - %s", strerror(-rc)); ++ ++ if (arg_children_max <= 0) { ++ cpu_set_t cpu_set; ++ ++ arg_children_max = 8; ++ ++ if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) { ++ arg_children_max += CPU_COUNT(&cpu_set) * 2; ++ } ++ } ++ log_debug("set children_max to %u", arg_children_max); ++ ++ udev_list_node_init(&event_list); ++ udev_list_node_init(&worker_list); ++ + fd_inotify = udev_watch_init(udev); + if (fd_inotify < 0) { + log_error("error initializing inotify"); +@@ -1247,32 +1277,10 @@ int main(int argc, char *argv[]) { + } + fd_worker = worker_watch[READ_END]; + +- udev_builtin_init(udev); +- +- rules = udev_rules_new(udev, arg_resolve_names); +- if (rules == NULL) { +- log_error("error reading rules"); +- goto exit; +- } +- +- memzero(&ep_ctrl, sizeof(struct epoll_event)); +- ep_ctrl.events = EPOLLIN; + ep_ctrl.data.fd = fd_ctrl; +- +- memzero(&ep_inotify, sizeof(struct epoll_event)); +- ep_inotify.events = EPOLLIN; + ep_inotify.data.fd = fd_inotify; +- +- memzero(&ep_signal, sizeof(struct epoll_event)); +- ep_signal.events = EPOLLIN; + ep_signal.data.fd = fd_signal; +- +- memzero(&ep_netlink, sizeof(struct epoll_event)); +- ep_netlink.events = EPOLLIN; + ep_netlink.data.fd = fd_netlink; +- +- memzero(&ep_worker, sizeof(struct epoll_event)); +- ep_worker.events = EPOLLIN; + ep_worker.data.fd = fd_worker; + + fd_ep = epoll_create1(EPOLL_CLOEXEC); +@@ -1289,24 +1297,6 @@ int main(int argc, char *argv[]) { + goto exit; + } + +- if (arg_children_max <= 0) { +- cpu_set_t cpu_set; +- +- arg_children_max = 8; +- +- if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) { +- arg_children_max += CPU_COUNT(&cpu_set) * 2; +- } +- } +- log_debug("set children_max to %u", arg_children_max); +- +- rc = udev_rules_apply_static_dev_perms(rules); +- if (rc < 0) +- log_error("failed to apply permissions on static device nodes - %s", strerror(-rc)); +- +- udev_list_node_init(&event_list); +- udev_list_node_init(&worker_list); +- + for (;;) { + static usec_t last_usec; + struct epoll_event ev[8]; diff --git a/0255-udev-only-print-after-final-log-level-has-been-deter.patch b/0255-udev-only-print-after-final-log-level-has-been-deter.patch new file mode 100644 index 0000000..f3cff17 --- /dev/null +++ b/0255-udev-only-print-after-final-log-level-has-been-deter.patch @@ -0,0 +1,34 @@ +From ebc164ef40cfa0fa01ce77a6a966129cc611d4ff Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 15 Sep 2014 11:53:03 +0200 +Subject: [PATCH] udev: only print after final log level has been determined + +This delays label_init(), and drops the (duplicate) printing of version +information. +--- + src/udev/udevd.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 04014b468a..cfa071eba9 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1104,9 +1104,6 @@ int main(int argc, char *argv[]) { + udev_set_log_fn(udev, udev_main_log); + log_set_max_level(udev_get_log_priority(udev)); + +- log_debug("version %s", VERSION); +- label_init("/dev"); +- + r = parse_argv(argc, argv); + if (r <= 0) + goto exit; +@@ -1123,6 +1120,8 @@ int main(int argc, char *argv[]) { + goto exit; + } + ++ label_init("/dev"); ++ + /* set umask before creating any file/directory */ + chdir("/"); + umask(022); diff --git a/0256-udev-apply-permissions-to-static-nodes-before-signal.patch b/0256-udev-apply-permissions-to-static-nodes-before-signal.patch new file mode 100644 index 0000000..c9256d8 --- /dev/null +++ b/0256-udev-apply-permissions-to-static-nodes-before-signal.patch @@ -0,0 +1,58 @@ +From 4d6dac13ad376cb537647741c45185395beb3e9c Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 15 Sep 2014 12:04:29 +0200 +Subject: [PATCH] udev: apply permissions to static nodes before signallying + READY + +Processes expecting static nodes to have the right permissions may order themselves after systemd-udevd.service, +make sure that actually guarantees what is expected. +--- + src/udev/udevd.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index cfa071eba9..e8b3602986 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1199,6 +1199,20 @@ int main(int argc, char *argv[]) { + + udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024); + ++ log_info("starting version " VERSION "\n"); ++ ++ udev_builtin_init(udev); ++ ++ rules = udev_rules_new(udev, arg_resolve_names); ++ if (rules == NULL) { ++ log_error("error reading rules"); ++ goto exit; ++ } ++ ++ rc = udev_rules_apply_static_dev_perms(rules); ++ if (rc < 0) ++ log_error("failed to apply permissions on static device nodes - %s", strerror(-rc)); ++ + if (arg_daemonize) { + pid_t pid; + +@@ -1222,20 +1236,6 @@ int main(int argc, char *argv[]) { + sd_notify(1, "READY=1"); + } + +- log_info("starting version " VERSION "\n"); +- +- udev_builtin_init(udev); +- +- rules = udev_rules_new(udev, arg_resolve_names); +- if (rules == NULL) { +- log_error("error reading rules"); +- goto exit; +- } +- +- rc = udev_rules_apply_static_dev_perms(rules); +- if (rc < 0) +- log_error("failed to apply permissions on static device nodes - %s", strerror(-rc)); +- + if (arg_children_max <= 0) { + cpu_set_t cpu_set; + diff --git a/0257-libudev-drop-util_lookup_-user-group.patch b/0257-libudev-drop-util_lookup_-user-group.patch new file mode 100644 index 0000000..2a978c4 --- /dev/null +++ b/0257-libudev-drop-util_lookup_-user-group.patch @@ -0,0 +1,209 @@ +From 23bf8dd7d5ce1e2a52f28d5d242109ddb668b3fb Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 9 Sep 2014 23:12:14 +0200 +Subject: [PATCH] libudev: drop util_lookup_{user,group} + +Use shared versions instead. Difference is with overwriting of repeated user/group +name, and lack of logging. +--- + src/libudev/libudev-private.h | 2 -- + src/libudev/libudev-util.c | 64 ------------------------------------------- + src/udev/udev-rules.c | 46 +++++++++++++++++++++++++++---- + 3 files changed, 40 insertions(+), 72 deletions(-) + +diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h +index 35ea7ba44c..1c060d95a3 100644 +--- a/src/libudev/libudev-private.h ++++ b/src/libudev/libudev-private.h +@@ -168,8 +168,6 @@ uint64_t util_string_bloom64(const char *str); + + /* libudev-util-private.c */ + int util_delete_path(struct udev *udev, const char *path); +-uid_t util_lookup_user(struct udev *udev, const char *user); +-gid_t util_lookup_group(struct udev *udev, const char *group); + int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); + + #endif +diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c +index 9e19e31407..3bc9c67f3b 100644 +--- a/src/libudev/libudev-util.c ++++ b/src/libudev/libudev-util.c +@@ -77,70 +77,6 @@ int util_delete_path(struct udev *udev, const char *path) + return err; + } + +-uid_t util_lookup_user(struct udev *udev, const char *user) +-{ +- char *endptr; +- struct passwd pwbuf; +- struct passwd *pw; +- uid_t uid; +- size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); +- char *buf = alloca(buflen); +- +- if (streq(user, "root")) +- return 0; +- uid = strtoul(user, &endptr, 10); +- if (endptr[0] == '\0') +- return uid; +- +- errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw); +- if (pw != NULL) +- return pw->pw_uid; +- if (errno == 0 || errno == ENOENT || errno == ESRCH) +- udev_err(udev, "specified user '%s' unknown\n", user); +- else +- udev_err(udev, "error resolving user '%s': %m\n", user); +- return 0; +-} +- +-gid_t util_lookup_group(struct udev *udev, const char *group) +-{ +- char *endptr; +- struct group grbuf; +- struct group *gr; +- gid_t gid = 0; +- size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); +- char *buf = NULL; +- +- if (streq(group, "root")) +- return 0; +- gid = strtoul(group, &endptr, 10); +- if (endptr[0] == '\0') +- return gid; +- gid = 0; +- for (;;) { +- char *newbuf; +- +- newbuf = realloc(buf, buflen); +- if (!newbuf) +- break; +- buf = newbuf; +- errno = getgrnam_r(group, &grbuf, buf, buflen, &gr); +- if (gr != NULL) { +- gid = gr->gr_gid; +- } else if (errno == ERANGE) { +- buflen *= 2; +- continue; +- } else if (errno == 0 || errno == ENOENT || errno == ESRCH) { +- udev_err(udev, "specified group '%s' unknown\n", group); +- } else { +- udev_err(udev, "error resolving group '%s': %m\n", group); +- } +- break; +- } +- free(buf); +- return gid; +-} +- + /* handle "[/]" format */ + int util_resolve_subsys_kernel(struct udev *udev, const char *string, + char *result, size_t maxsize, int read_value) +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index db95442fda..ce4d173ee9 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -459,8 +459,9 @@ static int add_token(struct udev_rules *rules, struct token *token) { + + static uid_t add_uid(struct udev_rules *rules, const char *owner) { + unsigned int i; +- uid_t uid; ++ uid_t uid = 0; + unsigned int off; ++ int r; + + /* lookup, if we know it already */ + for (i = 0; i < rules->uids_cur; i++) { +@@ -470,7 +471,13 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) { + return uid; + } + } +- uid = util_lookup_user(rules->udev, owner); ++ r = get_user_creds(&owner, &uid, NULL, NULL, NULL); ++ if (r < 0) { ++ if (r == -ENOENT || r == -ESRCH) ++ udev_err(rules->udev, "specified user '%s' unknown\n", owner); ++ else ++ udev_err(rules->udev, "error resolving user '%s': %s\n", owner, strerror(-r)); ++ } + + /* grow buffer if needed */ + if (rules->uids_cur+1 >= rules->uids_max) { +@@ -499,8 +506,9 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) { + + static gid_t add_gid(struct udev_rules *rules, const char *group) { + unsigned int i; +- gid_t gid; ++ gid_t gid = 0; + unsigned int off; ++ int r; + + /* lookup, if we know it already */ + for (i = 0; i < rules->gids_cur; i++) { +@@ -510,7 +518,13 @@ static gid_t add_gid(struct udev_rules *rules, const char *group) { + return gid; + } + } +- gid = util_lookup_group(rules->udev, group); ++ r = get_group_creds(&group, &gid); ++ if (r < 0) { ++ if (r == -ENOENT || r == -ESRCH) ++ udev_err(rules->udev, "specified group '%s' unknown\n", group); ++ else ++ udev_err(rules->udev, "error resolving group '%s': %s\n", group, strerror(-r)); ++ } + + /* grow buffer if needed */ + if (rules->gids_cur+1 >= rules->gids_max) { +@@ -2241,6 +2255,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules, + break; + case TK_A_OWNER: { + char owner[UTIL_NAME_SIZE]; ++ const char *ow = owner; ++ int r; + + if (event->owner_final) + break; +@@ -2248,7 +2264,15 @@ int udev_rules_apply_to_event(struct udev_rules *rules, + event->owner_final = true; + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner)); + event->owner_set = true; +- event->uid = util_lookup_user(event->udev, owner); ++ r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL); ++ if (r < 0) { ++ if (r == -ENOENT || r == -ESRCH) ++ udev_err(event->udev, "specified user '%s' unknown\n", owner); ++ else ++ udev_err(event->udev, "error resolving user '%s': %s\n", owner, strerror(-r)); ++ ++ event->uid = 0; ++ } + log_debug("OWNER %u %s:%u", + event->uid, + rules_str(rules, rule->rule.filename_off), +@@ -2257,6 +2281,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules, + } + case TK_A_GROUP: { + char group[UTIL_NAME_SIZE]; ++ const char *gr = group; ++ int r; + + if (event->group_final) + break; +@@ -2264,7 +2290,15 @@ int udev_rules_apply_to_event(struct udev_rules *rules, + event->group_final = true; + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group)); + event->group_set = true; +- event->gid = util_lookup_group(event->udev, group); ++ r = get_group_creds(&gr, &event->gid); ++ if (r < 0) { ++ if (r == -ENOENT || r == -ESRCH) ++ udev_err(event->udev, "specified group '%s' unknown\n", group); ++ else ++ udev_err(event->udev, "error resolving group '%s': %s\n", group, strerror(-r)); ++ ++ event->gid = 0; ++ } + log_debug("GROUP %u %s:%u", + event->gid, + rules_str(rules, rule->rule.filename_off), diff --git a/0258-libudev-util-drop-util_delete_path.patch b/0258-libudev-util-drop-util_delete_path.patch new file mode 100644 index 0000000..1f19bef --- /dev/null +++ b/0258-libudev-util-drop-util_delete_path.patch @@ -0,0 +1,102 @@ +From 37d522746b67fda0d52111364d81358ce560bcf7 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 15 Sep 2014 14:20:32 +0200 +Subject: [PATCH] libudev: util - drop util_delete_path() + +Use rmdir_parents() from src/shared instead. +--- + src/libudev/libudev-private.h | 1 - + src/libudev/libudev-util.c | 32 -------------------------------- + src/test/test-udev.c | 2 +- + src/udev/udev-node.c | 3 +-- + 4 files changed, 2 insertions(+), 36 deletions(-) + +diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h +index 1c060d95a3..2f74bc0883 100644 +--- a/src/libudev/libudev-private.h ++++ b/src/libudev/libudev-private.h +@@ -167,7 +167,6 @@ unsigned int util_string_hash32(const char *key); + uint64_t util_string_bloom64(const char *str); + + /* libudev-util-private.c */ +-int util_delete_path(struct udev *udev, const char *path); + int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); + + #endif +diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c +index 3bc9c67f3b..a7125fa63f 100644 +--- a/src/libudev/libudev-util.c ++++ b/src/libudev/libudev-util.c +@@ -45,38 +45,6 @@ + * Utilities useful when dealing with devices and device node names. + */ + +-int util_delete_path(struct udev *udev, const char *path) +-{ +- char p[UTIL_PATH_SIZE]; +- char *pos; +- int err = 0; +- +- if (path[0] == '/') +- while(path[1] == '/') +- path++; +- strscpy(p, sizeof(p), path); +- pos = strrchr(p, '/'); +- if (pos == p || pos == NULL) +- return 0; +- +- for (;;) { +- *pos = '\0'; +- pos = strrchr(p, '/'); +- +- /* don't remove the last one */ +- if ((pos == p) || (pos == NULL)) +- break; +- +- err = rmdir(p); +- if (err < 0) { +- if (errno == ENOENT) +- err = 0; +- break; +- } +- } +- return err; +-} +- + /* handle "[/]" format */ + int util_resolve_subsys_kernel(struct udev *udev, const char *string, + char *result, size_t maxsize, int read_value) +diff --git a/src/test/test-udev.c b/src/test/test-udev.c +index f085262b01..f368c3f333 100644 +--- a/src/test/test-udev.c ++++ b/src/test/test-udev.c +@@ -149,7 +149,7 @@ int main(int argc, char *argv[]) { + mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev)); + } else { + unlink(udev_device_get_devnode(dev)); +- util_delete_path(udev, udev_device_get_devnode(dev)); ++ rmdir_parents(udev_device_get_devnode(dev), "/"); + } + } + +diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c +index d42af9a6d2..c164603795 100644 +--- a/src/udev/udev-node.c ++++ b/src/udev/udev-node.c +@@ -179,7 +179,6 @@ static const char *link_find_prioritized(struct udev_device *dev, bool add, cons + + /* manage "stack of names" with possibly specified device priorities */ + static void link_update(struct udev_device *dev, const char *slink, bool add) { +- struct udev *udev = udev_device_get_udev(dev); + char name_enc[UTIL_PATH_SIZE]; + char filename[UTIL_PATH_SIZE * 2]; + char dirname[UTIL_PATH_SIZE]; +@@ -197,7 +196,7 @@ static void link_update(struct udev_device *dev, const char *slink, bool add) { + if (target == NULL) { + log_debug("no reference left, remove '%s'", slink); + if (unlink(slink) == 0) +- util_delete_path(udev, slink); ++ rmdir_parents(slink, "/"); + } else { + log_debug("creating link '%s' to '%s'", slink, target); + node_symlink(dev, target, slink); diff --git a/0259-udev-util-use-log_level_from_string.patch b/0259-udev-util-use-log_level_from_string.patch new file mode 100644 index 0000000..02ed90a --- /dev/null +++ b/0259-udev-util-use-log_level_from_string.patch @@ -0,0 +1,29 @@ +From ba7408a6e9fa2f79f7e69052de78f82e12c613f6 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 15 Sep 2014 14:21:00 +0200 +Subject: [PATCH] udev: util - use log_level_from_string() + +--- + src/libudev/libudev-util.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c +index a7125fa63f..f3fdf3b5aa 100644 +--- a/src/libudev/libudev-util.c ++++ b/src/libudev/libudev-util.c +@@ -162,13 +162,8 @@ int util_log_priority(const char *priority) + prio = strtol(priority, &endptr, 10); + if (endptr[0] == '\0' || isspace(endptr[0])) + return prio; +- if (startswith(priority, "err")) +- return LOG_ERR; +- if (startswith(priority, "info")) +- return LOG_INFO; +- if (startswith(priority, "debug")) +- return LOG_DEBUG; +- return 0; ++ ++ return log_level_from_string(priority); + } + + size_t util_path_encode(const char *src, char *dest, size_t size) diff --git a/0260-udevd-use-safe_ato-in-place-of-strto.patch b/0260-udevd-use-safe_ato-in-place-of-strto.patch new file mode 100644 index 0000000..38c86f3 --- /dev/null +++ b/0260-udevd-use-safe_ato-in-place-of-strto.patch @@ -0,0 +1,65 @@ +From f1e8664e4a86f9b9b8d8a001d886d69f1ac42e9b Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 15 Sep 2014 14:41:30 +0200 +Subject: [PATCH] udevd: use safe_ato*() in place of strto*() + +--- + src/udev/udevd.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index e8b3602986..cd517931d3 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -986,11 +986,20 @@ static void kernel_cmdline_options(struct udev *udev) { + log_set_max_level(prio); + udev_set_log_priority(udev, prio); + } else if (startswith(opt, "udev.children-max=")) { +- arg_children_max = strtoul(opt + 18, NULL, 0); ++ r = safe_atoi(opt + 18, &arg_children_max); ++ if (r < 0) ++ log_warning("Invalid udev.children-max ignored: %s", opt + 18); + } else if (startswith(opt, "udev.exec-delay=")) { +- arg_exec_delay = strtoul(opt + 16, NULL, 0); ++ r = safe_atoi(opt + 16, &arg_exec_delay); ++ if (r < 0) ++ log_warning("Invalid udev.exec-delay ignored: %s", opt + 16); + } else if (startswith(opt, "udev.event-timeout=")) { +- arg_event_timeout_usec = strtoul(opt + 16, NULL, 0) * USEC_PER_SEC; ++ r = safe_atou64(opt + 16, &arg_event_timeout_usec); ++ if (r < 0) { ++ log_warning("Invalid udev.event-timeout ignored: %s", opt + 16); ++ break; ++ } ++ arg_event_timeout_usec *= USEC_PER_SEC; + arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; + } + +@@ -1031,6 +1040,7 @@ static int parse_argv(int argc, char *argv[]) { + assert(argv); + + while ((c = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL)) >= 0) { ++ int r; + + switch (c) { + +@@ -1038,13 +1048,16 @@ static int parse_argv(int argc, char *argv[]) { + arg_daemonize = true; + break; + case 'c': +- arg_children_max = strtoul(optarg, NULL, 0); ++ safe_atoi(optarg, &arg_children_max); + break; + case 'e': +- arg_exec_delay = strtoul(optarg, NULL, 0); ++ safe_atoi(optarg, &arg_exec_delay); + break; + case 't': +- arg_event_timeout_usec = strtoul(optarg, NULL, 0) * USEC_PER_SEC; ++ r = safe_atou64(optarg, &arg_event_timeout_usec); ++ if (r < 0) ++ break; ++ arg_event_timeout_usec *= USEC_PER_SEC; + arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; + break; + case 'D': diff --git a/0261-udev-rules-add-missing-whitespace-to-log-message.patch b/0261-udev-rules-add-missing-whitespace-to-log-message.patch new file mode 100644 index 0000000..7c6eb68 --- /dev/null +++ b/0261-udev-rules-add-missing-whitespace-to-log-message.patch @@ -0,0 +1,23 @@ +From 85639427b3a3014adf934ee94c86d91f3aaf4cfb Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 15 Sep 2014 16:36:07 +0200 +Subject: [PATCH] udev: rules - add missing whitespace to log message + +--- + src/udev/udev-rules.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index ce4d173ee9..2a691f6ab7 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -1072,8 +1072,7 @@ static int add_rule(struct udev_rules *rules, char *line, + _cleanup_free_ char *tmp; + + tmp = cescape(buf); +- log_error("invalid key/value pair in file %s on line %u," +- "starting at character %tu ('%s')\n", ++ log_error("invalid key/value pair in file %s on line %u, starting at character %tu ('%s')\n", + filename, lineno, linepos - line + 1, tmp); + if (linepos[1] == '#') + log_error("hint: comments can only start at beginning of line"); diff --git a/0262-gpt-auto-generator-fix-typo.patch b/0262-gpt-auto-generator-fix-typo.patch new file mode 100644 index 0000000..5e84460 --- /dev/null +++ b/0262-gpt-auto-generator-fix-typo.patch @@ -0,0 +1,22 @@ +From 821b2e792159e237a1e5a1ea4bb6ae2e55d64be5 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 16 Sep 2014 13:50:11 +0200 +Subject: [PATCH] gpt-auto-generator: fix typo + +--- + 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 7dcbbfe497..25d868aa87 100644 +--- a/src/gpt-auto-generator/gpt-auto-generator.c ++++ b/src/gpt-auto-generator/gpt-auto-generator.c +@@ -124,7 +124,7 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi + return log_oom(); + + p = strjoin(arg_dest, "/", n, NULL); +- if (!n) ++ if (!p) + return log_oom(); + + f = fopen(p, "wxe"); diff --git a/0263-libsystemd-network-avoid-double-free-in-error-case.patch b/0263-libsystemd-network-avoid-double-free-in-error-case.patch new file mode 100644 index 0000000..3d57ab9 --- /dev/null +++ b/0263-libsystemd-network-avoid-double-free-in-error-case.patch @@ -0,0 +1,26 @@ +From 2833796106420e4634543d06052482f75cbb5762 Mon Sep 17 00:00:00 2001 +From: Andreas Henriksson +Date: Tue, 16 Sep 2014 15:50:58 +0200 +Subject: [PATCH] libsystemd-network: avoid double-free in error case + +Don't manually free 'n' in error path as it's already tagged +_cleanup_free_ and will be freed once it goes out of scope, +leading to double-free in this case. + +Found with coverity. Fixes: CID#1237786 +--- + src/libsystemd-network/network-internal.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c +index 208c314695..372f3ed371 100644 +--- a/src/libsystemd-network/network-internal.c ++++ b/src/libsystemd-network/network-internal.c +@@ -199,7 +199,6 @@ int config_parse_ifname(const char *unit, + if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); +- free(n); + return 0; + } + diff --git a/0264-hostname-add-missing-EMITS_CHANGE-annotation.patch b/0264-hostname-add-missing-EMITS_CHANGE-annotation.patch new file mode 100644 index 0000000..617127a --- /dev/null +++ b/0264-hostname-add-missing-EMITS_CHANGE-annotation.patch @@ -0,0 +1,24 @@ +From caffbef636ec48958dcb22e4b4140a9889a6a769 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 16 Sep 2014 17:33:20 +0200 +Subject: [PATCH] hostname: add missing EMITS_CHANGE annotation + +We call into sd-bus to send PropertiesChanged notifications for +"Hostname", but forgot to add the annotation to the bus-vtable. Fix that! +--- + src/hostname/hostnamed.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c +index d31fef7abe..b6b5d524c5 100644 +--- a/src/hostname/hostnamed.c ++++ b/src/hostname/hostnamed.c +@@ -613,7 +613,7 @@ static int method_set_location(sd_bus *bus, sd_bus_message *m, void *userdata, s + + static const sd_bus_vtable hostname_vtable[] = { + SD_BUS_VTABLE_START(0), +- SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, 0), ++ SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), diff --git a/0265-bootchart-use-safe_atod-rather-than-strtod.patch b/0265-bootchart-use-safe_atod-rather-than-strtod.patch new file mode 100644 index 0000000..46498ff --- /dev/null +++ b/0265-bootchart-use-safe_atod-rather-than-strtod.patch @@ -0,0 +1,34 @@ +From e10f3c431a3bc1a94fbe9d2a14d3025550f9672e Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 16 Sep 2014 18:42:22 +0200 +Subject: [PATCH] bootchart: use safe_atod() rather than strtod() + +--- + src/bootchart/store.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/bootchart/store.c b/src/bootchart/store.c +index 2d2ea428fa..ed46a503c6 100644 +--- a/src/bootchart/store.c ++++ b/src/bootchart/store.c +@@ -251,6 +251,7 @@ schedstat_next: + _cleanup_fclose_ FILE *st = NULL; + char t[32]; + struct ps_struct *parent; ++ int r; + + ps->next_ps = new0(struct ps_struct, 1); + if (!ps->next_ps) { +@@ -310,7 +311,11 @@ schedstat_next: + if (!sscanf(m, "%*s %*s %s", t)) + continue; + +- ps->starttime = strtod(t, NULL) / 1000.0; ++ r = safe_atod(t, &ps->starttime); ++ if (r < 0) ++ continue; ++ ++ ps->starttime /= 1000.0; + + if (arg_show_cgroup) + /* if this fails, that's OK */ diff --git a/0266-bootchart-oom-check-correct-variable.patch b/0266-bootchart-oom-check-correct-variable.patch new file mode 100644 index 0000000..cc990a5 --- /dev/null +++ b/0266-bootchart-oom-check-correct-variable.patch @@ -0,0 +1,28 @@ +From d498a616075ebfd8025d66c4c4f725d24eb3aca3 Mon Sep 17 00:00:00 2001 +From: Andreas Henriksson +Date: Tue, 16 Sep 2014 19:40:25 +0200 +Subject: [PATCH] bootchart: oom-check correct variable + +Coverity warned that we have already dereferenced ps->sample before +null-checking it. I suspect that's not really the issue and that +the check is checking the wrong variable. +Likely the oom-check should be on the just allocated ps->sample->next. + +Found by coverity. Fixes: CID#1237765 +--- + src/bootchart/store.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bootchart/store.c b/src/bootchart/store.c +index ed46a503c6..ed683e88d9 100644 +--- a/src/bootchart/store.c ++++ b/src/bootchart/store.c +@@ -399,7 +399,7 @@ schedstat_next: + continue; + + ps->sample->next = new0(struct ps_sched_struct, 1); +- if (!ps->sample) { ++ if (!ps->sample->next) { + log_oom(); + exit(EXIT_FAILURE); + } diff --git a/0267-sd-bus-sd_bus_message_get_errno-should-only-return-p.patch b/0267-sd-bus-sd_bus_message_get_errno-should-only-return-p.patch new file mode 100644 index 0000000..85ebe19 --- /dev/null +++ b/0267-sd-bus-sd_bus_message_get_errno-should-only-return-p.patch @@ -0,0 +1,70 @@ +From b49ffb29ed902f173852707652b3e3c9c303cebb Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Mon, 15 Sep 2014 22:36:43 +0200 +Subject: [PATCH] sd-bus: sd_bus_message_get_errno should only return positive + errno + +sd_bus_message_get_errno can currently return either a number of +different poitive errno values (from bus-error-mapping), or a negative +EINVAL if passed null as parameter. + +The check for null parameter was introduced in 40ca29a1370379d43e44c0ed425eecc7218dcbca +at the same as the function was renamed from bus_message_to_errno and +made public API. Before becoming public the function used to return +only negative values. + +It is weird to have a function return both positive and negative errno +and it generally looks like a mistake. The function is guarded by the +--enable-kdbus flags so I wonder if we still have time to fix it up? +It does not have any documentation yet. However, except for a few details +it is just a convenient way to call sd_bus_error_get_errno which is documented +to return only positive errno. + +This patch makes it return only positive errno and fixes up the two +calls to the function that tried to cope with both positive and negative +values. +--- + src/libsystemd/sd-bus/bus-message.c | 2 +- + src/libsystemd/sd-bus/sd-bus.c | 2 -- + src/network/networkd-link.c | 2 -- + 3 files changed, 1 insertion(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index bfb14fcce6..1fa3ad2611 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -5337,7 +5337,7 @@ int bus_header_message_size(struct bus_header *h, size_t *sum) { + } + + _public_ int sd_bus_message_get_errno(sd_bus_message *m) { +- assert_return(m, -EINVAL); ++ assert_return(m, EINVAL); + + if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) + return 0; +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 33b65aba72..28b993b7ba 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -349,8 +349,6 @@ static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd + assert(reply); + + r = sd_bus_message_get_errno(reply); +- if (r < 0) +- return r; + if (r > 0) + return -r; + +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 9bf1a811c9..427f6953c5 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -725,8 +725,6 @@ static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, + return 1; + + r = sd_bus_message_get_errno(m); +- if (r < 0) +- r = -r; + if (r > 0) + log_warning_link(link, "Could not set hostname: %s", + strerror(r)); diff --git a/0268-terminal-sd_bus_error_get_errno-returns-positive-err.patch b/0268-terminal-sd_bus_error_get_errno-returns-positive-err.patch new file mode 100644 index 0000000..9f669ce --- /dev/null +++ b/0268-terminal-sd_bus_error_get_errno-returns-positive-err.patch @@ -0,0 +1,45 @@ +From 9169b9a8cc43046f92a4c5c85b0b3fe9ca0fb429 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Mon, 15 Sep 2014 22:55:36 +0200 +Subject: [PATCH] terminal: sd_bus_error_get_errno returns positive errno + +The 3 calls to sd_bus_error_get_errno appear to expect a negative +return value. + +This patch negates the returned value so it matches the other error +cases in the 3 functions where sd_bus_error_get_errno is used. +--- + src/libsystemd-terminal/sysview.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 2083f5a7e0..fde87d1117 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -263,7 +263,7 @@ static int session_take_control_fn(sd_bus *bus, + + log_debug("sysview: %s: TakeControl failed: %s: %s", + session->name, e->name, e->message); +- error = sd_bus_error_get_errno(e); ++ error = -sd_bus_error_get_errno(e); + } else { + session->has_control = true; + error = 0; +@@ -1195,7 +1195,7 @@ static int context_ld_list_seats_fn(sd_bus *bus, + + log_debug("sysview: ListSeats on logind failed: %s: %s", + error->name, error->message); +- return sd_bus_error_get_errno(error); ++ return -sd_bus_error_get_errno(error); + } + + r = sd_bus_message_enter_container(reply, 'a', "(so)"); +@@ -1247,7 +1247,7 @@ static int context_ld_list_sessions_fn(sd_bus *bus, + + log_debug("sysview: ListSessions on logind failed: %s: %s", + error->name, error->message); +- return sd_bus_error_get_errno(error); ++ return -sd_bus_error_get_errno(error); + } + + r = sd_bus_message_enter_container(reply, 'a', "(susso)"); diff --git a/0269-missing-memfd_create-takes-unsigned-int-flags-in-fin.patch b/0269-missing-memfd_create-takes-unsigned-int-flags-in-fin.patch new file mode 100644 index 0000000..b98a772 --- /dev/null +++ b/0269-missing-memfd_create-takes-unsigned-int-flags-in-fin.patch @@ -0,0 +1,23 @@ +From 06b7f7bd7fa8cde840dd693c7a68dbd954c119ec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Tue, 16 Sep 2014 14:17:01 -0300 +Subject: [PATCH] missing: memfd_create takes unsigned int flags in final + version + +--- + src/shared/missing.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 023c680ec6..b441149945 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -209,7 +209,7 @@ static inline int fanotify_mark(int fanotify_fd, unsigned int flags, uint64_t ma + #endif + + #ifndef HAVE_MEMFD_CREATE +-static inline int memfd_create(const char *name, uint64_t flags) { ++static inline int memfd_create(const char *name, unsigned int flags) { + return syscall(__NR_memfd_create, name, flags); + } + #endif diff --git a/0270-core-fix-resource-leak-in-manager_environment_add.patch b/0270-core-fix-resource-leak-in-manager_environment_add.patch new file mode 100644 index 0000000..ead23b3 --- /dev/null +++ b/0270-core-fix-resource-leak-in-manager_environment_add.patch @@ -0,0 +1,29 @@ +From aa9f8a30fd7dc7aa3aa2575b75b3f9a0ab3f02db Mon Sep 17 00:00:00 2001 +From: Andreas Henriksson +Date: Tue, 16 Sep 2014 21:11:02 +0200 +Subject: [PATCH] core: fix resource leak in manager_environment_add + +Second error path must free the (potentially) allocated memory in the +first code chunk before returning. + +Found by coverity. Fixes: CID#1237750 +--- + src/core/manager.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 0770727cde..e0c1cd187e 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2751,8 +2751,10 @@ int manager_environment_add(Manager *m, char **minus, char **plus) { + + if (!strv_isempty(plus)) { + b = strv_env_merge(2, l, plus); +- if (!b) ++ if (!b) { ++ strv_free(a); + return -ENOMEM; ++ } + + l = b; + } diff --git a/0271-sysv-generator-fix-resource-leak.patch b/0271-sysv-generator-fix-resource-leak.patch new file mode 100644 index 0000000..a47cb43 --- /dev/null +++ b/0271-sysv-generator-fix-resource-leak.patch @@ -0,0 +1,27 @@ +From 91e7bad45dced1cb2dfaac79337bb08d6e2b74a9 Mon Sep 17 00:00:00 2001 +From: Andreas Henriksson +Date: Tue, 16 Sep 2014 21:22:59 +0200 +Subject: [PATCH] sysv-generator: fix resource leak + +The "unit" string allocation is not freed on either error or success path. + +Found by coverity. Fixes: CID#1237755 +--- + src/sysv-generator/sysv-generator.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 6c3281ff15..e5902ab8f8 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -114,9 +114,9 @@ static int add_symlink(const char *service, const char *where) { + } + + static int generate_unit_file(SysvStub *s) { +- char *unit; + char **p; + _cleanup_fclose_ FILE *f = NULL; ++ _cleanup_free_ char *unit = NULL; + _cleanup_free_ char *before = NULL; + _cleanup_free_ char *after = NULL; + _cleanup_free_ char *wants = NULL; diff --git a/0272-shared-fix-resource-leak-in-config_parse_default_ins.patch b/0272-shared-fix-resource-leak-in-config_parse_default_ins.patch new file mode 100644 index 0000000..f6b740b --- /dev/null +++ b/0272-shared-fix-resource-leak-in-config_parse_default_ins.patch @@ -0,0 +1,28 @@ +From d9ab174bd7ec1dd5b382d3d84737d1c9ed1f4481 Mon Sep 17 00:00:00 2001 +From: Andreas Henriksson +Date: Tue, 16 Sep 2014 21:36:26 +0200 +Subject: [PATCH] shared: fix resource leak in config_parse_default_instance + +The recently allocated "printed" is not freed on error path. + +Found by coverity. Fixes: CID#1237745 +--- + src/shared/install.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 5d3fcf5e32..61e572bdf3 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1025,8 +1025,10 @@ static int config_parse_default_instance( + if (r < 0) + return r; + +- if (!unit_instance_is_valid(printed)) ++ if (!unit_instance_is_valid(printed)) { ++ free(printed); + return -EINVAL; ++ } + + free(i->default_instance); + i->default_instance = printed; diff --git a/0273-test-silence-a-coverity-report.patch b/0273-test-silence-a-coverity-report.patch new file mode 100644 index 0000000..0b71d82 --- /dev/null +++ b/0273-test-silence-a-coverity-report.patch @@ -0,0 +1,26 @@ +From cca0efb0477f9bb7d61b48ba270b885b29c0bb72 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 16 Sep 2014 21:59:50 +0200 +Subject: [PATCH] test: silence a coverity report + +We check the actual contents of the file on the line after but we +might as well also check the number of bytes read here. + +Found by coverity. Fixes: CID#1237521 +--- + src/test/test-fileio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index e69706c3f8..92aa794a95 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -325,7 +325,7 @@ static void test_write_string_file(void) { + + assert_se(write_string_file(fn, "boohoo") == 0); + +- assert_se(read(fd, buf, sizeof(buf))); ++ assert_se(read(fd, buf, sizeof(buf)) == 7); + assert_se(streq(buf, "boohoo\n")); + + unlink(fn); diff --git a/0274-terminal-remove-dead-code-checking-O_WRONLY.patch b/0274-terminal-remove-dead-code-checking-O_WRONLY.patch new file mode 100644 index 0000000..3e5feb9 --- /dev/null +++ b/0274-terminal-remove-dead-code-checking-O_WRONLY.patch @@ -0,0 +1,30 @@ +From 1164e944d9689c3e94c100a634fb5a404662e247 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 16 Sep 2014 23:00:26 +0200 +Subject: [PATCH] terminal: remove dead code checking O_WRONLY + +We only reject evdev FDs that are O_WRONLY as they're currently pretty +useless. The following check for O_WRONLY is thus never excercised so drop +it. +Thanks to Thomas Andersen (via coverity)! +--- + src/libsystemd-terminal/idev-evdev.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index 6509d1011e..18c48ee592 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -314,11 +314,7 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { + return -EACCES; + + evdev->element.readable = true; +- evdev->element.writable = true; +- if (flags == O_RDONLY) +- evdev->element.writable = false; +- else if (flags == O_WRONLY) +- evdev->element.readable = false; ++ evdev->element.writable = !(flags & O_RDONLY); + + /* + * TODO: We *MUST* re-sync the device so we get a delta of the changed diff --git a/0275-util-remove-a-unnecessary-check.patch b/0275-util-remove-a-unnecessary-check.patch new file mode 100644 index 0000000..cfc8896 --- /dev/null +++ b/0275-util-remove-a-unnecessary-check.patch @@ -0,0 +1,27 @@ +From 42646a8bf24be2c9280554c9d8540c67c835b3c4 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 16 Sep 2014 22:58:35 +0200 +Subject: [PATCH] util: remove a unnecessary check + +We only break out of the previous loop if fd >= 0 so there is no +use in checking it again. + +Found by coverity. Fixes: CID#1237577 +--- + src/shared/util.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 61d6680ddd..30b0364b64 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -1878,9 +1878,6 @@ int open_terminal(const char *name, int mode) { + c++; + } + +- if (fd < 0) +- return -errno; +- + r = isatty(fd); + if (r < 0) { + safe_close(fd); diff --git a/0276-sysctl-make-prefix-allow-all-kinds-of-sysctl-paths.patch b/0276-sysctl-make-prefix-allow-all-kinds-of-sysctl-paths.patch new file mode 100644 index 0000000..b1fac93 --- /dev/null +++ b/0276-sysctl-make-prefix-allow-all-kinds-of-sysctl-paths.patch @@ -0,0 +1,62 @@ +From 0e1f579227b08832437a7ac2227c7e4007a89d23 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 17 Sep 2014 09:06:49 +0200 +Subject: [PATCH] sysctl: make --prefix allow all kinds of sysctl paths + +Currently, we save arguments passed as --prefix directly and compare them +later to absolute sysctl file-system paths. That is, you are required to +specify arguments to --prefix with leading /proc/sys/. This is kinda +uselesss. Furthermore, we replace dots by slashes in the name, which makes +it impossible to match on specific sysfs paths that have dots in their +name (like netdev names). The intention of this argument is clear, but it +never worked as expected. + +This patch modifies --prefix to accept any kind of sysctl paths. It +supports paths prefixed with /proc/sys for compatibility (but drops the +erroneous dot->slash conversion), but instead applies normalize_sysctl() +which turns any name or path into a proper path. It then appends +/proc/sys/ so we can properly use it in matches. + +Thanks to Jan Synacek for catching this! +--- + src/sysctl/sysctl.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c +index 4f9530baf8..809e59b71f 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -219,7 +219,7 @@ static void help(void) { + "Applies kernel sysctl settings.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" +- " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n" ++ " --prefix=PATH Only apply rules with the specified prefix\n" + , program_invocation_short_name); + } + +@@ -258,11 +258,19 @@ static int parse_argv(int argc, char *argv[]) { + case ARG_PREFIX: { + char *p; + +- for (p = optarg; *p; p++) +- if (*p == '.') +- *p = '/'; +- +- if (strv_extend(&arg_prefixes, optarg) < 0) ++ /* We used to require people to specify absolute paths ++ * in /proc/sys in the past. This is kinda useless, but ++ * we need to keep compatibility. We now support any ++ * sysctl name available. */ ++ normalize_sysctl(optarg); ++ if (startswith(optarg, "/proc/sys")) ++ p = strdup(optarg); ++ else ++ p = strappend("/proc/sys/", optarg); ++ ++ if (!p) ++ return log_oom(); ++ if (strv_consume(&arg_prefixes, p) < 0) + return log_oom(); + + break; diff --git a/0277-bus-never-respond-to-GetManagedObjects-on-sub-paths.patch b/0277-bus-never-respond-to-GetManagedObjects-on-sub-paths.patch new file mode 100644 index 0000000..c3b5a32 --- /dev/null +++ b/0277-bus-never-respond-to-GetManagedObjects-on-sub-paths.patch @@ -0,0 +1,139 @@ +From 943c3f94e2f8b8b35ef6a40220bbe4c06510930c Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 17 Sep 2014 09:28:09 +0200 +Subject: [PATCH] bus: never respond to GetManagedObjects() on sub-paths + +The dbus-spec clearly specifies that GetManagedObjects() should only work +on the root-path of an object-tree. But on that path, it works regardless +whether there are any objects available or not. + +We could, technically, define all sub-paths as a root-path of its own +sub-tree. However, if we do that, we enter undefined territory: + + Imagine only a fallback vtable is registered. We want + GetManagedObjects() to *NOT* fail with UNKNOWN_METHOD if it is called + on a valid sub-tree of the fallback. On the other hand, we don't want + it to work on arbitrary sub-tree. Something like: + /path/to/fallback/foobar/foobar/foobar/invalid/foobar + should not work. + However, there is no way to know which paths on a fallback are valid + without looking at there registered objects. If no objects are + registered, we have no way to figure it out. + +Therefore, we now try to follow the dbus spec by only returning valid data +on registered root-paths. We treat each path as root which was registered +an object-manager on via add_object_manager(). So applications can now +directly control which paths to place an object-manager on. + +We also fix the introspection to not return object-manager interfaces on +non-root paths. + +Also fixes some dead-code paths initially reported by Philippe De Swert. +--- + src/libsystemd/sd-bus/bus-objects.c | 63 ++++++++----------------------------- + 1 file changed, 13 insertions(+), 50 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c +index 81c840f129..ecac73a94d 100644 +--- a/src/libsystemd/sd-bus/bus-objects.c ++++ b/src/libsystemd/sd-bus/bus-objects.c +@@ -820,19 +820,6 @@ static int property_get_all_callbacks_run( + return 1; + } + +-static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) { +- assert(bus); +- assert(n); +- +- if (n->object_managers) +- return true; +- +- if (n->parent) +- return bus_node_with_object_manager(bus, n->parent); +- +- return false; +-} +- + static bool bus_node_exists( + sd_bus *bus, + struct node *n, +@@ -902,7 +889,7 @@ static int process_introspect( + if (r < 0) + return r; + +- r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n)); ++ r = introspect_write_default_interfaces(&intro, !require_fallback && n->object_managers); + if (r < 0) + return r; + +@@ -1142,7 +1129,8 @@ static int process_get_managed_objects( + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_set_free_free_ Set *s = NULL; +- bool empty; ++ Iterator i; ++ char *path; + int r; + + assert(bus); +@@ -1150,7 +1138,11 @@ static int process_get_managed_objects( + assert(n); + assert(found_object); + +- if (!bus_node_with_object_manager(bus, n)) ++ /* Spec says, GetManagedObjects() is only implemented on the root of a ++ * sub-tree. Therefore, we require a registered object-manager on ++ * exactly the queried path, otherwise, we refuse to respond. */ ++ ++ if (require_fallback || !n->object_managers) + return 0; + + r = get_child_nodes(bus, m->path, n, &s, &error); +@@ -1167,42 +1159,13 @@ static int process_get_managed_objects( + if (r < 0) + return r; + +- empty = set_isempty(s); +- if (empty) { +- struct node_vtable *c; +- +- /* Hmm, so we have no children? Then let's check +- * whether we exist at all, i.e. whether at least one +- * vtable exists. */ +- +- LIST_FOREACH(vtables, c, n->vtables) { +- +- if (require_fallback && !c->is_fallback) +- continue; +- +- if (r < 0) +- return r; +- if (r == 0) +- continue; +- +- empty = false; +- break; +- } ++ SET_FOREACH(path, s, i) { ++ r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error); ++ if (r < 0) ++ return r; + +- if (empty) ++ if (bus->nodes_modified) + return 0; +- } else { +- Iterator i; +- char *path; +- +- SET_FOREACH(path, s, i) { +- r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error); +- if (r < 0) +- return r; +- +- if (bus->nodes_modified) +- return 0; +- } + } + + r = sd_bus_message_close_container(reply); diff --git a/0278-bus-fix-error-leak-in-bus_node_exists.patch b/0278-bus-fix-error-leak-in-bus_node_exists.patch new file mode 100644 index 0000000..eb4e44f --- /dev/null +++ b/0278-bus-fix-error-leak-in-bus_node_exists.patch @@ -0,0 +1,98 @@ +From ff02f101cb7db516bf1732bb74c42cb3b6259af1 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 17 Sep 2014 10:32:49 +0200 +Subject: [PATCH] bus: fix error leak in bus_node_exists() + +If we call into user callbacks, we must always propagate possible errors. +Fix bus_node_exists() to do that and adjust the callers (which already +partially propagated the error). + +Also speed up that function by first checking for registered enumerators +and/or object-managers. +--- + src/libsystemd/sd-bus/bus-objects.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c +index ecac73a94d..0ab1119b58 100644 +--- a/src/libsystemd/sd-bus/bus-objects.c ++++ b/src/libsystemd/sd-bus/bus-objects.c +@@ -820,7 +820,7 @@ static int property_get_all_callbacks_run( + return 1; + } + +-static bool bus_node_exists( ++static int bus_node_exists( + sd_bus *bus, + struct node *n, + const char *path, +@@ -828,6 +828,7 @@ static bool bus_node_exists( + + struct node_vtable *c; + struct node_callback *k; ++ int r; + + assert(bus); + assert(n); +@@ -836,11 +837,14 @@ static bool bus_node_exists( + /* Tests if there's anything attached directly to this node + * for the specified path */ + ++ if (!require_fallback && (n->enumerators || n->object_managers)) ++ return true; ++ + LIST_FOREACH(callbacks, k, n->callbacks) { + if (require_fallback && !k->is_fallback) + continue; + +- return true; ++ return 1; + } + + LIST_FOREACH(vtables, c, n->vtables) { +@@ -849,13 +853,14 @@ static bool bus_node_exists( + if (require_fallback && !c->is_fallback) + continue; + +- if (node_vtable_get_userdata(bus, path, c, NULL, &error) > 0) +- return true; ++ r = node_vtable_get_userdata(bus, path, c, NULL, &error); ++ if (r != 0) ++ return r; + if (bus->nodes_modified) +- return false; ++ return 0; + } + +- return !require_fallback && (n->enumerators || n->object_managers); ++ return 0; + } + + static int process_introspect( +@@ -938,12 +943,12 @@ static int process_introspect( + /* Nothing?, let's see if we exist at all, and if not + * refuse to do anything */ + r = bus_node_exists(bus, n, m->path, require_fallback); +- if (r < 0) +- return r; +- if (bus->nodes_modified) +- return 0; +- if (r == 0) ++ if (r <= 0) ++ goto finish; ++ if (bus->nodes_modified) { ++ r = 0; + goto finish; ++ } + } + + *found_object = true; +@@ -1293,6 +1298,8 @@ static int object_find_and_run( + r = bus_node_exists(bus, n, m->path, require_fallback); + if (r < 0) + return r; ++ if (bus->nodes_modified) ++ return 0; + if (r > 0) + *found_object = true; + } diff --git a/0279-networkd-dhcp4-fix-unchecked-return-value.patch b/0279-networkd-dhcp4-fix-unchecked-return-value.patch new file mode 100644 index 0000000..4b54c44 --- /dev/null +++ b/0279-networkd-dhcp4-fix-unchecked-return-value.patch @@ -0,0 +1,49 @@ +From f414a269b378d526b8b26c5b52743360b43965ce Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 17 Sep 2014 19:00:55 +0200 +Subject: [PATCH] networkd: dhcp4 - fix unchecked return value + +Found by coverity. CID #1237529 and #1237528. +--- + src/network/networkd-dhcp4.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c +index e0b3acad1b..e451af8643 100644 +--- a/src/network/networkd-dhcp4.c ++++ b/src/network/networkd-dhcp4.c +@@ -178,7 +178,7 @@ static int dhcp_lease_lost(Link *link) { + struct in_addr addr; + struct in_addr netmask; + struct in_addr gateway; +- unsigned prefixlen; ++ unsigned prefixlen = 0; + int r; + + assert(link); +@@ -237,15 +237,18 @@ static int dhcp_lease_lost(Link *link) { + } + } + +- sd_dhcp_lease_get_address(link->dhcp_lease, &addr); +- sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); +- prefixlen = in_addr_netmask_to_prefixlen(&netmask); ++ r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr); ++ if (r >= 0) { ++ r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); ++ if (r >= 0) ++ prefixlen = in_addr_netmask_to_prefixlen(&netmask); + +- address->family = AF_INET; +- address->in_addr.in = addr; +- address->prefixlen = prefixlen; ++ address->family = AF_INET; ++ address->in_addr.in = addr; ++ address->prefixlen = prefixlen; + +- address_drop(address, link, &link_address_drop_handler); ++ address_drop(address, link, &link_address_drop_handler); ++ } + } + + if (link->network->dhcp_mtu) { diff --git a/0280-libsystemd-network-dhcp-test-assert-that-malloc0-suc.patch b/0280-libsystemd-network-dhcp-test-assert-that-malloc0-suc.patch new file mode 100644 index 0000000..6abab5b --- /dev/null +++ b/0280-libsystemd-network-dhcp-test-assert-that-malloc0-suc.patch @@ -0,0 +1,24 @@ +From 6f42877282a7237f3aa840403047b7cc18d7faa6 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 17 Sep 2014 19:07:56 +0200 +Subject: [PATCH] libsystemd-network: dhcp-test - assert that malloc0 succeeds + +Otherwise we would get a nullptr dereference later on. + +Found by coverity. Fixes CID #1237655. +--- + src/libsystemd-network/test-dhcp-option.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c +index 7a0fac8d33..63cdc7aa06 100644 +--- a/src/libsystemd-network/test-dhcp-option.c ++++ b/src/libsystemd-network/test-dhcp-option.c +@@ -115,6 +115,7 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen, + size_t len = sizeof(DHCPMessage) + optlen; + + message = malloc0(len); ++ assert_se(message); + + if (options && optlen) + memcpy(&message->options, options, optlen); diff --git a/0281-udev-rules-close-empty-file.patch b/0281-udev-rules-close-empty-file.patch new file mode 100644 index 0000000..7a0c1bd --- /dev/null +++ b/0281-udev-rules-close-empty-file.patch @@ -0,0 +1,33 @@ +From 6c8aaf0c1bf2a04010ae7125a08ceb51e7058712 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 17 Sep 2014 19:53:01 +0200 +Subject: [PATCH] udev: rules - close empty file + +If the file is found to be empty, we exit early without closing the file first. + +Found by coverity. Fixes CID #1237759. +--- + src/udev/udev-rules.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index 2a691f6ab7..3bc25f7c26 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -1575,7 +1575,7 @@ invalid: + } + + static int parse_file(struct udev_rules *rules, const char *filename) { +- FILE *f; ++ _cleanup_fclose_ FILE *f = NULL; + unsigned int first_token; + unsigned int filename_off; + char line[UTIL_LINE_SIZE]; +@@ -1633,7 +1633,6 @@ static int parse_file(struct udev_rules *rules, const char *filename) { + } + add_rule(rules, key, filename, filename_off, line_nr); + } +- fclose(f); + + /* link GOTOs to LABEL rules in this file to be able to fast-forward */ + for (i = first_token+1; i < rules->token_cur; i++) { diff --git a/0282-nss-resolve-remove-dead-code.patch b/0282-nss-resolve-remove-dead-code.patch new file mode 100644 index 0000000..0ef563c --- /dev/null +++ b/0282-nss-resolve-remove-dead-code.patch @@ -0,0 +1,28 @@ +From 4eef5b7441692c962af57eab7bb758f1cfdece35 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Wed, 17 Sep 2014 20:48:39 +0200 +Subject: [PATCH] nss-resolve: remove dead code + +ifindex < 0 was already checked before entering the loop + +Found by coverity. Fixes: CID#1237609 +--- + src/nss-resolve/nss-resolve.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c +index bc55acf8dd..39b73203d2 100644 +--- a/src/nss-resolve/nss-resolve.c ++++ b/src/nss-resolve/nss-resolve.c +@@ -466,11 +466,6 @@ enum nss_status _nss_resolve_gethostbyname3_r( + goto fail; + } + +- if (ifindex < 0) { +- r = -EINVAL; +- goto fail; +- } +- + memcpy(r_addr + i*ALIGN(alen), a, alen); + i++; + } diff --git a/0283-udev-event-modernize-spawn_read.patch b/0283-udev-event-modernize-spawn_read.patch new file mode 100644 index 0000000..a018410 --- /dev/null +++ b/0283-udev-event-modernize-spawn_read.patch @@ -0,0 +1,116 @@ +From 4cd5d5adb6a573d8ffb336b82325e5f2bb188381 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 17 Sep 2014 21:43:57 +0200 +Subject: [PATCH] udev: event - modernize spawn_read() + +--- + src/udev/udev-event.c | 51 ++++++++++++++++++++++++++------------------------- + 1 file changed, 26 insertions(+), 25 deletions(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index e8d6676616..6b8b5a8efa 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -422,9 +422,17 @@ static void spawn_read(struct udev_event *event, + const char *cmd, + int fd_stdout, int fd_stderr, + char *result, size_t ressize) { ++ _cleanup_close_ int fd_ep = -1; ++ struct epoll_event ep_outpipe = { ++ .events = EPOLLIN, ++ .data.ptr = &fd_stdout, ++ }; ++ struct epoll_event ep_errpipe = { ++ .events = EPOLLIN, ++ .data.ptr = &fd_stderr, ++ }; + size_t respos = 0; +- int fd_ep = -1; +- struct epoll_event ep_outpipe, ep_errpipe; ++ int r; + + /* read from child if requested */ + if (fd_stdout < 0 && fd_stderr < 0) +@@ -433,26 +441,22 @@ static void spawn_read(struct udev_event *event, + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + log_error("error creating epoll fd: %m"); +- goto out; ++ return; + } + + if (fd_stdout >= 0) { +- memzero(&ep_outpipe, sizeof(struct epoll_event)); +- ep_outpipe.events = EPOLLIN; +- ep_outpipe.data.ptr = &fd_stdout; +- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stdout, &ep_outpipe) < 0) { +- log_error("fail to add fd to epoll: %m"); +- goto out; ++ r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stdout, &ep_outpipe); ++ if (r < 0) { ++ log_error("fail to add stdout fd to epoll: %m"); ++ return; + } + } + + if (fd_stderr >= 0) { +- memzero(&ep_errpipe, sizeof(struct epoll_event)); +- ep_errpipe.events = EPOLLIN; +- ep_errpipe.data.ptr = &fd_stderr; +- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stderr, &ep_errpipe) < 0) { +- log_error("fail to add fd to epoll: %m"); +- goto out; ++ r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stderr, &ep_errpipe); ++ if (r < 0) { ++ log_error("fail to add stderr fd to epoll: %m"); ++ return; + } + } + +@@ -469,7 +473,7 @@ static void spawn_read(struct udev_event *event, + age_usec = now(CLOCK_MONOTONIC) - event->birth_usec; + if (age_usec >= timeout_usec) { + log_error("timeout '%s'", cmd); +- goto out; ++ return; + } + timeout = ((timeout_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC; + } else { +@@ -481,11 +485,10 @@ static void spawn_read(struct udev_event *event, + if (errno == EINTR) + continue; + log_error("failed to poll: %m"); +- goto out; +- } +- if (fdcount == 0) { ++ return; ++ } else if (fdcount == 0) { + log_error("timeout '%s'", cmd); +- goto out; ++ return; + } + + for (i = 0; i < fdcount; i++) { +@@ -522,9 +525,10 @@ static void spawn_read(struct udev_event *event, + } + } + } else if (ev[i].events & EPOLLHUP) { +- if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL) < 0) { ++ r = epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL); ++ if (r < 0) { + log_error("failed to remove fd from epoll: %m"); +- goto out; ++ return; + } + *fd = -1; + } +@@ -534,9 +538,6 @@ static void spawn_read(struct udev_event *event, + /* return the child's stdout string */ + if (result != NULL) + result[respos] = '\0'; +-out: +- if (fd_ep >= 0) +- close(fd_ep); + } + + static int spawn_wait(struct udev_event *event, diff --git a/0284-udev-event-explicitly-don-t-read-from-invalid-fd.patch b/0284-udev-event-explicitly-don-t-read-from-invalid-fd.patch new file mode 100644 index 0000000..d582d15 --- /dev/null +++ b/0284-udev-event-explicitly-don-t-read-from-invalid-fd.patch @@ -0,0 +1,24 @@ +From 3f796750b192e62701e91a95f85389f876d1059b Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 17 Sep 2014 21:44:56 +0200 +Subject: [PATCH] udev: event - explicitly don't read() from invalid fd + +This fixes CID #1237641. +--- + src/udev/udev-event.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 6b8b5a8efa..c8b142077e 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -494,6 +494,9 @@ static void spawn_read(struct udev_event *event, + for (i = 0; i < fdcount; i++) { + int *fd = (int *)ev[i].data.ptr; + ++ if (*fd < 0) ++ continue; ++ + if (ev[i].events & EPOLLIN) { + ssize_t count; + char buf[4096]; diff --git a/0285-udev-event-modernize-spawn_exec.patch b/0285-udev-event-modernize-spawn_exec.patch new file mode 100644 index 0000000..9a32a23 --- /dev/null +++ b/0285-udev-event-modernize-spawn_exec.patch @@ -0,0 +1,58 @@ +From 19c784c414e6f2b35a268034905e1db226e905f6 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 17 Sep 2014 21:53:20 +0200 +Subject: [PATCH] udev: event - modernize spawn_exec() + +--- + src/udev/udev-event.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index c8b142077e..dc1f682bfe 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -376,8 +376,7 @@ out: + static int spawn_exec(struct udev_event *event, + const char *cmd, char *const argv[], char **envp, const sigset_t *sigmask, + int fd_stdout, int fd_stderr) { +- int err; +- int fd; ++ _cleanup_close_ int fd = -1; + + /* discard child output or connect to pipe */ + fd = open("/dev/null", O_RDWR); +@@ -387,19 +386,17 @@ static int spawn_exec(struct udev_event *event, + dup2(fd, STDOUT_FILENO); + if (fd_stderr < 0) + dup2(fd, STDERR_FILENO); +- close(fd); +- } else { ++ } else + log_error("open /dev/null failed: %m"); +- } + + /* connect pipes to std{out,err} */ + if (fd_stdout >= 0) { + dup2(fd_stdout, STDOUT_FILENO); +- close(fd_stdout); ++ safe_close(fd_stdout); + } + if (fd_stderr >= 0) { + dup2(fd_stderr, STDERR_FILENO); +- close(fd_stderr); ++ safe_close(fd_stderr); + } + + /* terminate child in case parent goes away */ +@@ -412,9 +409,9 @@ static int spawn_exec(struct udev_event *event, + execve(argv[0], argv, envp); + + /* exec failed */ +- err = -errno; + log_error("failed to execute '%s' '%s': %m", argv[0], cmd); +- return err; ++ ++ return -errno; + } + + static void spawn_read(struct udev_event *event, diff --git a/0286-shared-conf-parser.patch b/0286-shared-conf-parser.patch new file mode 100644 index 0000000..cee4a8e --- /dev/null +++ b/0286-shared-conf-parser.patch @@ -0,0 +1,34 @@ +From 83e341a637b75f7f592a5dc717c34d8b67ed4ffa Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Wed, 17 Sep 2014 22:17:53 +0200 +Subject: [PATCH] shared: conf-parser + +Check memory allocation. Found by Coverity. + +Fixes CID #1237644. +--- + src/shared/conf-parser.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h +index a17dde9069..94185152cd 100644 +--- a/src/shared/conf-parser.h ++++ b/src/shared/conf-parser.h +@@ -179,6 +179,9 @@ int log_syntax_internal(const char *unit, int level, + assert(data); \ + \ + xs = new0(type, 1); \ ++ if(!xs) \ ++ return -ENOMEM; \ ++ \ + *xs = invalid; \ + \ + FOREACH_WORD(word, l, rvalue, state) { \ +@@ -211,6 +214,7 @@ int log_syntax_internal(const char *unit, int level, + xs = realloc(xs, (++i + 1) * sizeof(type)); \ + if (!xs) \ + return -ENOMEM; \ ++ \ + *(xs + i) = invalid; \ + } \ + \ diff --git a/0287-logind-fix-typo.patch b/0287-logind-fix-typo.patch new file mode 100644 index 0000000..3bcccbd --- /dev/null +++ b/0287-logind-fix-typo.patch @@ -0,0 +1,22 @@ +From 2b2332856bafe25c4aa17db2a90bdcddef1fec1a Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Wed, 17 Sep 2014 20:10:44 +0200 +Subject: [PATCH] logind: fix typo + +--- + src/login/logind-session-dbus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c +index 7d81500426..58836fce25 100644 +--- a/src/login/logind-session-dbus.c ++++ b/src/login/logind-session-dbus.c +@@ -249,7 +249,7 @@ static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *user + return r; + + if (uid != 0 && uid != s->user->uid) +- return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session my set idle hint"); ++ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint"); + + session_set_idle_hint(s, b); + diff --git a/0288-sysv-generator-don-t-check-first-if-hashmap-contains.patch b/0288-sysv-generator-don-t-check-first-if-hashmap-contains.patch new file mode 100644 index 0000000..e952f11 --- /dev/null +++ b/0288-sysv-generator-don-t-check-first-if-hashmap-contains.patch @@ -0,0 +1,31 @@ +From 8c84621c25c563c7428f3d355136fc542389aab8 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Wed, 17 Sep 2014 23:03:27 +0200 +Subject: [PATCH] sysv-generator: don't check first if hashmap contains the + service name + +Just test if hashmap_get returns null. hashmap_contains does exactly +same thing internally so this is slightly more efficient for the true +case. + +Silences a coverity warning too. CID#1237648 +--- + src/sysv-generator/sysv-generator.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index e5902ab8f8..43bcaa862f 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -810,9 +810,8 @@ static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) { + goto finish; + } + +- if (hashmap_contains(all_services, name)) +- service = hashmap_get(all_services, name); +- else { ++ service = hashmap_get(all_services, name); ++ if (!service){ + log_warning("Could not find init script for %s", name); + continue; + } diff --git a/0289-Fix-resource-leak-coverity-CID-1237760.patch b/0289-Fix-resource-leak-coverity-CID-1237760.patch new file mode 100644 index 0000000..8e67dca --- /dev/null +++ b/0289-Fix-resource-leak-coverity-CID-1237760.patch @@ -0,0 +1,27 @@ +From 4edf33d1e3fb551b1b0cee8e4a2a380c71b00dc7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Wed, 17 Sep 2014 18:10:21 -0300 +Subject: [PATCH] Fix resource leak (coverity CID 1237760) + +--- + src/libsystemd/sd-bus/bus-kernel.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 505f335e07..b3cc996b1e 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -1446,9 +1446,11 @@ int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char * + } + + if (ep_path) { +- asprintf(ep_path, "%s/%s", dirname(path), ep_name); +- if (!*ep_path) ++ int r = asprintf(ep_path, "%s/%s", dirname(path), ep_name); ++ if (r == -1 || !*ep_path) { ++ safe_close(fd); + return -ENOMEM; ++ } + } + + return fd; diff --git a/0290-systemctl-fix-resource-leak-CID-1237747.patch b/0290-systemctl-fix-resource-leak-CID-1237747.patch new file mode 100644 index 0000000..dac595e --- /dev/null +++ b/0290-systemctl-fix-resource-leak-CID-1237747.patch @@ -0,0 +1,32 @@ +From 48a2900c6612052149a1d0dd88aeacb99b49ce4d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Wed, 17 Sep 2014 21:56:25 -0300 +Subject: [PATCH] systemctl: fix resource leak CID #1237747 + +..by simply moving the declaration of "unit" into the STRV_FOREACH +loop as suggested by Andreas. +--- + src/systemctl/systemctl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 88be871f32..901212852d 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4449,7 +4449,6 @@ static int show(sd_bus *bus, char **args) { + } + + static int cat(sd_bus *bus, char **args) { +- _cleanup_free_ char *unit = NULL; + _cleanup_strv_free_ char **names = NULL; + char **name; + bool first = true; +@@ -4468,6 +4467,8 @@ static int cat(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **dropin_paths = NULL; + _cleanup_free_ char *fragment_path = NULL; ++ _cleanup_free_ char *unit = NULL; ++ + char **path; + + unit = unit_dbus_path_from_name(*name); diff --git a/0291-sd-bus-sync-kdbus.h.patch b/0291-sd-bus-sync-kdbus.h.patch new file mode 100644 index 0000000..68a83dc --- /dev/null +++ b/0291-sd-bus-sync-kdbus.h.patch @@ -0,0 +1,274 @@ +From 913b6d70cbfd6151babc77ffc5e8c67b953ddba9 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Thu, 18 Sep 2014 10:25:35 +0200 +Subject: [PATCH] sd-bus: sync kdbus.h + +(no API/ABI break this time) +--- + src/libsystemd/sd-bus/kdbus.h | 176 ++++++++++++------------------------------ + 1 file changed, 49 insertions(+), 127 deletions(-) + +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index 65f76e9cf4..7379b3d442 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -1,9 +1,9 @@ + /* +- * Copyright (C) 2013 Kay Sievers +- * Copyright (C) 2013 Greg Kroah-Hartman +- * Copyright (C) 2013 Linux Foundation +- * Copyright (C) 2013 Lennart Poettering +- * Copyright (C) 2013 Daniel Mack ++ * Copyright (C) 2013-2014 Kay Sievers ++ * Copyright (C) 2013-2014 Greg Kroah-Hartman ++ * Copyright (C) 2013-2014 Linux Foundation ++ * Copyright (C) 2013-2014 Lennart Poettering ++ * Copyright (C) 2013-2014 Daniel Mack + * + * kdbus 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 +@@ -14,8 +14,8 @@ + * -- Albert Einstein + */ + +-#ifndef _KDBUS_H_ +-#define _KDBUS_H_ ++#ifndef _KDBUS_UAPI_H_ ++#define _KDBUS_UAPI_H_ + + #ifndef __KERNEL__ + #include +@@ -126,7 +126,7 @@ struct kdbus_timestamp { + * relative to the message head + * + * Attached to: +- * KDBUS_ITEM_PAYLOAD_VEC ++ * KDBUS_ITEM_PAYLOAD_VEC, KDBUS_ITEM_PAYLOAD_OFF + */ + struct kdbus_vec { + __u64 size; +@@ -358,9 +358,9 @@ struct kdbus_item { + * name is not currently active + */ + enum kdbus_msg_flags { +- KDBUS_MSG_FLAGS_EXPECT_REPLY = 1 << 0, +- KDBUS_MSG_FLAGS_SYNC_REPLY = 1 << 1, +- KDBUS_MSG_FLAGS_NO_AUTO_START = 1 << 2, ++ KDBUS_MSG_FLAGS_EXPECT_REPLY = 1ULL << 0, ++ KDBUS_MSG_FLAGS_SYNC_REPLY = 1ULL << 1, ++ KDBUS_MSG_FLAGS_NO_AUTO_START = 1ULL << 2, + }; + + /** +@@ -425,9 +425,9 @@ struct kdbus_msg { + * the priority value is ignored. + */ + enum kdbus_recv_flags { +- KDBUS_RECV_PEEK = 1 << 0, +- KDBUS_RECV_DROP = 1 << 1, +- KDBUS_RECV_USE_PRIORITY = 1 << 2, ++ KDBUS_RECV_PEEK = 1ULL << 0, ++ KDBUS_RECV_DROP = 1ULL << 1, ++ KDBUS_RECV_USE_PRIORITY = 1ULL << 2, + }; + + /** +@@ -486,16 +486,16 @@ enum kdbus_policy_type { + * policy entries for a name. The provided name + * is not activated and not registered with the + * name database, it only allows unprivileged +- * connections to acquire a name, talk or discover ++ * connections to aquire a name, talk or discover + * a service + * @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor + * bus traffic + */ + enum kdbus_hello_flags { +- KDBUS_HELLO_ACCEPT_FD = 1 << 0, +- KDBUS_HELLO_ACTIVATOR = 1 << 1, +- KDBUS_HELLO_POLICY_HOLDER = 1 << 2, +- KDBUS_HELLO_MONITOR = 1 << 3, ++ KDBUS_HELLO_ACCEPT_FD = 1ULL << 0, ++ KDBUS_HELLO_ACTIVATOR = 1ULL << 1, ++ KDBUS_HELLO_POLICY_HOLDER = 1ULL << 2, ++ KDBUS_HELLO_MONITOR = 1ULL << 3, + }; + + /** +@@ -515,19 +515,19 @@ enum kdbus_hello_flags { + * @_KDBUS_ATTACH_ALL: All of the above + */ + enum kdbus_attach_flags { +- KDBUS_ATTACH_TIMESTAMP = 1 << 0, +- KDBUS_ATTACH_CREDS = 1 << 1, +- KDBUS_ATTACH_AUXGROUPS = 1 << 2, +- KDBUS_ATTACH_NAMES = 1 << 3, +- KDBUS_ATTACH_COMM = 1 << 4, +- KDBUS_ATTACH_EXE = 1 << 5, +- KDBUS_ATTACH_CMDLINE = 1 << 6, +- KDBUS_ATTACH_CGROUP = 1 << 7, +- KDBUS_ATTACH_CAPS = 1 << 8, +- KDBUS_ATTACH_SECLABEL = 1 << 9, +- KDBUS_ATTACH_AUDIT = 1 << 10, +- KDBUS_ATTACH_CONN_NAME = 1 << 11, +- _KDBUS_ATTACH_ALL = (1 << 12) - 1, ++ KDBUS_ATTACH_TIMESTAMP = 1ULL << 0, ++ KDBUS_ATTACH_CREDS = 1ULL << 1, ++ KDBUS_ATTACH_AUXGROUPS = 1ULL << 2, ++ KDBUS_ATTACH_NAMES = 1ULL << 3, ++ KDBUS_ATTACH_COMM = 1ULL << 4, ++ KDBUS_ATTACH_EXE = 1ULL << 5, ++ KDBUS_ATTACH_CMDLINE = 1ULL << 6, ++ KDBUS_ATTACH_CGROUP = 1ULL << 7, ++ KDBUS_ATTACH_CAPS = 1ULL << 8, ++ KDBUS_ATTACH_SECLABEL = 1ULL << 9, ++ KDBUS_ATTACH_AUDIT = 1ULL << 10, ++ KDBUS_ATTACH_CONN_NAME = 1ULL << 11, ++ _KDBUS_ATTACH_ALL = (1ULL << 12) - 1, + }; + + /** +@@ -569,8 +569,8 @@ struct kdbus_cmd_hello { + * @KDBUS_MAKE_ACCESS_WORLD: Make the device node world-accessible + */ + enum kdbus_make_flags { +- KDBUS_MAKE_ACCESS_GROUP = 1 << 0, +- KDBUS_MAKE_ACCESS_WORLD = 1 << 1, ++ KDBUS_MAKE_ACCESS_GROUP = 1ULL << 0, ++ KDBUS_MAKE_ACCESS_WORLD = 1ULL << 1, + }; + + /** +@@ -597,11 +597,11 @@ struct kdbus_cmd_make { + * @KDBUS_NAME_ACTIVATOR: Name is owned by a activator connection + */ + enum kdbus_name_flags { +- KDBUS_NAME_REPLACE_EXISTING = 1 << 0, +- KDBUS_NAME_ALLOW_REPLACEMENT = 1 << 1, +- KDBUS_NAME_QUEUE = 1 << 2, +- KDBUS_NAME_IN_QUEUE = 1 << 3, +- KDBUS_NAME_ACTIVATOR = 1 << 4, ++ KDBUS_NAME_REPLACE_EXISTING = 1ULL << 0, ++ KDBUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, ++ KDBUS_NAME_QUEUE = 1ULL << 2, ++ KDBUS_NAME_IN_QUEUE = 1ULL << 3, ++ KDBUS_NAME_ACTIVATOR = 1ULL << 4, + }; + + /** +@@ -630,10 +630,10 @@ struct kdbus_cmd_name { + * @KDBUS_NAME_LIST_QUEUED: All queued-up names + */ + enum kdbus_name_list_flags { +- KDBUS_NAME_LIST_UNIQUE = 1 << 0, +- KDBUS_NAME_LIST_NAMES = 1 << 1, +- KDBUS_NAME_LIST_ACTIVATORS = 1 << 2, +- KDBUS_NAME_LIST_QUEUED = 1 << 3, ++ KDBUS_NAME_LIST_UNIQUE = 1ULL << 0, ++ KDBUS_NAME_LIST_NAMES = 1ULL << 1, ++ KDBUS_NAME_LIST_ACTIVATORS = 1ULL << 2, ++ KDBUS_NAME_LIST_QUEUED = 1ULL << 3, + }; + + /** +@@ -749,11 +749,11 @@ struct kdbus_cmd_match { + * @KDBUS_CMD_HELLO: By opening the bus device node a connection is + * created. After a HELLO the opened connection + * becomes an active peer on the bus. +- * @KDBUS_CMD_BYEBYE: Disconnect a connection. If the connection's +- * message list is empty, the calls succeeds, and +- * the handle is rendered unusable. Otherwise, +- * -EAGAIN is returned without any further side- +- * effects. ++ * @KDBUS_CMD_BYEBYE: Disconnect a connection. If there are no ++ * messages queued up in the connection's pool, ++ * the call succeeds, and the handle is rendered ++ * unusable. Otherwise, -EBUSY is returned without ++ * any further side-effects. + * @KDBUS_CMD_MSG_SEND: Send a message and pass data from userspace to + * the kernel. + * @KDBUS_CMD_MSG_RECV: Receive a message from the kernel which is +@@ -824,82 +824,4 @@ enum kdbus_ioctl_type { + struct kdbus_cmd_match), + }; + +-/* +- * errno - api error codes +- * @E2BIG: A message contains too many records or items. +- * @EADDRINUSE: A well-known bus name is already taken by another +- * connection. +- * @EADDRNOTAVAIL: A message flagged not to activate a service, addressed +- * a service which is not currently running. +- * @EAGAIN: No messages are queued at the moment. +- * @EALREADY: A requested name is already owned by the connection, +- * a connection is already disconnected, memfd is already +- * sealed or has the requested size. +- * @EBADF: File descriptors passed with the message are not valid. +- * @EBADFD: A bus connection is in a corrupted state. +- * @EBADMSG: Passed data contains a combination of conflicting or +- * inconsistent types. +- * @EBUSY: The user tried to say BYEBYE to a connection, but the +- * connection had a non-empty message list. +- * @ECANCELED: A synchronous message sending was cancelled. +- * @ECONNRESET: A connection is shut down, no further operations are +- * possible. +- * @ECOMM: A peer does not accept the file descriptors addressed +- * to it. +- * @EDESTADDRREQ: The well-known bus name is required but missing. +- * @EDOM: The size of data does not match the expectations. Used +- * for bloom bit field sizes. +- * @EEXIST: A requested domain, bus or endpoint with the same +- * name already exists. A specific data type, which is +- * only expected once, is provided multiple times. +- * @EFAULT: The supplied memory could not be accessed, the data +- * is not properly aligned, or the current task's memory +- * is inaccessible. +- * @EINVAL: The provided data does not match its type or other +- * expectations, like a string which is not NUL terminated, +- * or a string length that points behind the first +- * \0-byte in the string. +- * @EMEDIUMTYPE: A file descriptor which is not a kdbus memfd was +- * refused to send as KDBUS_MSG_PAYLOAD_MEMFD. +- * @EMFILE: Too many file descriptors have been supplied with a +- * message. +- * Too many connections or buses are created for a given +- * user. +- * @EMLINK: Too many requests from this connection to other peers +- * are queued and waiting for a reply +- * @EMSGSIZE: The supplied data is larger than the allowed maximum +- * size. +- * @ENAMETOOLONG: The requested name is larger than the allowed maximum +- * size. +- * @ENOBUFS: There is no space left for the submitted data to fit +- * into the receiver's pool. +- * @ENOENT: The to be cancelled message was not found. +- * @ENOMEM: Out of memory. +- * @ENOMSG: The queue is not empty, but no message with a matching +- * priority is currently queued. +- * @ENOSYS: The requested functionality is not available. +- * @ENOTTY: An unknown ioctl command was received. +- * @ENOTUNIQ: A specific data type was addressed to a broadcast +- * address, but only direct addresses support this kind of +- * data. +- * @ENXIO: A unique address does not exist, or an offset in the +- * receiver's pool does not represent a queued message. +- * @EOPNOTSUPP: The feature negotiation failed, a not supported feature +- * was requested, or an unknown item type was received. +- * @EPERM: The policy prevented an operation. The requested +- * resource is owned by another entity. +- * @EPIPE: When sending a message, a synchronous reply from the +- * receiving connection was expected but the connection +- * died before answering. +- * @ESHUTDOWN: A domain, bus or endpoint is currently shutting down; +- * no further operations will be possible. +- * @ESRCH: A requested well-known bus name is not found. +- * @ETIMEDOUT: A synchronous wait for a message reply did not arrive +- * within the specified time frame. +- * @ETXTBSY: A kdbus memfd file cannot be sealed or the seal removed, +- * because it is shared with other processes or still +- * mmap()ed. +- * @EXFULL: The size limits in the pool are reached, no data of +- * the size tried to submit can be queued. +- */ +-#endif ++#endif /* _KDBUS_UAPI_H_ */ diff --git a/0292-tests-fix-resource-mem-leaks.patch b/0292-tests-fix-resource-mem-leaks.patch new file mode 100644 index 0000000..5027413 --- /dev/null +++ b/0292-tests-fix-resource-mem-leaks.patch @@ -0,0 +1,57 @@ +From 76082570b8115c3410bac42bb5842ba201dddb76 Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Thu, 18 Sep 2014 12:09:10 +0200 +Subject: [PATCH] tests: fix resource & mem leaks + +--- + src/test/test-condition-util.c | 2 +- + src/test/test-fileio.c | 9 ++++----- + 2 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/src/test/test-condition-util.c b/src/test/test-condition-util.c +index 4ee5600ff6..35ee9167bf 100644 +--- a/src/test/test-condition-util.c ++++ b/src/test/test-condition-util.c +@@ -45,7 +45,7 @@ static void test_condition_test_host(void) { + sd_id128_t id; + int r; + char sid[SD_ID128_STRING_MAX]; +- char *hostname; ++ _cleanup_free_ char *hostname = NULL; + + r = sd_id128_get_machine(&id); + assert_se(r >= 0); +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index 92aa794a95..1b99828191 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -303,7 +303,7 @@ static void test_write_string_stream(void) { + assert_se(f); + assert_se(write_string_stream(f, "boohoo") < 0); + +- f = fdopen(fd, "r+"); ++ f = freopen(fn, "r+", f); + assert_se(f); + + assert_se(write_string_stream(f, "boohoo") == 0); +@@ -317,8 +317,8 @@ static void test_write_string_stream(void) { + + static void test_write_string_file(void) { + char fn[] = "/tmp/test-write_string_file-XXXXXX"; +- int fd; +- char buf[64] = {0}; ++ char buf[64] = {}; ++ _cleanup_close_ int fd; + + fd = mkostemp_safe(fn, O_RDWR); + assert_se(fd >= 0); +@@ -334,8 +334,7 @@ static void test_write_string_file(void) { + static void test_sendfile_full(void) { + char in_fn[] = "/tmp/test-sendfile_full-XXXXXX"; + char out_fn[] = "/tmp/test-sendfile_full-XXXXXX"; +- _cleanup_close_ int in_fd = -1; +- int out_fd; ++ _cleanup_close_ int in_fd, out_fd; + char text[] = "boohoo\nfoo\n\tbar\n"; + char buf[64] = {0}; + diff --git a/0293-libudev-monitor-warn-if-we-fail-to-request-SO_PASSCR.patch b/0293-libudev-monitor-warn-if-we-fail-to-request-SO_PASSCR.patch new file mode 100644 index 0000000..236ee88 --- /dev/null +++ b/0293-libudev-monitor-warn-if-we-fail-to-request-SO_PASSCR.patch @@ -0,0 +1,26 @@ +From 9dedfe7f667a8cb22ba85d0223556c69c4fd0e9a Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 09:20:46 +0200 +Subject: [PATCH] libudev: monitor - warn if we fail to request SO_PASSCRED + +The function still succeeds, so there is no functional change. This fixes CID #996288. +--- + src/libudev/libudev-monitor.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c +index 186e5e1e87..59698b85b7 100644 +--- a/src/libudev/libudev-monitor.c ++++ b/src/libudev/libudev-monitor.c +@@ -412,7 +412,10 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) + } + + /* enable receiving of sender credentials */ +- setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); ++ err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); ++ if (err < 0) ++ udev_err(udev_monitor->udev, "setting SO_PASSCRED failed: %m\n"); ++ + return 0; + } + diff --git a/0294-shared-conf-parser-don-t-leak-memory-on-error-in-DEF.patch b/0294-shared-conf-parser-don-t-leak-memory-on-error-in-DEF.patch new file mode 100644 index 0000000..66c0e18 --- /dev/null +++ b/0294-shared-conf-parser-don-t-leak-memory-on-error-in-DEF.patch @@ -0,0 +1,54 @@ +From 77c10205bb337585c320e91af4b416f2dcc6faba Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 13:47:00 +0200 +Subject: [PATCH] shared: conf-parser - don't leak memory on error in + DEFINE_CONFIG_PARSE_ENUMV + +Found by Coverity. Fixes CID #1237746. +--- + src/shared/conf-parser.h | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h +index 94185152cd..62f2a01e5e 100644 +--- a/src/shared/conf-parser.h ++++ b/src/shared/conf-parser.h +@@ -169,7 +169,8 @@ int log_syntax_internal(const char *unit, int level, + void *data, \ + void *userdata) { \ + \ +- type **enums = data, *xs, x, *ys; \ ++ type **enums = data, x, *ys; \ ++ _cleanup_free_ type *xs = NULL; \ + const char *word, *state; \ + size_t l, i = 0; \ + \ +@@ -186,6 +187,7 @@ int log_syntax_internal(const char *unit, int level, + \ + FOREACH_WORD(word, l, rvalue, state) { \ + _cleanup_free_ char *en = NULL; \ ++ type *new_xs; \ + \ + en = strndup(word, l); \ + if (!en) \ +@@ -211,8 +213,10 @@ int log_syntax_internal(const char *unit, int level, + continue; \ + \ + *(xs + i) = x; \ +- xs = realloc(xs, (++i + 1) * sizeof(type)); \ +- if (!xs) \ ++ new_xs = realloc(xs, (++i + 1) * sizeof(type)); \ ++ if (new_xs) \ ++ xs = new_xs; \ ++ else \ + return -ENOMEM; \ + \ + *(xs + i) = invalid; \ +@@ -220,5 +224,7 @@ int log_syntax_internal(const char *unit, int level, + \ + free(*enums); \ + *enums = xs; \ ++ xs = NULL; \ ++ \ + return 0; \ + } diff --git a/0295-bus-fix-bus_print_property-to-use-int-for-booleans.patch b/0295-bus-fix-bus_print_property-to-use-int-for-booleans.patch new file mode 100644 index 0000000..0fd6cff --- /dev/null +++ b/0295-bus-fix-bus_print_property-to-use-int-for-booleans.patch @@ -0,0 +1,26 @@ +From c2fa048c4a70c8386c6d8fe939e5ea9edecf1e98 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 18 Sep 2014 13:28:28 +0200 +Subject: [PATCH] bus: fix bus_print_property() to use "int" for booleans + +We always use "int" if we retrieve boolean values from sd-bus, as "bool" +is only a single byte, but full int on va-args. + +Thanks to Werner Fink for the report! +--- + src/libsystemd/sd-bus/bus-util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 7c6da60cca..9018bcee5c 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -631,7 +631,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { + } + + case SD_BUS_TYPE_BOOLEAN: { +- bool b; ++ int b; + + r = sd_bus_message_read_basic(property, type, &b); + if (r < 0) diff --git a/0296-udev-fix-path-for-database-names-on-change-event.patch b/0296-udev-fix-path-for-database-names-on-change-event.patch new file mode 100644 index 0000000..a6855b9 --- /dev/null +++ b/0296-udev-fix-path-for-database-names-on-change-event.patch @@ -0,0 +1,56 @@ +From 572016d1c2c5a679ea3ac95ff15ce9f3508020f3 Mon Sep 17 00:00:00 2001 +From: Robert Milasan +Date: Sat, 13 Sep 2014 15:18:37 +0200 +Subject: [PATCH] udev: fix path for database names on 'change' event + +If a device does not have a major/minor number attached, we use different +database names than if it does. On "change" events, we didn't copy the +devnum over, therefore, we used different paths than on 'add' or 'remove' +events (where devnum was properly copied). + +Fix this by always copying the devnum into the udev-device. + +(David: added commit-log from email) +--- + src/libudev/libudev-device.c | 2 +- + src/libudev/libudev-private.h | 1 + + src/udev/udev-event.c | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c +index d61a2ad8f4..2699374072 100644 +--- a/src/libudev/libudev-device.c ++++ b/src/libudev/libudev-device.c +@@ -161,7 +161,7 @@ _public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) + return udev_device->devnum; + } + +-static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) ++int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) + { + char num[32]; + +diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h +index 2f74bc0883..7e11f7326d 100644 +--- a/src/libudev/libudev-private.h ++++ b/src/libudev/libudev-private.h +@@ -59,6 +59,7 @@ uid_t udev_device_get_devnode_uid(struct udev_device *udev_device); + gid_t udev_device_get_devnode_gid(struct udev_device *udev_device); + int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem); + int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath); ++int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum); + int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink); + void udev_device_cleanup_devlinks_list(struct udev_device *udev_device); + struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value); +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index dc1f682bfe..30a6708901 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -813,6 +813,7 @@ void udev_event_execute_rules(struct udev_event *event, + if (event->dev_db != NULL) { + udev_device_set_syspath(event->dev_db, udev_device_get_syspath(dev)); + udev_device_set_subsystem(event->dev_db, udev_device_get_subsystem(dev)); ++ udev_device_set_devnum(event->dev_db, udev_device_get_devnum(dev)); + udev_device_read_db(event->dev_db, NULL); + udev_device_set_info_loaded(event->dev_db); + diff --git a/0297-man-use-the-escape-for-in-example-instead-of-space.patch b/0297-man-use-the-escape-for-in-example-instead-of-space.patch new file mode 100644 index 0000000..314dce3 --- /dev/null +++ b/0297-man-use-the-escape-for-in-example-instead-of-space.patch @@ -0,0 +1,26 @@ +From fb7661a6020b5680d5647d3d85b0501a4f3a5042 Mon Sep 17 00:00:00 2001 +From: Michael Marineau +Date: Mon, 15 Sep 2014 14:07:39 -0700 +Subject: [PATCH] man: use the escape for "-" in example instead of space. + +This sentence can be misread to mean that "\x20" is the escape code for +"-" which is the only character explicitly mentioned. This lead to at +least one user loosing hair over why a mount unit for "/foo/bar-baz" +didn't work. The example escape is arbitrary so lets prevent hair loss. +--- + man/systemd.unit.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index 6ea552e8b4..67d46eda98 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -226,7 +226,7 @@ + result is usable as part of a filename. Basically, + given a path, "/" is replaced by "-", and all + unprintable characters and the "-" are replaced by +- C-style "\x20" escapes. The root directory "/" is ++ C-style "\x2d" escapes. The root directory "/" is + encoded as single dash, while otherwise the initial + and ending "/" is removed from all paths during + transformation. This escaping is reversible. diff --git a/0298-journal-Do-not-count-on-the-compiler-initializing-fo.patch b/0298-journal-Do-not-count-on-the-compiler-initializing-fo.patch new file mode 100644 index 0000000..45970a0 --- /dev/null +++ b/0298-journal-Do-not-count-on-the-compiler-initializing-fo.patch @@ -0,0 +1,27 @@ +From e8c108ca9f11a382742f212f5b42a02536b3d40f Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Wed, 17 Sep 2014 00:27:16 +0300 +Subject: [PATCH] journal: Do not count on the compiler initializing found_last + to false + +There is a very unlikely case where this can happen since gcc usually +does the sane thing. But let's make sure found_last is initialized anyway. + +Fixes: CID#996386 +--- + 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 6c8ca8c268..b4e8f73c41 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -804,7 +804,7 @@ int journal_file_verify( + usec_t last_usec = 0; + int data_fd = -1, entry_fd = -1, entry_array_fd = -1; + unsigned i; +- bool found_last; ++ bool found_last = false; + #ifdef HAVE_GCRYPT + uint64_t last_tag = 0; + #endif diff --git a/0299-udev-link-config-remove-unneded-linux-netdevice.h-in.patch b/0299-udev-link-config-remove-unneded-linux-netdevice.h-in.patch new file mode 100644 index 0000000..ce014f3 --- /dev/null +++ b/0299-udev-link-config-remove-unneded-linux-netdevice.h-in.patch @@ -0,0 +1,21 @@ +From 58c9846d32e55799b6e4607136a34e2727c919ac Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 18 Sep 2014 15:24:39 +0200 +Subject: [PATCH] udev: link-config: remove unneded linux/netdevice.h include + +--- + src/udev/net/link-config.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index ee2865a863..25e3cc8dfb 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -20,7 +20,6 @@ + ***/ + + #include +-#include + + #include "sd-id128.h" + diff --git a/0300-sd-rtnl-rtnl-message-remove-unneeded-linux-includes.patch b/0300-sd-rtnl-rtnl-message-remove-unneeded-linux-includes.patch new file mode 100644 index 0000000..282beb0 --- /dev/null +++ b/0300-sd-rtnl-rtnl-message-remove-unneeded-linux-includes.patch @@ -0,0 +1,26 @@ +From 1ed96046cb2143f99888383157db16cd184d4b5a Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 18 Sep 2014 15:24:40 +0200 +Subject: [PATCH] sd-rtnl: rtnl-message: remove unneeded linux includes + +--- + src/libsystemd/sd-rtnl/rtnl-message.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c +index 30e33584c4..b501a52cf1 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-message.c ++++ b/src/libsystemd/sd-rtnl/rtnl-message.c +@@ -23,12 +23,6 @@ + #include + #include + #include +-#include +-#include +-#include +-#include +-#include +-#include + + #include "util.h" + #include "refcnt.h" diff --git a/0301-include-fcntl.h-rather-than-sys-fcntl.h.patch b/0301-include-fcntl.h-rather-than-sys-fcntl.h.patch new file mode 100644 index 0000000..06de1cf --- /dev/null +++ b/0301-include-fcntl.h-rather-than-sys-fcntl.h.patch @@ -0,0 +1,22 @@ +From fdb8bd0fe7244b72ddc1c08e401ebddefdaf4f46 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 18 Sep 2014 15:24:38 +0200 +Subject: [PATCH] include fcntl.h rather than sys/fcntl.h + +--- + src/socket-proxy/socket-proxyd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c +index 81d8457fdd..ff2b24f452 100644 +--- a/src/socket-proxy/socket-proxyd.c ++++ b/src/socket-proxy/socket-proxyd.c +@@ -26,7 +26,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include diff --git a/0302-mount-order-options-before-other-arguments-to-mount.patch b/0302-mount-order-options-before-other-arguments-to-mount.patch new file mode 100644 index 0000000..3886373 --- /dev/null +++ b/0302-mount-order-options-before-other-arguments-to-mount.patch @@ -0,0 +1,39 @@ +From 141a1ceaa62578f1ed14f04cae2113dd0f49fd7f Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 18 Sep 2014 15:24:59 +0200 +Subject: [PATCH] mount: order options before other arguments to mount + +--- + src/core/mount.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index e284357c6f..f3ec7365d1 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -903,10 +903,10 @@ static void mount_enter_mounting(Mount *m) { + m->control_command, + "/bin/mount", + m->sloppy_options ? "-ns" : "-n", ++ "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", ++ "-o", m->parameters_fragment.options ? m->parameters_fragment.options : "", + m->parameters_fragment.what, + m->where, +- "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", +- m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options, + NULL); + else + r = -ENOENT; +@@ -951,10 +951,10 @@ static void mount_enter_remounting(Mount *m) { + m->control_command, + "/bin/mount", + m->sloppy_options ? "-ns" : "-n", +- m->parameters_fragment.what, +- m->where, + "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", + "-o", o, ++ m->parameters_fragment.what, ++ m->where, + NULL); + } else + r = -ENOENT; diff --git a/0303-journal-upload-Remove-compilation-warning.patch b/0303-journal-upload-Remove-compilation-warning.patch new file mode 100644 index 0000000..cbb4ebe --- /dev/null +++ b/0303-journal-upload-Remove-compilation-warning.patch @@ -0,0 +1,31 @@ +From b88a40a7e592e0a4a2e6e8eb1ed3721989ba5d0e Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Thu, 18 Sep 2014 18:56:55 +0300 +Subject: [PATCH] journal-upload: Remove compilation warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When compiling we see this curl warning popping up: +src/journal-remote/journal-upload.c:194:17: warning: call to +‘_curl_easy_setopt_err_error_buffer’ declared with attribute +warning: curl_easy_setopt expects a char buffer of CURL_ERROR_SIZE +as argument for this option [enabled by default] +This patch removes the warning (which occurs twice). +--- + src/journal-remote/journal-upload.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c +index 40c380aa9e..e16204484e 100644 +--- a/src/journal-remote/journal-upload.c ++++ b/src/journal-remote/journal-upload.c +@@ -191,7 +191,7 @@ int start_upload(Uploader *u, + easy_setopt(curl, CURLOPT_POST, 1L, + LOG_ERR, return -EXFULL); + +- easy_setopt(curl, CURLOPT_ERRORBUFFER, &u->error, ++ easy_setopt(curl, CURLOPT_ERRORBUFFER, u->error, + LOG_ERR, return -EXFULL); + + /* set where to write to */ diff --git a/0304-core-Remove-uninitialized-warnings-from-bus-endpoint.patch b/0304-core-Remove-uninitialized-warnings-from-bus-endpoint.patch new file mode 100644 index 0000000..5aed794 --- /dev/null +++ b/0304-core-Remove-uninitialized-warnings-from-bus-endpoint.patch @@ -0,0 +1,26 @@ +From 96f2f3b1b5f44eb59d23d2abeac12b33a18e1e21 Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Thu, 18 Sep 2014 18:56:56 +0300 +Subject: [PATCH] core: Remove uninitialized warnings from bus-endpoint.c + +Gcc is spewing some warnings about uninitialized variables. +Let's get rid of the noise. +--- + src/core/bus-endpoint.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c +index 1e8f07eb54..aac540ddee 100644 +--- a/src/core/bus-endpoint.c ++++ b/src/core/bus-endpoint.c +@@ -34,8 +34,8 @@ int bus_endpoint_new(BusEndpoint **ep) + + int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access) + { +- _cleanup_free_ BusEndpointPolicy *po; +- _cleanup_free_ char *key; ++ _cleanup_free_ BusEndpointPolicy *po = NULL; ++ _cleanup_free_ char *key = NULL; + int r; + + assert(ep); diff --git a/0305-sysusers-Remove-some-gcc-warnings-about-uninitialize.patch b/0305-sysusers-Remove-some-gcc-warnings-about-uninitialize.patch new file mode 100644 index 0000000..63734b6 --- /dev/null +++ b/0305-sysusers-Remove-some-gcc-warnings-about-uninitialize.patch @@ -0,0 +1,27 @@ +From 56d21cdebce3ecd3b06189cb2184a84ba909619f Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Thu, 18 Sep 2014 18:56:57 +0300 +Subject: [PATCH] sysusers: Remove some gcc warnings about uninitialized + variables + +Gcc is spewing some warnings about uninitialized variables. +Let's get rid of the noise. +--- + src/sysusers/sysusers.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c +index ba20d949dc..4203b3e017 100644 +--- a/src/sysusers/sysusers.c ++++ b/src/sysusers/sysusers.c +@@ -796,8 +796,8 @@ static int root_stat(const char *p, struct stat *st) { + static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) { + struct stat st; + bool found_uid = false, found_gid = false; +- uid_t uid; +- gid_t gid; ++ uid_t uid = 0; ++ gid_t gid = 0; + + assert(i); + diff --git a/0306-journal-remote-check-return-code-of-sd_event_default.patch b/0306-journal-remote-check-return-code-of-sd_event_default.patch new file mode 100644 index 0000000..d4428f7 --- /dev/null +++ b/0306-journal-remote-check-return-code-of-sd_event_default.patch @@ -0,0 +1,30 @@ +From b1604b341bcd190d67894f416d842990a082a4a4 Mon Sep 17 00:00:00 2001 +From: Andreas Henriksson +Date: Thu, 18 Sep 2014 17:52:54 +0200 +Subject: [PATCH] journal-remote: check return code of sd_event_default + +Handle sd_event_default returning error and bail out properly +as done in every other caller of this function. + +Found by coverity. Fixes: CID#1238957 +--- + src/journal-remote/journal-remote.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index 12de820330..f06c2cb249 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -808,7 +808,11 @@ static int remoteserver_init(RemoteServer *s, + return -EINVAL; + } + +- sd_event_default(&s->events); ++ r = sd_event_default(&s->events); ++ if (r < 0) { ++ log_error("Failed to allocate event loop: %s", strerror(-r)); ++ return r; ++ } + + setup_signals(s); + diff --git a/0307-udevd-parse_argv-warn-if-argumens-are-invalid.patch b/0307-udevd-parse_argv-warn-if-argumens-are-invalid.patch new file mode 100644 index 0000000..a680e34 --- /dev/null +++ b/0307-udevd-parse_argv-warn-if-argumens-are-invalid.patch @@ -0,0 +1,43 @@ +From 6f5cf8a8b1de763383f7382821147e538b7dbd6d Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 19:02:03 +0200 +Subject: [PATCH] udevd: parse_argv - warn if argumens are invalid + +Found by Coverity. Fixes CID #1238780. +--- + src/udev/udevd.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index cd517931d3..95c6468029 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1048,17 +1048,23 @@ static int parse_argv(int argc, char *argv[]) { + arg_daemonize = true; + break; + case 'c': +- safe_atoi(optarg, &arg_children_max); ++ r = safe_atoi(optarg, &arg_children_max); ++ if (r < 0) ++ log_warning("Invalid --children-max ignored: %s", optarg); + break; + case 'e': +- safe_atoi(optarg, &arg_exec_delay); ++ r = safe_atoi(optarg, &arg_exec_delay); ++ if (r < 0) ++ log_warning("Invalid --exec-delay ignored: %s", optarg); + break; + case 't': + r = safe_atou64(optarg, &arg_event_timeout_usec); + if (r < 0) +- break; +- arg_event_timeout_usec *= USEC_PER_SEC; +- arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; ++ log_warning("Invalig --event-timeout ignored: %s", optarg); ++ else { ++ arg_event_timeout_usec *= USEC_PER_SEC; ++ arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; ++ } + break; + case 'D': + arg_debug = true; diff --git a/0308-udevd-check-return-of-various-functions.patch b/0308-udevd-check-return-of-various-functions.patch new file mode 100644 index 0000000..01c0341 --- /dev/null +++ b/0308-udevd-check-return-of-various-functions.patch @@ -0,0 +1,44 @@ +From d457ff8319b1e7c522c146f75e272f1226f4720c Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 19:07:02 +0200 +Subject: [PATCH] udevd: check return of various functions + +One reported by Coverity. Fixes CID #996252. +--- + src/udev/udevd.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 95c6468029..9210da6c47 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1139,13 +1139,26 @@ int main(int argc, char *argv[]) { + goto exit; + } + +- label_init("/dev"); ++ r = label_init("/dev"); ++ if (r < 0) { ++ log_error("could not initialize labelling: %s", strerror(-r)); ++ goto exit; ++ } + + /* set umask before creating any file/directory */ +- chdir("/"); ++ r = chdir("/"); ++ if (r < 0) { ++ log_error("could not change dir to /: %m"); ++ goto exit; ++ } ++ + umask(022); + +- mkdir("/run/udev", 0755); ++ r = mkdir("/run/udev", 0755); ++ if (r < 0) { ++ log_error("could not create /run/udev: %m"); ++ goto exit; ++ } + + dev_setup(NULL); + diff --git a/0309-udevadm-hwdb-check-return-value-of-fseeko.patch b/0309-udevadm-hwdb-check-return-value-of-fseeko.patch new file mode 100644 index 0000000..62863e5 --- /dev/null +++ b/0309-udevadm-hwdb-check-return-value-of-fseeko.patch @@ -0,0 +1,42 @@ +From f901aaadd68050bc575c1c15b84f8f31fd4d494d Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 19:16:54 +0200 +Subject: [PATCH] udevadm: hwdb - check return value of fseeko() + +Fonud by Coverity. Fixes CID #996255. +--- + src/udev/udevadm-hwdb.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c +index 65cbf61865..64273fbe8d 100644 +--- a/src/udev/udevadm-hwdb.c ++++ b/src/udev/udevadm-hwdb.c +@@ -365,7 +365,12 @@ static int trie_store(struct trie *trie, const char *filename) { + fchmod(fileno(t.f), 0444); + + /* write nodes */ +- fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET); ++ err = fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET); ++ if (err < 0) { ++ fclose(t.f); ++ unlink_noerrno(filename_tmp); ++ return -errno; ++ } + root_off = trie_store_nodes(&t, trie->root); + h.nodes_root_off = htole64(root_off); + pos = ftello(t.f); +@@ -378,7 +383,12 @@ static int trie_store(struct trie *trie, const char *filename) { + /* write header */ + size = ftello(t.f); + h.file_size = htole64(size); +- fseeko(t.f, 0, SEEK_SET); ++ err = fseeko(t.f, 0, SEEK_SET); ++ if (err < 0) { ++ fclose(t.f); ++ unlink_noerrno(filename_tmp); ++ return -errno; ++ } + fwrite(&h, sizeof(struct trie_header_f), 1, t.f); + err = ferror(t.f); + if (err) diff --git a/0310-udev-node-warn-if-chmod-chown-fails.patch b/0310-udev-node-warn-if-chmod-chown-fails.patch new file mode 100644 index 0000000..9c4dd91 --- /dev/null +++ b/0310-udev-node-warn-if-chmod-chown-fails.patch @@ -0,0 +1,31 @@ +From 543afdc63c02a5af3cf6bd2a264162f23474346a Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 19:22:09 +0200 +Subject: [PATCH] udev: node - warn if chmod/chown fails + +No functional change, just log the warning. + +Fonud by Coverity. Fixes CID #1237544. +--- + src/udev/udev-node.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c +index c164603795..8ef788954d 100644 +--- a/src/udev/udev-node.c ++++ b/src/udev/udev-node.c +@@ -281,8 +281,12 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, + + if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { + log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); +- chmod(devnode, mode); +- chown(devnode, uid, gid); ++ err = chmod(devnode, mode); ++ if (err < 0) ++ log_warning("setting mode of %s to %#o failed: %m", devnode, mode); ++ err = chown(devnode, uid, gid); ++ if (err < 0) ++ log_warning("setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid); + } else { + log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); + } diff --git a/0311-udev-ctrl-log-if-setting-SO_PASSCRED-fails.patch b/0311-udev-ctrl-log-if-setting-SO_PASSCRED-fails.patch new file mode 100644 index 0000000..f14510c --- /dev/null +++ b/0311-udev-ctrl-log-if-setting-SO_PASSCRED-fails.patch @@ -0,0 +1,47 @@ +From 4bbdff757ed4e718a3348b93439a03055cc5e3bc Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 19:26:11 +0200 +Subject: [PATCH] udev: ctrl - log if setting SO_PASSCRED fails + +No functional change. + +Found by Coverity. Fixes CID #1237533. +--- + src/udev/udev-ctrl.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c +index 6fb5bb4a7a..d02147f0f2 100644 +--- a/src/udev/udev-ctrl.c ++++ b/src/udev/udev-ctrl.c +@@ -73,6 +73,7 @@ struct udev_ctrl_connection { + struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) { + struct udev_ctrl *uctrl; + const int on = 1; ++ int r; + + uctrl = new0(struct udev_ctrl, 1); + if (uctrl == NULL) +@@ -91,7 +92,9 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) { + uctrl->bound = true; + uctrl->sock = fd; + } +- setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); ++ r = setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); ++ if (r < 0) ++ log_warning("could not set SO_PASSCRED: %m"); + + uctrl->saddr.sun_family = AF_LOCAL; + strscpy(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path), "/run/udev/control"); +@@ -200,7 +203,10 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) { + } + + /* enable receiving of the sender credentials in the messages */ +- setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); ++ r = setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); ++ if (r < 0) ++ log_warning("colud not set SO_PASSCRED: %m"); ++ + udev_ctrl_ref(uctrl); + return conn; + err: diff --git a/0312-udev-fix-typos.patch b/0312-udev-fix-typos.patch new file mode 100644 index 0000000..7edcfb8 --- /dev/null +++ b/0312-udev-fix-typos.patch @@ -0,0 +1,37 @@ +From 65fea570f03df51dadc06a3e0d261a71fe62aa01 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 20:25:33 +0200 +Subject: [PATCH] udev: fix typos + +Spotted by Andreas Henriksson. +--- + src/udev/udev-ctrl.c | 2 +- + src/udev/udevd.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c +index d02147f0f2..98fd3a9acf 100644 +--- a/src/udev/udev-ctrl.c ++++ b/src/udev/udev-ctrl.c +@@ -205,7 +205,7 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) { + /* enable receiving of the sender credentials in the messages */ + r = setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + if (r < 0) +- log_warning("colud not set SO_PASSCRED: %m"); ++ log_warning("could not set SO_PASSCRED: %m"); + + udev_ctrl_ref(uctrl); + return conn; +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 9210da6c47..37db81c8bb 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1060,7 +1060,7 @@ static int parse_argv(int argc, char *argv[]) { + case 't': + r = safe_atou64(optarg, &arg_event_timeout_usec); + if (r < 0) +- log_warning("Invalig --event-timeout ignored: %s", optarg); ++ log_warning("Invalid --event-timeout ignored: %s", optarg); + else { + arg_event_timeout_usec *= USEC_PER_SEC; + arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; diff --git a/0313-udevd-don-t-fail-if-run-udev-exists.patch b/0313-udevd-don-t-fail-if-run-udev-exists.patch new file mode 100644 index 0000000..b43d2c2 --- /dev/null +++ b/0313-udevd-don-t-fail-if-run-udev-exists.patch @@ -0,0 +1,22 @@ +From 25773e7fc59b4ce53d67da4e18bfe4d13ab0b14b Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 21:57:49 +0200 +Subject: [PATCH] udevd: don't fail if /run/udev exists + +--- + src/udev/udevd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index 37db81c8bb..29ccb518e6 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1155,7 +1155,7 @@ int main(int argc, char *argv[]) { + umask(022); + + r = mkdir("/run/udev", 0755); +- if (r < 0) { ++ if (r < 0 && errno != EEXIST) { + log_error("could not create /run/udev: %m"); + goto exit; + } diff --git a/0314-timesyncd-check-return-of-setting-IP_TOS.patch b/0314-timesyncd-check-return-of-setting-IP_TOS.patch new file mode 100644 index 0000000..62b5d00 --- /dev/null +++ b/0314-timesyncd-check-return-of-setting-IP_TOS.patch @@ -0,0 +1,25 @@ +From 2f905e821e0342c36f5a5d3a51d53aabccc800bd Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 18 Sep 2014 23:37:07 +0200 +Subject: [PATCH] timesyncd: check return of setting IP_TOS + +Fonud by Coverity. Fixes CID #1237534. +--- + src/timesync/timesyncd-manager.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index a5678ccaed..46f8bd6d81 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -721,7 +721,9 @@ static int manager_listen_setup(Manager *m) { + if (r < 0) + return -errno; + +- setsockopt(m->server_socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); ++ r = setsockopt(m->server_socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); ++ if (r < 0) ++ return -errno; + + return sd_event_add_io(m->event, &m->event_receive, m->server_socket, EPOLLIN, manager_receive_response, m); + } diff --git a/0315-nss-remove-dead-code.patch b/0315-nss-remove-dead-code.patch new file mode 100644 index 0000000..87da1a9 --- /dev/null +++ b/0315-nss-remove-dead-code.patch @@ -0,0 +1,63 @@ +From 66a16e7e9fc501d371b57cbe2ae5d130fe930c6d Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Thu, 18 Sep 2014 23:55:46 +0200 +Subject: [PATCH] nss: remove dead code + +c > 0 is already guaranteed from earlier checks. + +We go from + +ms = ALIGN(l+1) + + sizeof(char*) + + (c > 0 ? c : 1) * ALIGN(alen) + + (c > 0 ? c+1 : 2) * sizeof(char*); + +to + +ms = ALIGN(l+1) + + sizeof(char*) + + c * ALIGN(alen) + + (c+1) * sizeof(char*); + +to + +ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); + +Found by coverity. Fixes: CID#1237570 and CID#1237610 +--- + src/nss-mymachines/nss-mymachines.c | 5 +---- + src/nss-resolve/nss-resolve.c | 5 +---- + 2 files changed, 2 insertions(+), 8 deletions(-) + +diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c +index abeb8253c3..9476ad1694 100644 +--- a/src/nss-mymachines/nss-mymachines.c ++++ b/src/nss-mymachines/nss-mymachines.c +@@ -289,10 +289,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r( + alen = FAMILY_ADDRESS_SIZE(af); + l = strlen(name); + +- ms = ALIGN(l+1) + +- sizeof(char*) + +- (c > 0 ? c : 1) * ALIGN(alen) + +- (c > 0 ? c+1 : 2) * sizeof(char*); ++ ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); + + if (buflen < ms) { + *errnop = ENOMEM; +diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c +index 39b73203d2..6a029a331b 100644 +--- a/src/nss-resolve/nss-resolve.c ++++ b/src/nss-resolve/nss-resolve.c +@@ -404,10 +404,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( + alen = FAMILY_ADDRESS_SIZE(af); + l = strlen(canonical); + +- ms = ALIGN(l+1) + +- sizeof(char*) + +- (c > 0 ? c : 1) * ALIGN(alen) + +- (c > 0 ? c+1 : 2) * sizeof(char*); ++ ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); + + if (buflen < ms) { + *errnop = ENOMEM; diff --git a/0316-pty-include-linux-ioctl.h-for-TIOCSIG.patch b/0316-pty-include-linux-ioctl.h-for-TIOCSIG.patch new file mode 100644 index 0000000..061e915 --- /dev/null +++ b/0316-pty-include-linux-ioctl.h-for-TIOCSIG.patch @@ -0,0 +1,24 @@ +From fb1f4170d008315cb9eabe994038977a0366ede5 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 19 Sep 2014 00:23:42 +0200 +Subject: [PATCH] pty: include linux/ioctl.h for TIOCSIG + +TIOCSIG is linux specific, so include the linux ioctl header to make sure +it's defined. We currently rely on some rather non-obvious recursive +includes. Make sure its always defined regardless of the system headers. +--- + src/shared/pty.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/pty.c b/src/shared/pty.c +index 2863da489c..31123e5af2 100644 +--- a/src/shared/pty.c ++++ b/src/shared/pty.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/0317-shared-label.h-add-missing-stdio.h-include.patch b/0317-shared-label.h-add-missing-stdio.h-include.patch new file mode 100644 index 0000000..1312e6d --- /dev/null +++ b/0317-shared-label.h-add-missing-stdio.h-include.patch @@ -0,0 +1,21 @@ +From 45f15021e3524b04d574b9ff4e801cb3219daf3f Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 18 Sep 2014 15:24:42 +0200 +Subject: [PATCH] shared/label.h: add missing stdio.h include + +--- + src/shared/label.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/label.h b/src/shared/label.h +index 72948205f6..cb2ec79eea 100644 +--- a/src/shared/label.h ++++ b/src/shared/label.h +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + int label_init(const char *prefix); + void label_finish(void); diff --git a/0318-shared-sparse-endian.h-add-missing-byteswap.h-includ.patch b/0318-shared-sparse-endian.h-add-missing-byteswap.h-includ.patch new file mode 100644 index 0000000..4c9e7b6 --- /dev/null +++ b/0318-shared-sparse-endian.h-add-missing-byteswap.h-includ.patch @@ -0,0 +1,21 @@ +From 8e8af4cfc7fa373504a22e58966909161acfb72f Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Thu, 18 Sep 2014 15:24:43 +0200 +Subject: [PATCH] shared/sparse-endian.h: add missing byteswap.h include + +--- + src/shared/sparse-endian.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/sparse-endian.h b/src/shared/sparse-endian.h +index eb4dbf3615..c913fda8c5 100644 +--- a/src/shared/sparse-endian.h ++++ b/src/shared/sparse-endian.h +@@ -21,6 +21,7 @@ + #ifndef SPARSE_ENDIAN_H + #define SPARSE_ENDIAN_H + ++#include + #include + #include + diff --git a/0319-test-warn-if-we-could-not-parse-the-loop-count-argum.patch b/0319-test-warn-if-we-could-not-parse-the-loop-count-argum.patch new file mode 100644 index 0000000..1a6de4c --- /dev/null +++ b/0319-test-warn-if-we-could-not-parse-the-loop-count-argum.patch @@ -0,0 +1,29 @@ +From cbb452e7ef4419666af7ad343786ee54c23dd977 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Fri, 19 Sep 2014 01:43:04 +0200 +Subject: [PATCH] test: warn if we could not parse the loop count argument + +Found by coverity. Fixes: CID#1237512 +--- + src/journal/test-journal-init.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c +index ada2f6c3e4..11fb150fe8 100644 +--- a/src/journal/test-journal-init.c ++++ b/src/journal/test-journal-init.c +@@ -31,8 +31,12 @@ int main(int argc, char *argv[]) { + + log_set_max_level(LOG_DEBUG); + +- if (argc >= 2) +- safe_atoi(argv[1], &I); ++ if (argc >= 2) { ++ r = safe_atoi(argv[1], &I); ++ if (r < 0) ++ log_info("Could not parse loop count argument. Using default."); ++ } ++ + log_info("Running %d loops", I); + + assert_se(mkdtemp(t)); diff --git a/0320-shared-wtmp-utmp-don-t-clear-store_wtmp-in-utmp_put_.patch b/0320-shared-wtmp-utmp-don-t-clear-store_wtmp-in-utmp_put_.patch new file mode 100644 index 0000000..589cd9a --- /dev/null +++ b/0320-shared-wtmp-utmp-don-t-clear-store_wtmp-in-utmp_put_.patch @@ -0,0 +1,103 @@ +From 863f3ce0d050f005839f6aa41fe7bac5478a7b5e Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 19 Sep 2014 08:03:31 +0200 +Subject: [PATCH] shared: wtmp-utmp - don't clear store_wtmp in + utmp_put_dead_process() + +Also modernize a few other things and add comments to explain CID #1237503 +and CID #1237504. +--- + src/shared/utmp-wtmp.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c +index 30a0c031f3..31f13ec808 100644 +--- a/src/shared/utmp-wtmp.c ++++ b/src/shared/utmp-wtmp.c +@@ -92,8 +92,6 @@ int utmp_get_runlevel(int *runlevel, int *previous) { + static void init_timestamp(struct utmpx *store, usec_t t) { + assert(store); + +- zero(*store); +- + if (t <= 0) + t = now(CLOCK_REALTIME); + +@@ -143,7 +141,7 @@ static int write_entry_wtmp(const struct utmpx *store) { + assert(store); + + /* wtmp is a simple append-only file where each entry is +- simply appended to * the end; i.e. basically a log. */ ++ simply appended to the end; i.e. basically a log. */ + + errno = 0; + updwtmpx(_PATH_WTMPX, store); +@@ -172,7 +170,7 @@ static int write_entry_both(const struct utmpx *store) { + } + + int utmp_put_shutdown(void) { +- struct utmpx store; ++ struct utmpx store = {}; + + init_entry(&store, 0); + +@@ -183,7 +181,7 @@ int utmp_put_shutdown(void) { + } + + int utmp_put_reboot(usec_t t) { +- struct utmpx store; ++ struct utmpx store = {}; + + init_entry(&store, t); + +@@ -206,16 +204,17 @@ _pure_ static const char *sanitize_id(const char *id) { + } + + int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) { +- struct utmpx store; ++ struct utmpx store = { ++ .ut_type = INIT_PROCESS, ++ .ut_pid = pid, ++ .ut_session = sid, ++ }; + + assert(id); + + init_timestamp(&store, 0); + +- store.ut_type = INIT_PROCESS; +- store.ut_pid = pid; +- store.ut_session = sid; +- ++ /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */ + strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id)); + + if (line) +@@ -225,14 +224,15 @@ int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line + } + + int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) { +- struct utmpx lookup, store, store_wtmp, *found; ++ struct utmpx lookup = { ++ .ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */ ++ }, store, store_wtmp, *found; + + assert(id); + + setutxent(); + +- zero(lookup); +- lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */ ++ /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */ + strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id)); + + found = getutxid(&lookup); +@@ -260,7 +260,7 @@ int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) { + + + int utmp_put_runlevel(int runlevel, int previous) { +- struct utmpx store; ++ struct utmpx store = {}; + int r; + + assert(runlevel > 0); diff --git a/0321-socket-introduce-SELinuxContextFromNet-option.patch b/0321-socket-introduce-SELinuxContextFromNet-option.patch new file mode 100644 index 0000000..a07b644 --- /dev/null +++ b/0321-socket-introduce-SELinuxContextFromNet-option.patch @@ -0,0 +1,397 @@ +From 16115b0a7b7cdf08fb38084d857d572d8a9088dc Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 24 Jul 2014 10:40:28 +0200 +Subject: [PATCH] socket: introduce SELinuxContextFromNet option + +This makes possible to spawn service instances triggered by socket with +MLS/MCS SELinux labels which are created based on information provided by +connected peer. + +Implementation of label_get_child_mls_label derived from xinetd. + +Reviewed-by: Paul Moore +--- + man/systemd.socket.xml | 26 ++++++++ + src/core/execute.c | 29 +++++++-- + src/core/execute.h | 1 + + src/core/load-fragment-gperf.gperf.m4 | 3 + + src/core/service.c | 4 +- + src/core/service.h | 3 +- + src/core/socket.c | 16 +++-- + src/core/socket.h | 2 + + src/shared/label.c | 113 ++++++++++++++++++++++++++++++++++ + src/shared/label.h | 2 + + 10 files changed, 187 insertions(+), 12 deletions(-) + +diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml +index 7a63348caf..dad0267467 100644 +--- a/man/systemd.socket.xml ++++ b/man/systemd.socket.xml +@@ -676,6 +676,32 @@ + + + ++ SELinuxContextFromNet= ++ Takes a boolean ++ argument. When true systemd will attempt ++ to figure out the SELinux label used ++ for the instantiated service from the ++ information handed by the peer over the ++ network. Note that only the security ++ level is used from the information ++ provided by the peer. Other parts of ++ the resulting SELinux context originate ++ from either the target binary that is ++ effectively triggered by socket unit ++ are taken from the value of the ++ SELinuxContext= ++ option.This configuration option only ++ affects sockets with ++ Accept= mode set to ++ true. Also note that ++ this option is useful only when ++ MLS/MCS SELinux policy is ++ deployed. Defaults to ++ false. ++ ++ ++ ++ + PipeSize= + Takes a size in + bytes. Controls the pipe buffer size +diff --git a/src/core/execute.c b/src/core/execute.c +index db755777c1..8c9dfde00a 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -84,6 +84,7 @@ + #include "mkdir.h" + #include "apparmor-util.h" + #include "bus-kernel.h" ++#include "label.h" + + #ifdef HAVE_SECCOMP + #include "seccomp-util.h" +@@ -1665,11 +1666,29 @@ static int exec_child(ExecCommand *command, + #endif + + #ifdef HAVE_SELINUX +- if (context->selinux_context && use_selinux()) { +- err = setexeccon(context->selinux_context); +- if (err < 0 && !context->selinux_context_ignore) { +- *error = EXIT_SELINUX_CONTEXT; +- return err; ++ if (use_selinux()) { ++ if (context->selinux_context) { ++ err = setexeccon(context->selinux_context); ++ if (err < 0 && !context->selinux_context_ignore) { ++ *error = EXIT_SELINUX_CONTEXT; ++ return err; ++ } ++ } ++ ++ if (params->selinux_context_net && socket_fd >= 0) { ++ _cleanup_free_ char *label = NULL; ++ ++ err = label_get_child_mls_label(socket_fd, command->path, &label); ++ if (err < 0) { ++ *error = EXIT_SELINUX_CONTEXT; ++ return err; ++ } ++ ++ err = setexeccon(label); ++ if (err < 0) { ++ *error = EXIT_SELINUX_CONTEXT; ++ return err; ++ } + } + } + #endif +diff --git a/src/core/execute.h b/src/core/execute.h +index 9c1f249cd4..6f35736eda 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -204,6 +204,7 @@ struct ExecParameters { + bool apply_chroot; + bool apply_tty_stdin; + bool confirm_spawn; ++ bool selinux_context_net; + CGroupControllerMask cgroup_supported; + const char *cgroup_path; + const char *runtime_prefix; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index e764d68ce4..050c5d819f 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -265,6 +265,9 @@ Socket.SmackLabelIPOut, config_parse_string, 0, + `Socket.SmackLabel, config_parse_warn_compat, 0, 0 + Socket.SmackLabelIPIn, config_parse_warn_compat, 0, 0 + Socket.SmackLabelIPOut, config_parse_warn_compat, 0, 0') ++m4_ifdef(`HAVE_SELINUX', ++`Socket.SELinuxContextFromNet, config_parse_bool, 0, offsetof(Socket, selinux_context_from_net)', ++`Socket.SELinuxContextFromNet, config_parse_warn_compat, 0, 0') + EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl + CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl + KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl +diff --git a/src/core/service.c b/src/core/service.c +index 3f6595c5c8..395e0ca8c6 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -901,6 +901,7 @@ static int service_spawn( + .apply_chroot = apply_chroot, + .apply_tty_stdin = apply_tty_stdin, + .bus_endpoint_fd = -1, ++ .selinux_context_net = s->socket_fd_selinux_context_net + }; + + assert(s); +@@ -2748,7 +2749,7 @@ static void service_bus_name_owner_change( + } + } + +-int service_set_socket_fd(Service *s, int fd, Socket *sock) { ++int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context_net) { + _cleanup_free_ char *peer = NULL; + int r; + +@@ -2786,6 +2787,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) { + } + + s->socket_fd = fd; ++ s->socket_fd_selinux_context_net = selinux_context_net; + + unit_ref_set(&s->accept_socket, UNIT(sock)); + +diff --git a/src/core/service.h b/src/core/service.h +index ad0b3b381e..0db0c4d64c 100644 +--- a/src/core/service.h ++++ b/src/core/service.h +@@ -161,6 +161,7 @@ struct Service { + + pid_t main_pid, control_pid; + int socket_fd; ++ bool socket_fd_selinux_context_net; + + int bus_endpoint_fd; + +@@ -205,7 +206,7 @@ extern const UnitVTable service_vtable; + + struct Socket; + +-int service_set_socket_fd(Service *s, int fd, struct Socket *socket); ++int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net); + + const char* service_state_to_string(ServiceState i) _const_; + ServiceState service_state_from_string(const char *s) _pure_; +diff --git a/src/core/socket.c b/src/core/socket.c +index 68e21e60ac..00d5fd1192 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -489,7 +489,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { + "%sPassCredentials: %s\n" + "%sPassSecurity: %s\n" + "%sTCPCongestion: %s\n" +- "%sRemoveOnStop: %s\n", ++ "%sRemoveOnStop: %s\n" ++ "%sSELinuxContextFromNet: %s\n", + prefix, socket_state_to_string(s->state), + prefix, socket_result_to_string(s->result), + prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only), +@@ -504,7 +505,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { + prefix, yes_no(s->pass_cred), + prefix, yes_no(s->pass_sec), + prefix, strna(s->tcp_congestion), +- prefix, yes_no(s->remove_on_stop)); ++ prefix, yes_no(s->remove_on_stop), ++ prefix, yes_no(s->selinux_context_from_net)); + + if (s->control_pid > 0) + fprintf(f, +@@ -1128,8 +1130,12 @@ static int socket_open_fds(Socket *s) { + continue; + + if (p->type == SOCKET_SOCKET) { +- +- if (!know_label) { ++ if (!know_label && s->selinux_context_from_net) { ++ r = label_get_our_label(&label); ++ if (r < 0) ++ return r; ++ know_label = true; ++ } else if (!know_label) { + + r = socket_instantiate_service(s); + if (r < 0) +@@ -1821,7 +1827,7 @@ static void socket_enter_running(Socket *s, int cfd) { + + unit_choose_id(UNIT(service), name); + +- r = service_set_socket_fd(service, cfd, s); ++ r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net); + if (r < 0) + goto fail; + +diff --git a/src/core/socket.h b/src/core/socket.h +index eede70564a..a2e08998c0 100644 +--- a/src/core/socket.h ++++ b/src/core/socket.h +@@ -165,6 +165,8 @@ struct Socket { + char *smack_ip_in; + char *smack_ip_out; + ++ bool selinux_context_from_net; ++ + char *user, *group; + }; + +diff --git a/src/shared/label.c b/src/shared/label.c +index 25a8b361b7..02b41f02d8 100644 +--- a/src/shared/label.c ++++ b/src/shared/label.c +@@ -31,6 +31,7 @@ + #ifdef HAVE_SELINUX + #include + #include ++#include + #endif + + #include "label.h" +@@ -41,6 +42,12 @@ + #include "smack-util.h" + + #ifdef HAVE_SELINUX ++DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon); ++DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free); ++ ++#define _cleanup_security_context_free_ _cleanup_(freeconp) ++#define _cleanup_context_free_ _cleanup_(context_freep) ++ + static struct selabel_handle *label_hnd = NULL; + #endif + +@@ -243,6 +250,112 @@ fail: + return r; + } + ++int label_get_our_label(char **label) { ++ int r = -EOPNOTSUPP; ++ char *l = NULL; ++ ++#ifdef HAVE_SELINUX ++ r = getcon(&l); ++ if (r < 0) ++ return r; ++ ++ *label = l; ++#endif ++ ++ return r; ++} ++ ++int label_get_child_mls_label(int socket_fd, const char *exe, char **label) { ++ int r = -EOPNOTSUPP; ++ ++#ifdef HAVE_SELINUX ++ ++ _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL, ret = NULL; ++ _cleanup_context_free_ context_t pcon = NULL, bcon = NULL; ++ security_class_t sclass; ++ ++ const char *range = NULL; ++ ++ assert(socket_fd >= 0); ++ assert(exe); ++ assert(label); ++ ++ r = getcon(&mycon); ++ if (r < 0) { ++ r = -EINVAL; ++ goto out; ++ } ++ ++ r = getpeercon(socket_fd, &peercon); ++ if (r < 0) { ++ r = -EINVAL; ++ goto out; ++ } ++ ++ r = getexeccon(&fcon); ++ if (r < 0) { ++ r = -EINVAL; ++ goto out; ++ } ++ ++ if (!fcon) { ++ /* If there is no context set for next exec let's use context ++ of target executable */ ++ r = getfilecon(exe, &fcon); ++ if (r < 0) { ++ r = -errno; ++ goto out; ++ } ++ } ++ ++ bcon = context_new(mycon); ++ if (!bcon) { ++ r = -ENOMEM; ++ goto out; ++ } ++ ++ pcon = context_new(peercon); ++ if (!pcon) { ++ r = -ENOMEM; ++ goto out; ++ } ++ ++ range = context_range_get(pcon); ++ if (!range) { ++ r = -errno; ++ goto out; ++ } ++ ++ r = context_range_set(bcon, range); ++ if (r) { ++ r = -errno; ++ goto out; ++ } ++ ++ freecon(mycon); ++ mycon = context_str(bcon); ++ if (!mycon) { ++ r = -errno; ++ goto out; ++ } ++ ++ sclass = string_to_security_class("process"); ++ r = security_compute_create(mycon, fcon, sclass, &ret); ++ if (r < 0) { ++ r = -EINVAL; ++ goto out; ++ } ++ ++ *label = ret; ++ r = 0; ++ ++out: ++ if (r < 0 && security_getenforce() == 1) ++ return r; ++#endif ++ return r; ++} ++ + int label_context_set(const char *path, mode_t mode) { + int r = 0; + +diff --git a/src/shared/label.h b/src/shared/label.h +index cb2ec79eea..ce1e5c3f57 100644 +--- a/src/shared/label.h ++++ b/src/shared/label.h +@@ -40,6 +40,8 @@ void label_context_clear(void); + void label_free(const char *label); + + int label_get_create_label_from_exe(const char *exe, char **label); ++int label_get_our_label(char **label); ++int label_get_child_mls_label(int socket_fd, const char *exec, char **label); + + int label_mkdir(const char *path, mode_t mode); + diff --git a/0322-login-pause-devices-before-acknowledging-VT-switches.patch b/0322-login-pause-devices-before-acknowledging-VT-switches.patch new file mode 100644 index 0000000..e9b1cad --- /dev/null +++ b/0322-login-pause-devices-before-acknowledging-VT-switches.patch @@ -0,0 +1,88 @@ +From 2ec3ff668ff03410e94cfef8e3ee9384a8222211 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 19 Sep 2014 13:26:39 +0200 +Subject: [PATCH] login: pause devices before acknowledging VT switches + +If a session controller does not need synchronous VT switches, we allow +them to pass VT control to logind, which acknowledges all VT switches +unconditionally. This works fine with all sessions using the dbus API, +but causes out-of-sync device use if we switch to legacy sessions that +are notified via VT signals. Those are processed before logind notices +the session-switch via sysfs. Therefore, leaving the old session still +active for a short amount of time. + +This, in fact, may cause the legacy session to prepare graphics devices +before the old session was deactivated, and thus, maybe causing the old +session to interfer with graphics device usage. + +Fix this by releasing devices immediately before acknowledging VT +switches. This way, sessions without VT handlers are required to support +async session switching (which they do in that case, anyway). +--- + src/login/logind-session.c | 21 +++++++++++++++++++++ + src/login/logind-session.h | 1 + + src/login/logind.c | 4 ++-- + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index eeb58c9031..477ac9ab1b 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -1053,6 +1053,27 @@ void session_restore_vt(Session *s) { + s->vtfd = safe_close(s->vtfd); + } + ++void session_leave_vt(Session *s) { ++ assert(s); ++ ++ /* This is called whenever we get a VT-switch signal from the kernel. ++ * We acknowledge all of them unconditionally. Note that session are ++ * free to overwrite those handlers and we only register them for ++ * sessions with controllers. Legacy sessions are not affected. ++ * However, if we switch from a non-legacy to a legacy session, we must ++ * make sure to pause all device before acknowledging the switch. We ++ * process the real switch only after we are notified via sysfs, so the ++ * legacy session might have already started using the devices. If we ++ * don't pause the devices before the switch, we might confuse the ++ * session we switch to. */ ++ ++ if (s->vtfd < 0) ++ return; ++ ++ session_device_pause_all(s); ++ ioctl(s->vtfd, VT_RELDISP, 1); ++} ++ + bool session_is_controller(Session *s, const char *sender) { + assert(s); + +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 9fb0188a84..a007fb5e84 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -174,6 +174,7 @@ KillWho kill_who_from_string(const char *s) _pure_; + + int session_prepare_vt(Session *s); + void session_restore_vt(Session *s); ++void session_leave_vt(Session *s); + + bool session_is_controller(Session *s, const char *sender); + int session_set_controller(Session *s, const char *sender, bool force); +diff --git a/src/login/logind.c b/src/login/logind.c +index f1b6a86298..8f00c46339 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -750,11 +750,11 @@ static int manager_vt_switch(sd_event_source *src, const struct signalfd_siginfo + } + + if (active->vtfd >= 0) { +- ioctl(active->vtfd, VT_RELDISP, 1); ++ session_leave_vt(active); + } else { + LIST_FOREACH(sessions_by_seat, iter, m->seat0->sessions) { + if (iter->vtnr == active->vtnr && iter->vtfd >= 0) { +- ioctl(iter->vtfd, VT_RELDISP, 1); ++ session_leave_vt(iter); + break; + } + } diff --git a/0323-terminal-add-graphics-interface.patch b/0323-terminal-add-graphics-interface.patch new file mode 100644 index 0000000..d4bbcdd --- /dev/null +++ b/0323-terminal-add-graphics-interface.patch @@ -0,0 +1,1722 @@ +From 650c5444273993f969b9cd7df9add6ab2df0414e Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 19 Sep 2014 14:05:52 +0200 +Subject: [PATCH] terminal: add graphics interface + +The grdev layer provides graphics-device access via the +libsystemd-terminal library. It will be used by all terminal helpers to +actually access display hardware. + +Like idev, the grdev layer is built around session objects. On each +session object you add/remove graphics devices as they appear and vanish. +Any device type can be supported via specific card-backends. The exported +grdev API hides any device details. + +Graphics devices are represented by "cards". Those are hidden in the +session and any pipe-configuration is automatically applied. Out of those, +we configure displays which are then exported to the API user. Displays +are meant as lowest hardware entity available outside of grdev. The +underlying pipe configuration is fully hidden and not accessible from the +outside. The grdev tiling layer allows almost arbitrary setups out of +multiple pipes, but so far we only use a small subset of this. More will +follow. + +A grdev-display is meant to represent real connected displays/monitors. +The upper level screen arrangements are user policy and not controlled by +grdev. Applications are free to apply any policy they want. + +Real card-backends will follow in later patches. +--- + Makefile.am | 3 + + configure.ac | 2 +- + src/libsystemd-terminal/grdev-internal.h | 237 ++++++ + src/libsystemd-terminal/grdev.c | 1219 ++++++++++++++++++++++++++++++ + src/libsystemd-terminal/grdev.h | 182 +++++ + 5 files changed, 1642 insertions(+), 1 deletion(-) + create mode 100644 src/libsystemd-terminal/grdev-internal.h + create mode 100644 src/libsystemd-terminal/grdev.c + create mode 100644 src/libsystemd-terminal/grdev.h + +diff --git a/Makefile.am b/Makefile.am +index 5dc17f8fe7..1931c5d96b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3005,6 +3005,9 @@ libsystemd_terminal_la_CFLAGS = \ + $(TERMINAL_CFLAGS) + + libsystemd_terminal_la_SOURCES = \ ++ src/libsystemd-terminal/grdev.h \ ++ src/libsystemd-terminal/grdev-internal.h \ ++ src/libsystemd-terminal/grdev.c \ + src/libsystemd-terminal/idev.h \ + src/libsystemd-terminal/idev-internal.h \ + src/libsystemd-terminal/idev.c \ +diff --git a/configure.ac b/configure.ac +index fb169042d8..38a165c101 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1065,7 +1065,7 @@ AM_CONDITIONAL(ENABLE_MULTI_SEAT_X, [test "$have_multi_seat_x" = "yes"]) + have_terminal=no + AC_ARG_ENABLE(terminal, AS_HELP_STRING([--enable-terminal], [enable terminal support])) + if test "x$enable_terminal" = "xyes"; then +- PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 xkbcommon >= 0.4 ], [have_terminal=yes]) ++ PKG_CHECK_MODULES([TERMINAL], [ libevdev >= 1.2 xkbcommon >= 0.4 libdrm >= 2.4], [have_terminal=yes]) + AS_IF([test "x$have_terminal" != xyes -a "x$enable_terminal" = xyes], + [AC_MSG_ERROR([*** terminal support requested but required dependencies not available])], + [test "x$have_terminal" = xyes], +diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h +new file mode 100644 +index 0000000000..7e69c49b63 +--- /dev/null ++++ b/src/libsystemd-terminal/grdev-internal.h +@@ -0,0 +1,237 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include "grdev.h" ++#include "hashmap.h" ++#include "list.h" ++#include "util.h" ++ ++typedef struct grdev_tile grdev_tile; ++typedef struct grdev_display_cache grdev_display_cache; ++ ++typedef struct grdev_pipe_vtable grdev_pipe_vtable; ++typedef struct grdev_pipe grdev_pipe; ++typedef struct grdev_card_vtable grdev_card_vtable; ++typedef struct grdev_card grdev_card; ++ ++/* ++ * Displays ++ */ ++ ++enum { ++ GRDEV_TILE_LEAF, ++ GRDEV_TILE_NODE, ++ GRDEV_TILE_CNT ++}; ++ ++struct grdev_tile { ++ LIST_FIELDS(grdev_tile, childs_by_node); ++ grdev_tile *parent; ++ grdev_display *display; ++ ++ uint32_t x; ++ uint32_t y; ++ unsigned int rotate; ++ unsigned int flip; ++ uint32_t cache_w; ++ uint32_t cache_h; ++ ++ unsigned int type; ++ ++ union { ++ struct { ++ grdev_pipe *pipe; ++ } leaf; ++ ++ struct { ++ size_t n_childs; ++ LIST_HEAD(grdev_tile, child_list); ++ } node; ++ }; ++}; ++ ++int grdev_tile_new_leaf(grdev_tile **out, grdev_pipe *pipe); ++int grdev_tile_new_node(grdev_tile **out); ++grdev_tile *grdev_tile_free(grdev_tile *tile); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_tile*, grdev_tile_free); ++ ++struct grdev_display { ++ grdev_session *session; ++ char *name; ++ ++ size_t n_leafs; ++ grdev_tile *tile; ++ ++ size_t n_pipes; ++ size_t max_pipes; ++ ++ uint32_t width; ++ uint32_t height; ++ ++ struct grdev_display_cache { ++ grdev_pipe *pipe; ++ grdev_display_target target; ++ ++ bool incomplete : 1; ++ } *pipes; ++ ++ bool enabled : 1; ++ bool public : 1; ++ bool modified : 1; ++ bool framed : 1; ++}; ++ ++grdev_display *grdev_find_display(grdev_session *session, const char *name); ++ ++int grdev_display_new(grdev_display **out, grdev_session *session, const char *name); ++grdev_display *grdev_display_free(grdev_display *display); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_display*, grdev_display_free); ++ ++/* ++ * Pipes ++ */ ++ ++struct grdev_pipe_vtable { ++ void (*free) (grdev_pipe *pipe); ++ void (*enable) (grdev_pipe *pipe); ++ void (*disable) (grdev_pipe *pipe); ++ grdev_fb *(*target) (grdev_pipe *pipe); ++}; ++ ++struct grdev_pipe { ++ const grdev_pipe_vtable *vtable; ++ grdev_card *card; ++ char *name; ++ ++ grdev_tile *tile; ++ grdev_display_cache *cache; ++ ++ uint32_t width; ++ uint32_t height; ++ ++ size_t max_fbs; ++ grdev_fb *front; ++ grdev_fb *back; ++ grdev_fb **fbs; ++ ++ bool enabled : 1; ++ bool running : 1; ++ bool flip : 1; ++ bool flipping : 1; ++}; ++ ++#define GRDEV_PIPE_INIT(_vtable, _card) ((grdev_pipe){ \ ++ .vtable = (_vtable), \ ++ .card = (_card), \ ++ }) ++ ++grdev_pipe *grdev_find_pipe(grdev_card *card, const char *name); ++ ++int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs); ++grdev_pipe *grdev_pipe_free(grdev_pipe *pipe); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_pipe*, grdev_pipe_free); ++ ++void grdev_pipe_ready(grdev_pipe *pipe, bool running); ++void grdev_pipe_frame(grdev_pipe *pipe); ++ ++/* ++ * Cards ++ */ ++ ++struct grdev_card_vtable { ++ void (*free) (grdev_card *card); ++ void (*enable) (grdev_card *card); ++ void (*disable) (grdev_card *card); ++ void (*commit) (grdev_card *card); ++ void (*restore) (grdev_card *card); ++}; ++ ++struct grdev_card { ++ const grdev_card_vtable *vtable; ++ grdev_session *session; ++ char *name; ++ ++ Hashmap *pipe_map; ++ ++ bool enabled : 1; ++ bool modified : 1; ++}; ++ ++#define GRDEV_CARD_INIT(_vtable, _session) ((grdev_card){ \ ++ .vtable = (_vtable), \ ++ .session = (_session), \ ++ }) ++ ++grdev_card *grdev_find_card(grdev_session *session, const char *name); ++ ++int grdev_card_add(grdev_card *card, const char *name); ++grdev_card *grdev_card_free(grdev_card *card); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_card*, grdev_card_free); ++ ++/* ++ * Sessions ++ */ ++ ++struct grdev_session { ++ grdev_context *context; ++ char *name; ++ char *path; ++ grdev_event_fn event_fn; ++ void *userdata; ++ ++ unsigned long n_pins; ++ ++ Hashmap *card_map; ++ Hashmap *display_map; ++ ++ bool custom : 1; ++ bool managed : 1; ++ bool enabled : 1; ++ bool modified : 1; ++}; ++ ++grdev_session *grdev_session_pin(grdev_session *session); ++grdev_session *grdev_session_unpin(grdev_session *session); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_session*, grdev_session_unpin); ++ ++/* ++ * Contexts ++ */ ++ ++struct grdev_context { ++ unsigned long ref; ++ sd_event *event; ++ sd_bus *sysbus; ++ ++ Hashmap *session_map; ++}; +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +new file mode 100644 +index 0000000000..ab1c407ecb +--- /dev/null ++++ b/src/libsystemd-terminal/grdev.c +@@ -0,0 +1,1219 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 "grdev.h" ++#include "grdev-internal.h" ++#include "hashmap.h" ++#include "login-shared.h" ++#include "macro.h" ++#include "util.h" ++ ++static void pipe_enable(grdev_pipe *pipe); ++static void pipe_disable(grdev_pipe *pipe); ++static void card_modified(grdev_card *card); ++static void session_frame(grdev_session *session, grdev_display *display); ++ ++/* ++ * Displays ++ */ ++ ++static inline grdev_tile *tile_leftmost(grdev_tile *tile) { ++ if (!tile) ++ return NULL; ++ ++ while (tile->type == GRDEV_TILE_NODE && tile->node.child_list) ++ tile = tile->node.child_list; ++ ++ return tile; ++} ++ ++#define TILE_FOREACH(_root, _i) \ ++ for (_i = tile_leftmost(_root); _i; _i = tile_leftmost(_i->childs_by_node_next) ? : _i->parent) ++ ++#define TILE_FOREACH_SAFE(_root, _i, _next) \ ++ for (_i = tile_leftmost(_root); _i && ((_next = tile_leftmost(_i->childs_by_node_next) ? : _i->parent), true); _i = _next) ++ ++static void tile_link(grdev_tile *tile, grdev_tile *parent) { ++ grdev_display *display; ++ grdev_tile *t; ++ ++ assert(tile); ++ assert(!tile->parent); ++ assert(!tile->display); ++ assert(parent); ++ assert(parent->type == GRDEV_TILE_NODE); ++ ++ display = parent->display; ++ ++ assert(!display || !display->enabled); ++ ++ ++parent->node.n_childs; ++ LIST_PREPEND(childs_by_node, parent->node.child_list, tile); ++ tile->parent = parent; ++ ++ if (display) { ++ display->modified = true; ++ TILE_FOREACH(tile, t) { ++ t->display = display; ++ if (t->type == GRDEV_TILE_LEAF) { ++ ++display->n_leafs; ++ if (display->enabled) ++ pipe_enable(t->leaf.pipe); ++ } ++ } ++ } ++} ++ ++static void tile_unlink(grdev_tile *tile) { ++ grdev_tile *parent, *t; ++ grdev_display *display; ++ ++ assert(tile); ++ ++ display = tile->display; ++ parent = tile->parent; ++ if (!parent) { ++ assert(!display); ++ return; ++ } ++ ++ assert(parent->type == GRDEV_TILE_NODE); ++ assert(parent->display == display); ++ assert(parent->node.n_childs > 0); ++ ++ --parent->node.n_childs; ++ LIST_REMOVE(childs_by_node, parent->node.child_list, tile); ++ tile->parent = NULL; ++ ++ if (display) { ++ display->modified = true; ++ TILE_FOREACH(tile, t) { ++ t->display = NULL; ++ if (t->type == GRDEV_TILE_LEAF) { ++ --display->n_leafs; ++ t->leaf.pipe->cache = NULL; ++ pipe_disable(t->leaf.pipe); ++ } ++ } ++ } ++ ++ /* Tile trees are driven by leafs. Internal nodes have no owner, thus, ++ * we must take care to not leave them around. Therefore, whenever we ++ * unlink any part of a tree, we also destroy the parent, in case it's ++ * now stale. ++ * Parents are stale if they have no childs and either have no display ++ * or if they are intermediate nodes (i.e, they have a parent). ++ * This means, you can easily create trees, but you can never partially ++ * move or destruct them so far. They're always reduced to minimal form ++ * if you cut them. This might change later, but so far we didn't need ++ * partial destruction or the ability to move whole trees. */ ++ ++ if (parent->node.n_childs < 1 && (parent->parent || !parent->display)) ++ grdev_tile_free(parent); ++} ++ ++static int tile_new(grdev_tile **out) { ++ _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL; ++ ++ assert(out); ++ ++ tile = new0(grdev_tile, 1); ++ if (!tile) ++ return -ENOMEM; ++ ++ tile->type = (unsigned)-1; ++ ++ *out = tile; ++ tile = NULL; ++ return 0; ++} ++ ++int grdev_tile_new_leaf(grdev_tile **out, grdev_pipe *pipe) { ++ _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL; ++ int r; ++ ++ assert_return(pipe, -EINVAL); ++ assert_return(!pipe->tile, -EINVAL); ++ ++ r = tile_new(&tile); ++ if (r < 0) ++ return r; ++ ++ tile->type = GRDEV_TILE_LEAF; ++ tile->leaf.pipe = pipe; ++ ++ if (out) ++ *out = tile; ++ tile = NULL; ++ return 0; ++} ++ ++int grdev_tile_new_node(grdev_tile **out) { ++ _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL; ++ int r; ++ ++ assert_return(out, -EINVAL); ++ ++ r = tile_new(&tile); ++ if (r < 0) ++ return r; ++ ++ tile->type = GRDEV_TILE_NODE; ++ ++ *out = tile; ++ tile = NULL; ++ return 0; ++} ++ ++grdev_tile *grdev_tile_free(grdev_tile *tile) { ++ if (!tile) ++ return NULL; ++ ++ tile_unlink(tile); ++ ++ switch (tile->type) { ++ case GRDEV_TILE_LEAF: ++ assert(!tile->parent); ++ assert(!tile->display); ++ assert(tile->leaf.pipe); ++ ++ break; ++ case GRDEV_TILE_NODE: ++ assert(!tile->parent); ++ assert(!tile->display); ++ assert(tile->node.n_childs == 0); ++ ++ break; ++ } ++ ++ free(tile); ++ ++ return NULL; ++} ++ ++grdev_display *grdev_find_display(grdev_session *session, const char *name) { ++ assert_return(session, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(session->display_map, name); ++} ++ ++int grdev_display_new(grdev_display **out, grdev_session *session, const char *name) { ++ _cleanup_(grdev_display_freep) grdev_display *display = NULL; ++ int r; ++ ++ assert(session); ++ assert(name); ++ ++ display = new0(grdev_display, 1); ++ if (!display) ++ return -ENOMEM; ++ ++ display->session = session; ++ ++ display->name = strdup(name); ++ if (!display->name) ++ return -ENOMEM; ++ ++ r = grdev_tile_new_node(&display->tile); ++ if (r < 0) ++ return r; ++ ++ display->tile->display = display; ++ ++ r = hashmap_put(session->display_map, display->name, display); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = display; ++ display = NULL; ++ return 0; ++} ++ ++grdev_display *grdev_display_free(grdev_display *display) { ++ if (!display) ++ return NULL; ++ ++ assert(!display->public); ++ assert(!display->enabled); ++ assert(!display->modified); ++ assert(display->n_leafs == 0); ++ assert(display->n_pipes == 0); ++ ++ if (display->name) ++ hashmap_remove_value(display->session->display_map, display->name, display); ++ ++ if (display->tile) { ++ display->tile->display = NULL; ++ grdev_tile_free(display->tile); ++ } ++ ++ free(display->pipes); ++ free(display->name); ++ free(display); ++ ++ return NULL; ++} ++ ++bool grdev_display_is_enabled(grdev_display *display) { ++ return display && display->enabled; ++} ++ ++void grdev_display_enable(grdev_display *display) { ++ grdev_tile *t; ++ ++ assert(display); ++ ++ if (!display->enabled) { ++ display->enabled = true; ++ TILE_FOREACH(display->tile, t) ++ if (t->type == GRDEV_TILE_LEAF) ++ pipe_enable(t->leaf.pipe); ++ } ++} ++ ++void grdev_display_disable(grdev_display *display) { ++ grdev_tile *t; ++ ++ assert(display); ++ ++ if (display->enabled) { ++ display->enabled = false; ++ TILE_FOREACH(display->tile, t) ++ if (t->type == GRDEV_TILE_LEAF) ++ pipe_disable(t->leaf.pipe); ++ } ++} ++ ++const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev, uint64_t minage) { ++ grdev_display_cache *cache; ++ size_t idx; ++ ++ assert_return(display, NULL); ++ assert_return(!display->modified, NULL); ++ assert_return(display->enabled, NULL); ++ ++ if (prev) { ++ cache = container_of(prev, grdev_display_cache, target); ++ ++ assert(cache->pipe); ++ assert(cache->pipe->tile->display == display); ++ assert(display->pipes >= cache); ++ ++ idx = (cache - display->pipes) / sizeof(*cache) + 1; ++ } else { ++ idx = 0; ++ } ++ ++ for (cache = display->pipes + idx; idx < display->n_pipes; ++idx, ++cache) { ++ grdev_display_target *target; ++ grdev_pipe *pipe; ++ grdev_fb *fb; ++ ++ pipe = cache->pipe; ++ target = &cache->target; ++ ++ if (!pipe->running || !pipe->enabled) ++ continue; ++ ++ /* if front-buffer is up-to-date, there's nothing to do */ ++ if (minage > 0 && pipe->front && pipe->front->age >= minage) ++ continue; ++ ++ /* find suitable back-buffer */ ++ if (!(fb = pipe->back)) { ++ if (!pipe->vtable->target || !(fb = pipe->vtable->target(pipe))) ++ continue; ++ } ++ ++ /* if back-buffer is up-to-date, schedule flip */ ++ if (minage > 0 && fb->age >= minage) { ++ grdev_display_flip_target(display, target, fb->age); ++ continue; ++ } ++ ++ /* we have an out-of-date back-buffer; return for redraw */ ++ target->fb = fb; ++ return target; ++ } ++ ++ return NULL; ++} ++ ++void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target, uint64_t age) { ++ grdev_display_cache *cache; ++ size_t i; ++ ++ assert(display); ++ assert(!display->modified); ++ assert(display->enabled); ++ assert(target); ++ assert(target->fb); ++ ++ cache = container_of(target, grdev_display_cache, target); ++ ++ assert(cache->pipe); ++ assert(cache->pipe->tile->display == display); ++ ++ /* reset age of all FB on overflow */ ++ if (age < target->fb->age) ++ for (i = 0; i < cache->pipe->max_fbs; ++i) ++ if (cache->pipe->fbs[i]) ++ cache->pipe->fbs[i]->age = 0; ++ ++ ((grdev_fb*)target->fb)->age = age; ++ cache->pipe->flip = true; ++} ++ ++static void display_cache_apply(grdev_display_cache *c, grdev_tile *l) { ++ uint32_t x, y, width, height; ++ grdev_display_target *t; ++ ++ assert(c); ++ assert(l); ++ assert(l->cache_w >= c->target.width + c->target.x); ++ assert(l->cache_h >= c->target.height + c->target.y); ++ ++ t = &c->target; ++ ++ /* rotate child */ ++ ++ t->rotate = (t->rotate + l->rotate) & 0x3; ++ ++ x = t->x; ++ y = t->y; ++ width = t->width; ++ height = t->height; ++ ++ switch (l->rotate) { ++ case GRDEV_ROTATE_0: ++ break; ++ case GRDEV_ROTATE_90: ++ t->x = l->cache_h - (height + y); ++ t->y = x; ++ t->width = height; ++ t->height = width; ++ break; ++ case GRDEV_ROTATE_180: ++ t->x = l->cache_w - (width + x); ++ t->y = l->cache_h - (height + y); ++ break; ++ case GRDEV_ROTATE_270: ++ t->x = y; ++ t->y = l->cache_w - (width + x); ++ t->width = height; ++ t->height = width; ++ break; ++ } ++ ++ /* flip child */ ++ ++ t->flip ^= l->flip; ++ ++ if (l->flip & GRDEV_FLIP_HORIZONTAL) ++ t->x = l->cache_w - (t->width + t->x); ++ if (l->flip & GRDEV_FLIP_VERTICAL) ++ t->y = l->cache_h - (t->height + t->y); ++ ++ /* move child */ ++ ++ t->x += l->x; ++ t->y += l->y; ++} ++ ++static void display_cache_targets(grdev_display *display) { ++ grdev_display_cache *c; ++ grdev_tile *tile; ++ ++ assert(display); ++ ++ /* depth-first with childs before parent */ ++ for (tile = tile_leftmost(display->tile); ++ tile; ++ tile = tile_leftmost(tile->childs_by_node_next) ? : tile->parent) { ++ if (tile->type == GRDEV_TILE_LEAF) { ++ grdev_pipe *p; ++ ++ /* We're at a leaf and no parent has been cached, yet. ++ * Copy the pipe information into the target cache and ++ * update our global pipe-caches if required. */ ++ ++ assert(tile->leaf.pipe); ++ assert(display->n_pipes + 1 <= display->max_pipes); ++ ++ p = tile->leaf.pipe; ++ c = &display->pipes[display->n_pipes++]; ++ ++ zero(*c); ++ c->pipe = p; ++ c->pipe->cache = c; ++ c->target.width = p->width; ++ c->target.height = p->height; ++ tile->cache_w = p->width; ++ tile->cache_h = p->height; ++ ++ /* all new tiles are incomplete due to geometry changes */ ++ c->incomplete = true; ++ ++ display_cache_apply(c, tile); ++ } else { ++ grdev_tile *child, *l; ++ ++ /* We're now at a node with all it's childs already ++ * computed (depth-first, child before parent). We ++ * first need to know the size of our tile, then we ++ * recurse into all leafs and update their cache. */ ++ ++ tile->cache_w = 0; ++ tile->cache_h = 0; ++ ++ LIST_FOREACH(childs_by_node, child, tile->node.child_list) { ++ if (child->x + child->cache_w > tile->cache_w) ++ tile->cache_w = child->x + child->cache_w; ++ if (child->y + child->cache_h > tile->cache_h) ++ tile->cache_h = child->y + child->cache_h; ++ } ++ ++ assert(tile->cache_w > 0); ++ assert(tile->cache_h > 0); ++ ++ TILE_FOREACH(tile, l) ++ if (l->type == GRDEV_TILE_LEAF) ++ display_cache_apply(l->leaf.pipe->cache, tile); ++ } ++ } ++} ++ ++static bool display_cache(grdev_display *display) { ++ grdev_tile *tile; ++ size_t n; ++ void *t; ++ int r; ++ ++ assert(display); ++ ++ if (!display->modified) ++ return false; ++ ++ display->modified = false; ++ display->framed = false; ++ display->n_pipes = 0; ++ display->width = 0; ++ display->height = 0; ++ ++ if (display->n_leafs < 1) ++ return false; ++ ++ TILE_FOREACH(display->tile, tile) ++ if (tile->type == GRDEV_TILE_LEAF) ++ tile->leaf.pipe->cache = NULL; ++ ++ if (display->n_leafs > display->max_pipes) { ++ n = ALIGN_POWER2(display->n_leafs); ++ if (!n) { ++ r = -ENOMEM; ++ goto out; ++ } ++ ++ t = realloc_multiply(display->pipes, sizeof(*display->pipes), n); ++ if (!t) { ++ r = -ENOMEM; ++ goto out; ++ } ++ ++ display->pipes = t; ++ display->max_pipes = n; ++ } ++ ++ display_cache_targets(display); ++ ++ r = 0; ++ ++out: ++ if (r < 0) ++ log_debug("grdev: %s/%s: cannot cache pipes: %s", ++ display->session->name, display->name, strerror(-r)); ++ return true; ++} ++ ++/* ++ * Pipes ++ */ ++ ++grdev_pipe *grdev_find_pipe(grdev_card *card, const char *name) { ++ assert_return(card, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(card->pipe_map, name); ++} ++ ++int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) { ++ int r; ++ ++ assert_return(pipe, -EINVAL); ++ assert_return(pipe->vtable, -EINVAL); ++ assert_return(pipe->vtable->free, -EINVAL); ++ assert_return(pipe->card, -EINVAL); ++ assert_return(pipe->card->session, -EINVAL); ++ assert_return(!pipe->cache, -EINVAL); ++ assert_return(pipe->width > 0, -EINVAL); ++ assert_return(pipe->height > 0, -EINVAL); ++ assert_return(!pipe->enabled, -EINVAL); ++ assert_return(!pipe->running, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ pipe->name = strdup(name); ++ if (!pipe->name) ++ return -ENOMEM; ++ ++ if (n_fbs > 0) { ++ pipe->fbs = new0(grdev_fb*, n_fbs); ++ if (!pipe->fbs) ++ return -ENOMEM; ++ ++ pipe->max_fbs = n_fbs; ++ } ++ ++ r = grdev_tile_new_leaf(&pipe->tile, pipe); ++ if (r < 0) ++ return r; ++ ++ r = hashmap_put(pipe->card->pipe_map, pipe->name, pipe); ++ if (r < 0) ++ return r; ++ ++ card_modified(pipe->card); ++ return 0; ++} ++ ++grdev_pipe *grdev_pipe_free(grdev_pipe *pipe) { ++ grdev_pipe tmp; ++ ++ if (!pipe) ++ return NULL; ++ ++ assert(pipe->card); ++ assert(pipe->vtable); ++ assert(pipe->vtable->free); ++ ++ if (pipe->name) ++ hashmap_remove_value(pipe->card->pipe_map, pipe->name, pipe); ++ if (pipe->tile) ++ tile_unlink(pipe->tile); ++ ++ assert(!pipe->cache); ++ ++ tmp = *pipe; ++ pipe->vtable->free(pipe); ++ ++ grdev_tile_free(tmp.tile); ++ card_modified(tmp.card); ++ free(tmp.fbs); ++ free(tmp.name); ++ ++ return NULL; ++} ++ ++static void pipe_enable(grdev_pipe *pipe) { ++ assert(pipe); ++ ++ if (!pipe->enabled) { ++ pipe->enabled = true; ++ if (pipe->vtable->enable) ++ pipe->vtable->enable(pipe); ++ } ++} ++ ++static void pipe_disable(grdev_pipe *pipe) { ++ assert(pipe); ++ ++ if (pipe->enabled) { ++ pipe->enabled = false; ++ if (pipe->vtable->disable) ++ pipe->vtable->disable(pipe); ++ } ++} ++ ++void grdev_pipe_ready(grdev_pipe *pipe, bool running) { ++ assert(pipe); ++ ++ /* grdev_pipe_ready() is used by backends to notify about pipe state ++ * changed. If a pipe is ready, it can be fully used by us (available, ++ * enabled and accessable). Backends can disable pipes at any time ++ * (like for async revocation), but can only enable them from parent ++ * context. Otherwise, we might call user-callbacks recursively. */ ++ ++ if (pipe->running == running) ++ return; ++ ++ pipe->running = running; ++ ++ /* runtime events for unused pipes are not interesting */ ++ if (pipe->cache) { ++ grdev_display *display = pipe->tile->display; ++ ++ assert(display); ++ ++ if (running) { ++ if (pipe->enabled) ++ session_frame(display->session, display); ++ } else { ++ pipe->cache->incomplete = true; ++ } ++ } ++} ++ ++void grdev_pipe_frame(grdev_pipe *pipe) { ++ grdev_display *display; ++ ++ assert(pipe); ++ ++ /* if pipe is unused, ignore any frame events */ ++ if (!pipe->cache) ++ return; ++ ++ display = pipe->tile->display; ++ assert(display); ++ ++ if (pipe->enabled) ++ session_frame(display->session, display); ++} ++ ++/* ++ * Cards ++ */ ++ ++grdev_card *grdev_find_card(grdev_session *session, const char *name) { ++ assert_return(session, NULL); ++ assert_return(name, NULL); ++ ++ return hashmap_get(session->card_map, name); ++} ++ ++int grdev_card_add(grdev_card *card, const char *name) { ++ int r; ++ ++ assert_return(card, -EINVAL); ++ assert_return(card->vtable, -EINVAL); ++ assert_return(card->vtable->free, -EINVAL); ++ assert_return(card->session, -EINVAL); ++ assert_return(name, -EINVAL); ++ ++ card->name = strdup(name); ++ if (!card->name) ++ return -ENOMEM; ++ ++ card->pipe_map = hashmap_new(&string_hash_ops); ++ if (!card->pipe_map) ++ return -ENOMEM; ++ ++ r = hashmap_put(card->session->card_map, card->name, card); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++grdev_card *grdev_card_free(grdev_card *card) { ++ grdev_card tmp; ++ ++ if (!card) ++ return NULL; ++ ++ assert(!card->enabled); ++ assert(card->vtable); ++ assert(card->vtable->free); ++ ++ if (card->name) ++ hashmap_remove_value(card->session->card_map, card->name, card); ++ ++ tmp = *card; ++ card->vtable->free(card); ++ ++ assert(hashmap_size(tmp.pipe_map) == 0); ++ ++ hashmap_free(tmp.pipe_map); ++ free(tmp.name); ++ ++ return NULL; ++} ++ ++static void card_modified(grdev_card *card) { ++ assert(card); ++ assert(card->session->n_pins > 0); ++ ++ card->modified = true; ++} ++ ++static void grdev_card_enable(grdev_card *card) { ++ assert(card); ++ ++ if (!card->enabled) { ++ card->enabled = true; ++ if (card->vtable->enable) ++ card->vtable->enable(card); ++ } ++} ++ ++static void grdev_card_disable(grdev_card *card) { ++ assert(card); ++ ++ if (card->enabled) { ++ card->enabled = false; ++ if (card->vtable->disable) ++ card->vtable->disable(card); ++ } ++} ++ ++/* ++ * Sessions ++ */ ++ ++static void session_raise(grdev_session *session, grdev_event *event) { ++ session->event_fn(session, session->userdata, event); ++} ++ ++static void session_raise_display_add(grdev_session *session, grdev_display *display) { ++ grdev_event event = { ++ .type = GRDEV_EVENT_DISPLAY_ADD, ++ .display_add = { ++ .display = display, ++ }, ++ }; ++ ++ session_raise(session, &event); ++} ++ ++static void session_raise_display_remove(grdev_session *session, grdev_display *display) { ++ grdev_event event = { ++ .type = GRDEV_EVENT_DISPLAY_REMOVE, ++ .display_remove = { ++ .display = display, ++ }, ++ }; ++ ++ session_raise(session, &event); ++} ++ ++static void session_raise_display_change(grdev_session *session, grdev_display *display) { ++ grdev_event event = { ++ .type = GRDEV_EVENT_DISPLAY_CHANGE, ++ .display_change = { ++ .display = display, ++ }, ++ }; ++ ++ session_raise(session, &event); ++} ++ ++static void session_raise_display_frame(grdev_session *session, grdev_display *display) { ++ grdev_event event = { ++ .type = GRDEV_EVENT_DISPLAY_FRAME, ++ .display_frame = { ++ .display = display, ++ }, ++ }; ++ ++ session_raise(session, &event); ++} ++ ++static void session_add_card(grdev_session *session, grdev_card *card) { ++ assert(session); ++ assert(card); ++ ++ log_debug("grdev: %s: add card '%s'", session->name, card->name); ++ ++ /* Cards are not exposed to users, but managed internally. Cards are ++ * enabled if the session is enabled, and will track that state. The ++ * backend can probe the card at any time, but only if enabled. It ++ * will then add pipes according to hardware state. ++ * That is, the card may create pipes as soon as we enable it here. */ ++ ++ if (session->enabled) ++ grdev_card_enable(card); ++} ++ ++static void session_remove_card(grdev_session *session, grdev_card *card) { ++ assert(session); ++ assert(card); ++ ++ log_debug("grdev: %s: remove card '%s'", session->name, card->name); ++ ++ /* As cards are not exposed, it can never be accessed by outside ++ * users and we can simply remove it. Disabling the card does not ++ * necessarily drop all pipes of the card. This is usually deferred ++ * to card destruction (as pipes are cached as long as FDs remain ++ * open). Therefore, the card destruction might cause pipes, and thus ++ * visible displays, to be removed. */ ++ ++ grdev_card_disable(card); ++ grdev_card_free(card); ++} ++ ++static void session_add_display(grdev_session *session, grdev_display *display) { ++ assert(session); ++ assert(display); ++ assert(!display->enabled); ++ ++ log_debug("grdev: %s: add display '%s'", session->name, display->name); ++ ++ /* Displays are the main entity for public API users. We create them ++ * independent of card backends and they wrap any underlying display ++ * architecture. Displays are public at all times, thus, may be entered ++ * by outside users at any time. */ ++ ++ display->public = true; ++ session_raise_display_add(session, display); ++} ++ ++static void session_remove_display(grdev_session *session, grdev_display *display) { ++ assert(session); ++ assert(display); ++ ++ log_debug("grdev: %s: remove display '%s'", session->name, display->name); ++ ++ /* Displays are public, so we have to be careful when removing them. ++ * We first tell users about their removal, disable them and then drop ++ * them. We now, after the notification, no external access will ++ * happen. Therefore, we can release the tiles afterwards safely. */ ++ ++ if (display->public) { ++ display->public = false; ++ session_raise_display_remove(session, display); ++ } ++ ++ grdev_display_disable(display); ++ grdev_display_free(display); ++} ++ ++static void session_change_display(grdev_session *session, grdev_display *display) { ++ bool changed; ++ ++ assert(session); ++ assert(display); ++ ++ changed = display_cache(display); ++ ++ if (display->n_leafs == 0) ++ session_remove_display(session, display); ++ else if (!display->public) ++ session_add_display(session, display); ++ else if (changed) ++ session_raise_display_change(session, display); ++ else if (display->framed) ++ session_frame(session, display); ++} ++ ++static void session_frame(grdev_session *session, grdev_display *display) { ++ assert(session); ++ assert(display); ++ ++ display->framed = false; ++ ++ if (!display->enabled || !session->enabled) ++ return; ++ ++ if (session->n_pins > 0) ++ display->framed = true; ++ else ++ session_raise_display_frame(session, display); ++} ++ ++int grdev_session_new(grdev_session **out, ++ grdev_context *context, ++ unsigned int flags, ++ const char *name, ++ grdev_event_fn event_fn, ++ void *userdata) { ++ _cleanup_(grdev_session_freep) grdev_session *session = NULL; ++ int r; ++ ++ assert(out); ++ assert(context); ++ assert(name); ++ assert(event_fn); ++ assert_return(session_id_valid(name) == !(flags & GRDEV_SESSION_CUSTOM), -EINVAL); ++ assert_return(!(flags & GRDEV_SESSION_CUSTOM) || !(flags & GRDEV_SESSION_MANAGED), -EINVAL); ++ assert_return(!(flags & GRDEV_SESSION_MANAGED) || context->sysbus, -EINVAL); ++ ++ session = new0(grdev_session, 1); ++ if (!session) ++ return -ENOMEM; ++ ++ session->context = grdev_context_ref(context); ++ session->custom = flags & GRDEV_SESSION_CUSTOM; ++ session->managed = flags & GRDEV_SESSION_MANAGED; ++ session->event_fn = event_fn; ++ session->userdata = userdata; ++ ++ session->name = strdup(name); ++ if (!session->name) ++ return -ENOMEM; ++ ++ if (session->managed) { ++ r = sd_bus_path_encode("/org/freedesktop/login1/session", ++ session->name, &session->path); ++ if (r < 0) ++ return r; ++ } ++ ++ session->card_map = hashmap_new(&string_hash_ops); ++ if (!session->card_map) ++ return -ENOMEM; ++ ++ session->display_map = hashmap_new(&string_hash_ops); ++ if (!session->display_map) ++ return -ENOMEM; ++ ++ r = hashmap_put(context->session_map, session->name, session); ++ if (r < 0) ++ return r; ++ ++ *out = session; ++ session = NULL; ++ return 0; ++} ++ ++grdev_session *grdev_session_free(grdev_session *session) { ++ grdev_card *card; ++ ++ if (!session) ++ return NULL; ++ ++ grdev_session_disable(session); ++ ++ while ((card = hashmap_first(session->card_map))) ++ session_remove_card(session, card); ++ ++ assert(hashmap_size(session->display_map) == 0); ++ ++ if (session->name) ++ hashmap_remove_value(session->context->session_map, session->name, session); ++ ++ hashmap_free(session->display_map); ++ hashmap_free(session->card_map); ++ session->context = grdev_context_unref(session->context); ++ free(session->path); ++ free(session->name); ++ free(session); ++ ++ return NULL; ++} ++ ++bool grdev_session_is_enabled(grdev_session *session) { ++ return session && session->enabled; ++} ++ ++void grdev_session_enable(grdev_session *session) { ++ grdev_card *card; ++ Iterator iter; ++ ++ assert(session); ++ ++ if (!session->enabled) { ++ session->enabled = true; ++ HASHMAP_FOREACH(card, session->card_map, iter) ++ grdev_card_enable(card); ++ } ++} ++ ++void grdev_session_disable(grdev_session *session) { ++ grdev_card *card; ++ Iterator iter; ++ ++ assert(session); ++ ++ if (session->enabled) { ++ session->enabled = false; ++ HASHMAP_FOREACH(card, session->card_map, iter) ++ grdev_card_disable(card); ++ } ++} ++ ++void grdev_session_commit(grdev_session *session) { ++ grdev_card *card; ++ Iterator iter; ++ ++ assert(session); ++ ++ if (!session->enabled) ++ return; ++ ++ HASHMAP_FOREACH(card, session->card_map, iter) ++ if (card->vtable->commit) ++ card->vtable->commit(card); ++} ++ ++void grdev_session_restore(grdev_session *session) { ++ grdev_card *card; ++ Iterator iter; ++ ++ assert(session); ++ ++ if (!session->enabled) ++ return; ++ ++ HASHMAP_FOREACH(card, session->card_map, iter) ++ if (card->vtable->restore) ++ card->vtable->restore(card); ++} ++ ++static void session_configure(grdev_session *session) { ++ grdev_display *display; ++ grdev_tile *tile; ++ grdev_card *card; ++ grdev_pipe *pipe; ++ Iterator i, j; ++ int r; ++ ++ assert(session); ++ ++ /* ++ * Whenever backends add or remove pipes, we set session->modified and ++ * require them to pin the session while modifying it. On release, we ++ * reconfigure the device and re-assign displays to all modified pipes. ++ * ++ * So far, we configure each pipe as a separate display. We do not ++ * support user-configuration, nor have we gotten any reports from ++ * users with multi-pipe monitors (4k on DP-1.2 MST and so on). Until ++ * we get reports, we keep the logic to a minimum. ++ */ ++ ++ /* create new displays for all unconfigured pipes */ ++ HASHMAP_FOREACH(card, session->card_map, i) { ++ if (!card->modified) ++ continue; ++ ++ card->modified = false; ++ ++ HASHMAP_FOREACH(pipe, card->pipe_map, j) { ++ tile = pipe->tile; ++ if (tile->display) ++ continue; ++ ++ assert(!tile->parent); ++ ++ display = grdev_find_display(session, pipe->name); ++ if (display && display->tile) { ++ log_debug("grdev: %s/%s: occupied display for pipe %s", ++ session->name, card->name, pipe->name); ++ continue; ++ } else if (!display) { ++ r = grdev_display_new(&display, session, pipe->name); ++ if (r < 0) { ++ log_debug("grdev: %s/%s: cannot create display for pipe %s: %s", ++ session->name, card->name, pipe->name, strerror(-r)); ++ continue; ++ } ++ } ++ ++ tile_link(pipe->tile, display->tile); ++ } ++ } ++ ++ /* update displays */ ++ HASHMAP_FOREACH(display, session->display_map, i) ++ session_change_display(session, display); ++} ++ ++grdev_session *grdev_session_pin(grdev_session *session) { ++ assert(session); ++ ++ ++session->n_pins; ++ return session; ++} ++ ++grdev_session *grdev_session_unpin(grdev_session *session) { ++ if (!session) ++ return NULL; ++ ++ assert(session->n_pins > 0); ++ ++ if (--session->n_pins == 0) ++ session_configure(session); ++ ++ return NULL; ++} ++ ++/* ++ * Contexts ++ */ ++ ++int grdev_context_new(grdev_context **out, sd_event *event, sd_bus *sysbus) { ++ _cleanup_(grdev_context_unrefp) grdev_context *context = NULL; ++ ++ assert_return(out, -EINVAL); ++ assert_return(event, -EINVAL); ++ ++ context = new0(grdev_context, 1); ++ if (!context) ++ return -ENOMEM; ++ ++ context->ref = 1; ++ context->event = sd_event_ref(event); ++ ++ if (sysbus) ++ context->sysbus = sd_bus_ref(sysbus); ++ ++ context->session_map = hashmap_new(&string_hash_ops); ++ if (!context->session_map) ++ return -ENOMEM; ++ ++ *out = context; ++ context = NULL; ++ return 0; ++} ++ ++static void context_cleanup(grdev_context *context) { ++ assert(hashmap_size(context->session_map) == 0); ++ ++ hashmap_free(context->session_map); ++ context->sysbus = sd_bus_unref(context->sysbus); ++ context->event = sd_event_unref(context->event); ++ free(context); ++} ++ ++grdev_context *grdev_context_ref(grdev_context *context) { ++ assert_return(context, NULL); ++ assert_return(context->ref > 0, NULL); ++ ++ ++context->ref; ++ return context; ++} ++ ++grdev_context *grdev_context_unref(grdev_context *context) { ++ if (!context) ++ return NULL; ++ ++ assert_return(context->ref > 0, NULL); ++ ++ if (--context->ref == 0) ++ context_cleanup(context); ++ ++ return NULL; ++} +diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h +new file mode 100644 +index 0000000000..2645b12113 +--- /dev/null ++++ b/src/libsystemd-terminal/grdev.h +@@ -0,0 +1,182 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++/* ++ * Graphics Devices ++ * The grdev layer provides generic access to graphics devices. The device ++ * types are hidden in the implementation and exported in a generic way. The ++ * grdev_session object forms the base layer. It loads, configures and prepares ++ * any graphics devices associated with that session. Each session is totally ++ * independent of other sessions and can be controlled separately. ++ * The target devices on a session are called display. A display always ++ * corresponds to a real display regardless how many pipes are needed to drive ++ * that display. That is, an exported display might internally be created out ++ * of arbitrary combinations of target pipes. However, this is meant as ++ * implementation detail and API users must never assume details below the ++ * display-level. That is, a display is the most low-level object exported. ++ * Therefore, pipe-configuration and any low-level modesetting is hidden from ++ * the public API. It is provided by the implementation, and it is the ++ * implementation that decides how pipes are driven. ++ * ++ * The API users are free to ignore specific displays or combine them to create ++ * larger screens. This often requires user-configuration so is dictated by ++ * policy. The underlying pipe-configuration might be affected by these ++ * high-level policies, but is never directly controlled by those. That means, ++ * depending on the displays you use, it might affect how underlying resources ++ * are assigned. However, users can never directly apply policies to the pipes, ++ * but only to displays. In case specific hardware needs quirks on the pipe ++ * level, we support that via hwdb, not via public user configuration. ++ * ++ * Right now, displays are limited to rgb32 memory-mapped framebuffers on the ++ * primary plane. However, the grdev implementation can be easily extended to ++ * allow more powerful access (including hardware-acceleration for 2D and 3D ++ * compositing). So far, this wasn't needed so it is not exposed. ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "util.h" ++ ++typedef struct grdev_fb grdev_fb; ++typedef struct grdev_display_target grdev_display_target; ++typedef struct grdev_display grdev_display; ++ ++typedef struct grdev_event grdev_event; ++typedef struct grdev_session grdev_session; ++typedef struct grdev_context grdev_context; ++ ++enum { ++ /* clockwise rotation; we treat this is abelian group Z4 with ADD */ ++ GRDEV_ROTATE_0 = 0, ++ GRDEV_ROTATE_90 = 1, ++ GRDEV_ROTATE_180 = 2, ++ GRDEV_ROTATE_270 = 3, ++}; ++ ++enum { ++ /* flip states; we treat this as abelian group V4 with XOR */ ++ GRDEV_FLIP_NONE = 0x0, ++ GRDEV_FLIP_HORIZONTAL = 0x1, ++ GRDEV_FLIP_VERTICAL = 0x2, ++}; ++ ++/* ++ * Displays ++ */ ++ ++struct grdev_fb { ++ uint32_t width; ++ uint32_t height; ++ uint32_t format; ++ uint64_t age; ++ int32_t strides[4]; ++ void *maps[4]; ++}; ++ ++struct grdev_display_target { ++ uint32_t x; ++ uint32_t y; ++ uint32_t width; ++ uint32_t height; ++ unsigned int rotate; ++ unsigned int flip; ++ const grdev_fb *fb; ++}; ++ ++bool grdev_display_is_enabled(grdev_display *display); ++void grdev_display_enable(grdev_display *display); ++void grdev_display_disable(grdev_display *display); ++ ++const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev, uint64_t minage); ++void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target, uint64_t age); ++ ++#define GRDEV_DISPLAY_FOREACH_TARGET(_display, _t, _minage) \ ++ for ((_t) = grdev_display_next_target((_display), NULL, (_minage)); \ ++ (_t); \ ++ (_t) = grdev_display_next_target((_display), (_t), (_minage))) ++ ++/* ++ * Events ++ */ ++ ++enum { ++ GRDEV_EVENT_DISPLAY_ADD, ++ GRDEV_EVENT_DISPLAY_REMOVE, ++ GRDEV_EVENT_DISPLAY_CHANGE, ++ GRDEV_EVENT_DISPLAY_FRAME, ++}; ++ ++typedef void (*grdev_event_fn) (grdev_session *session, void *userdata, grdev_event *ev); ++ ++struct grdev_event { ++ unsigned int type; ++ union { ++ struct { ++ grdev_display *display; ++ } display_add, display_remove, display_change; ++ ++ struct { ++ grdev_display *display; ++ } display_frame; ++ }; ++}; ++ ++/* ++ * Sessions ++ */ ++ ++enum { ++ GRDEV_SESSION_CUSTOM = (1 << 0), ++ GRDEV_SESSION_MANAGED = (1 << 1), ++}; ++ ++int grdev_session_new(grdev_session **out, ++ grdev_context *context, ++ unsigned int flags, ++ const char *name, ++ grdev_event_fn event_fn, ++ void *userdata); ++grdev_session *grdev_session_free(grdev_session *session); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_session*, grdev_session_free); ++ ++bool grdev_session_is_enabled(grdev_session *session); ++void grdev_session_enable(grdev_session *session); ++void grdev_session_disable(grdev_session *session); ++ ++void grdev_session_commit(grdev_session *session); ++void grdev_session_restore(grdev_session *session); ++ ++/* ++ * Contexts ++ */ ++ ++int grdev_context_new(grdev_context **out, sd_event *event, sd_bus *sysbus); ++grdev_context *grdev_context_ref(grdev_context *context); ++grdev_context *grdev_context_unref(grdev_context *context); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_context*, grdev_context_unref); diff --git a/0324-terminal-add-grdev-DRM-backend.patch b/0324-terminal-add-grdev-DRM-backend.patch new file mode 100644 index 0000000..b7f1d8d --- /dev/null +++ b/0324-terminal-add-grdev-DRM-backend.patch @@ -0,0 +1,3141 @@ +From f22e0bce3732c1fd005b7a886042394e036bc1b3 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 19 Sep 2014 14:13:06 +0200 +Subject: [PATCH] terminal: add grdev DRM backend + +The grdev-drm backend manages DRM cards for grdev. Any DRM card with +DUMB_BUFFER support can be used. So far, our policy is to configure all +available connectors, but keep pipes inactive as long as users don't +enable the displays on top. + +We hard-code double-buffering so far, but can easily support +single-buffering or n-buffering. We also require XRGB8888 as format as +this is required to be supported by all DRM drivers and it is what VTs +use. This allows us to switch from VTs to grdev via page-flips instead of +deep modesets. + +There is still a lot room for improvements in this backend, but it works +smoothly so far so more enhanced features can be added later. +--- + Makefile.am | 1 + + src/libsystemd-terminal/grdev-drm.c | 2957 ++++++++++++++++++++++++++++++ + src/libsystemd-terminal/grdev-internal.h | 9 + + src/libsystemd-terminal/grdev.c | 64 + + src/libsystemd-terminal/grdev.h | 5 + + 5 files changed, 3036 insertions(+) + create mode 100644 src/libsystemd-terminal/grdev-drm.c + +diff --git a/Makefile.am b/Makefile.am +index 1931c5d96b..be25023c75 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3008,6 +3008,7 @@ libsystemd_terminal_la_SOURCES = \ + src/libsystemd-terminal/grdev.h \ + src/libsystemd-terminal/grdev-internal.h \ + src/libsystemd-terminal/grdev.c \ ++ src/libsystemd-terminal/grdev-drm.c \ + src/libsystemd-terminal/idev.h \ + src/libsystemd-terminal/idev-internal.h \ + src/libsystemd-terminal/idev.c \ +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +new file mode 100644 +index 0000000000..3481584fbf +--- /dev/null ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -0,0 +1,2957 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 ++ ++/* Yuck! DRM headers need system headers included first.. but we have to ++ * include it before shared/missing.h to avoid redefining ioctl bits */ ++#include ++#include ++#include ++ ++#include "bus-util.h" ++#include "hashmap.h" ++#include "grdev.h" ++#include "grdev-internal.h" ++#include "macro.h" ++#include "udev-util.h" ++#include "util.h" ++ ++#define GRDRM_MAX_TRIES (16) ++ ++typedef struct grdrm_object grdrm_object; ++typedef struct grdrm_plane grdrm_plane; ++typedef struct grdrm_connector grdrm_connector; ++typedef struct grdrm_encoder grdrm_encoder; ++typedef struct grdrm_crtc grdrm_crtc; ++ ++typedef struct grdrm_fb grdrm_fb; ++typedef struct grdrm_pipe grdrm_pipe; ++typedef struct grdrm_card grdrm_card; ++typedef struct unmanaged_card unmanaged_card; ++typedef struct managed_card managed_card; ++ ++/* ++ * Objects ++ */ ++ ++enum { ++ GRDRM_TYPE_CRTC, ++ GRDRM_TYPE_ENCODER, ++ GRDRM_TYPE_CONNECTOR, ++ GRDRM_TYPE_PLANE, ++ GRDRM_TYPE_CNT ++}; ++ ++struct grdrm_object { ++ grdrm_card *card; ++ uint32_t id; ++ uint32_t index; ++ unsigned int type; ++ void (*free_fn) (grdrm_object *object); ++ ++ bool present : 1; ++ bool assigned : 1; ++}; ++ ++struct grdrm_plane { ++ grdrm_object object; ++ ++ struct { ++ uint32_t used_crtc; ++ uint32_t used_fb; ++ uint32_t gamma_size; ++ ++ uint32_t n_crtcs; ++ uint32_t max_crtcs; ++ uint32_t *crtcs; ++ uint32_t n_formats; ++ uint32_t max_formats; ++ uint32_t *formats; ++ } kern; ++}; ++ ++struct grdrm_connector { ++ grdrm_object object; ++ ++ struct { ++ uint32_t type; ++ uint32_t type_id; ++ uint32_t used_encoder; ++ uint32_t connection; ++ uint32_t mm_width; ++ uint32_t mm_height; ++ uint32_t subpixel; ++ ++ uint32_t n_encoders; ++ uint32_t max_encoders; ++ uint32_t *encoders; ++ uint32_t n_modes; ++ uint32_t max_modes; ++ struct drm_mode_modeinfo *modes; ++ uint32_t n_props; ++ uint32_t max_props; ++ uint32_t *prop_ids; ++ uint64_t *prop_values; ++ } kern; ++}; ++ ++struct grdrm_encoder { ++ grdrm_object object; ++ ++ struct { ++ uint32_t type; ++ uint32_t used_crtc; ++ ++ uint32_t n_crtcs; ++ uint32_t max_crtcs; ++ uint32_t *crtcs; ++ uint32_t n_clones; ++ uint32_t max_clones; ++ uint32_t *clones; ++ } kern; ++}; ++ ++struct grdrm_crtc { ++ grdrm_object object; ++ ++ struct { ++ uint32_t used_fb; ++ uint32_t fb_offset_x; ++ uint32_t fb_offset_y; ++ uint32_t gamma_size; ++ ++ uint32_t n_used_connectors; ++ uint32_t max_used_connectors; ++ uint32_t *used_connectors; ++ ++ bool mode_set; ++ struct drm_mode_modeinfo mode; ++ } kern; ++ ++ struct { ++ bool set; ++ uint32_t fb; ++ uint32_t fb_x; ++ uint32_t fb_y; ++ uint32_t gamma; ++ ++ uint32_t n_connectors; ++ uint32_t *connectors; ++ ++ bool mode_set; ++ struct drm_mode_modeinfo mode; ++ } old; ++ ++ struct { ++ struct drm_mode_modeinfo mode; ++ uint32_t n_connectors; ++ uint32_t max_connectors; ++ uint32_t *connectors; ++ } set; ++ ++ grdrm_pipe *pipe; ++ ++ bool applied : 1; ++}; ++ ++#define GRDRM_OBJECT_INIT(_card, _id, _index, _type, _free_fn) ((grdrm_object){ \ ++ .card = (_card), \ ++ .id = (_id), \ ++ .index = (_index), \ ++ .type = (_type), \ ++ .free_fn = (_free_fn), \ ++ }) ++ ++grdrm_object *grdrm_find_object(grdrm_card *card, uint32_t id); ++int grdrm_object_add(grdrm_object *object); ++grdrm_object *grdrm_object_free(grdrm_object *object); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdrm_object*, grdrm_object_free); ++ ++int grdrm_plane_new(grdrm_plane **out, grdrm_card *card, uint32_t id, uint32_t index); ++int grdrm_connector_new(grdrm_connector **out, grdrm_card *card, uint32_t id, uint32_t index); ++int grdrm_encoder_new(grdrm_encoder **out, grdrm_card *card, uint32_t id, uint32_t index); ++int grdrm_crtc_new(grdrm_crtc **out, grdrm_card *card, uint32_t id, uint32_t index); ++ ++#define plane_from_object(_obj) container_of((_obj), grdrm_plane, object) ++#define connector_from_object(_obj) container_of((_obj), grdrm_connector, object) ++#define encoder_from_object(_obj) container_of((_obj), grdrm_encoder, object) ++#define crtc_from_object(_obj) container_of((_obj), grdrm_crtc, object) ++ ++/* ++ * Framebuffers ++ */ ++ ++struct grdrm_fb { ++ grdev_fb base; ++ grdrm_card *card; ++ uint32_t id; ++ uint32_t handles[4]; ++ uint32_t offsets[4]; ++ uint32_t sizes[4]; ++ uint32_t flipid; ++}; ++ ++static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_modeinfo *mode); ++grdrm_fb *grdrm_fb_free(grdrm_fb *fb); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(grdrm_fb*, grdrm_fb_free); ++ ++#define fb_from_base(_fb) container_of((_fb), grdrm_fb, base) ++ ++/* ++ * Pipes ++ */ ++ ++struct grdrm_pipe { ++ grdev_pipe base; ++ grdrm_crtc *crtc; ++ uint32_t counter; ++}; ++ ++#define grdrm_pipe_from_base(_e) container_of((_e), grdrm_pipe, base) ++ ++#define GRDRM_PIPE_NAME_MAX (GRDRM_CARD_NAME_MAX + 1 + DECIMAL_STR_MAX(uint32_t)) ++ ++static const grdev_pipe_vtable grdrm_pipe_vtable; ++ ++static int grdrm_pipe_new(grdrm_pipe **out, grdrm_crtc *crtc, struct drm_mode_modeinfo *mode, size_t n_fbs); ++ ++/* ++ * Cards ++ */ ++ ++struct grdrm_card { ++ grdev_card base; ++ ++ int fd; ++ sd_event_source *fd_src; ++ ++ uint32_t n_crtcs; ++ uint32_t n_encoders; ++ uint32_t n_connectors; ++ uint32_t n_planes; ++ uint32_t max_ids; ++ Hashmap *object_map; ++ ++ bool async_hotplug : 1; ++ bool running : 1; ++ bool ready : 1; ++ bool cap_dumb : 1; ++ bool cap_monotonic : 1; ++}; ++ ++struct unmanaged_card { ++ grdrm_card card; ++ char *devnode; ++}; ++ ++struct managed_card { ++ grdrm_card card; ++ dev_t devnum; ++ ++ sd_bus_slot *slot_pause_device; ++ sd_bus_slot *slot_resume_device; ++ sd_bus_slot *slot_take_device; ++ ++ bool requested : 1; /* TakeDevice() was sent */ ++ bool acquired : 1; /* TakeDevice() was successful */ ++ bool master : 1; /* we are DRM-Master */ ++}; ++ ++#define grdrm_card_from_base(_e) container_of((_e), grdrm_card, base) ++#define unmanaged_card_from_base(_e) \ ++ container_of(grdrm_card_from_base(_e), unmanaged_card, card) ++#define managed_card_from_base(_e) \ ++ container_of(grdrm_card_from_base(_e), managed_card, card) ++ ++#define GRDRM_CARD_INIT(_vtable, _session) ((grdrm_card){ \ ++ .base = GRDEV_CARD_INIT((_vtable), (_session)), \ ++ .fd = -1, \ ++ .max_ids = 32, \ ++ }) ++ ++#define GRDRM_CARD_NAME_MAX (6 + DECIMAL_STR_MAX(unsigned) * 2) ++ ++static const grdev_card_vtable unmanaged_card_vtable; ++static const grdev_card_vtable managed_card_vtable; ++ ++static int grdrm_card_open(grdrm_card *card, int dev_fd); ++static void grdrm_card_close(grdrm_card *card); ++static bool grdrm_card_async(grdrm_card *card, int r); ++ ++/* ++ * The page-flip event of the kernel provides 64bit of arbitrary user-data. As ++ * drivers tend to drop events on intermediate deep mode-sets or because we ++ * might receive events during session activation, we try to avoid allocaing ++ * dynamic data on those events. Instead, we safe the CRTC id plus a 32bit ++ * counter in there. This way, we only get 32bit counters, not 64bit, but that ++ * should be more than enough. On the bright side, we no longer care whether we ++ * lose events. No memory leaks will occur. ++ * Modern DRM drivers might be fixed to no longer leak events, but we want to ++ * be safe. And associating dynamically allocated data with those events is ++ * kinda ugly, anyway. ++ */ ++ ++static uint64_t grdrm_encode_vblank_data(uint32_t id, uint32_t counter) { ++ return id | ((uint64_t)counter << 32); ++} ++ ++static void grdrm_decode_vblank_data(uint64_t data, uint32_t *out_id, uint32_t *out_counter) { ++ if (out_id) ++ *out_id = data & 0xffffffffU; ++ if (out_counter) ++ *out_counter = (data >> 32) & 0xffffffffU; ++} ++ ++static bool grdrm_modes_compatible(const struct drm_mode_modeinfo *a, const struct drm_mode_modeinfo *b) { ++ assert(a); ++ assert(b); ++ ++ /* Test whether both modes are compatible according to our internal ++ * assumptions on modes. This comparison is highly dependent on how ++ * we treat modes in grdrm. If we export mode details, we need to ++ * make this comparison much stricter. */ ++ ++ if (a->hdisplay != b->hdisplay) ++ return false; ++ if (a->vdisplay != b->vdisplay) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * Objects ++ */ ++ ++grdrm_object *grdrm_find_object(grdrm_card *card, uint32_t id) { ++ assert_return(card, NULL); ++ ++ return id > 0 ? hashmap_get(card->object_map, UINT32_TO_PTR(id)) : NULL; ++} ++ ++int grdrm_object_add(grdrm_object *object) { ++ int r; ++ ++ assert(object); ++ assert(object->card); ++ assert(object->id > 0); ++ assert(IN_SET(object->type, GRDRM_TYPE_CRTC, GRDRM_TYPE_ENCODER, GRDRM_TYPE_CONNECTOR, GRDRM_TYPE_PLANE)); ++ assert(object->free_fn); ++ ++ if (object->index >= 32) ++ log_debug("grdrm: %s: object index exceeds 32bit masks: type=%u, index=%" PRIu32, ++ object->card->base.name, object->type, object->index); ++ ++ r = hashmap_put(object->card->object_map, UINT32_TO_PTR(object->id), object); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++grdrm_object *grdrm_object_free(grdrm_object *object) { ++ if (!object) ++ return NULL; ++ ++ assert(object->card); ++ assert(object->id > 0); ++ assert(IN_SET(object->type, GRDRM_TYPE_CRTC, GRDRM_TYPE_ENCODER, GRDRM_TYPE_CONNECTOR, GRDRM_TYPE_PLANE)); ++ assert(object->free_fn); ++ ++ hashmap_remove_value(object->card->object_map, UINT32_TO_PTR(object->id), object); ++ ++ object->free_fn(object); ++ return NULL; ++} ++ ++/* ++ * Planes ++ */ ++ ++static void plane_free(grdrm_object *object) { ++ grdrm_plane *plane = plane_from_object(object); ++ ++ free(plane->kern.formats); ++ free(plane->kern.crtcs); ++ free(plane); ++} ++ ++int grdrm_plane_new(grdrm_plane **out, grdrm_card *card, uint32_t id, uint32_t index) { ++ _cleanup_(grdrm_object_freep) grdrm_object *object = NULL; ++ grdrm_plane *plane; ++ int r; ++ ++ assert(card); ++ ++ plane = new0(grdrm_plane, 1); ++ if (!plane) ++ return -ENOMEM; ++ ++ object = &plane->object; ++ *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_PLANE, plane_free); ++ ++ plane->kern.max_crtcs = 32; ++ plane->kern.crtcs = new0(uint32_t, plane->kern.max_crtcs); ++ if (!plane->kern.crtcs) ++ return -ENOMEM; ++ ++ plane->kern.max_formats = 32; ++ plane->kern.formats = new0(uint32_t, plane->kern.max_formats); ++ if (!plane->kern.formats) ++ return -ENOMEM; ++ ++ r = grdrm_object_add(object); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = plane; ++ object = NULL; ++ return 0; ++} ++ ++static int grdrm_plane_resync(grdrm_plane *plane) { ++ grdrm_card *card = plane->object.card; ++ size_t tries; ++ int r; ++ ++ assert(plane); ++ ++ for (tries = 0; tries < GRDRM_MAX_TRIES; ++tries) { ++ struct drm_mode_get_plane res; ++ grdrm_object *object; ++ bool resized = false; ++ Iterator iter; ++ ++ zero(res); ++ res.plane_id = plane->object.id; ++ res.format_type_ptr = PTR_TO_UINT64(plane->kern.formats); ++ res.count_format_types = plane->kern.max_formats; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_GETPLANE, &res); ++ if (r < 0) { ++ r = -errno; ++ if (r == -ENOENT) { ++ card->async_hotplug = true; ++ r = 0; ++ log_debug("grdrm: %s: plane %u removed during resync", card->base.name, plane->object.id); ++ } else { ++ log_debug("grdrm: %s: cannot retrieve plane %u: %m", card->base.name, plane->object.id); ++ } ++ ++ return r; ++ } ++ ++ plane->kern.n_crtcs = 0; ++ memzero(plane->kern.crtcs, sizeof(uint32_t) * plane->kern.max_crtcs); ++ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (object->type != GRDRM_TYPE_CRTC || object->index >= 32) ++ continue; ++ if (!(res.possible_crtcs & (1 << object->index))) ++ continue; ++ if (plane->kern.n_crtcs >= 32) { ++ log_debug("grdrm: %s: possible_crtcs of plane %" PRIu32 " exceeds 32bit mask", ++ card->base.name, plane->object.id); ++ continue; ++ } ++ ++ plane->kern.crtcs[plane->kern.n_crtcs++] = object->id; ++ } ++ ++ if (res.count_format_types > plane->kern.max_formats) { ++ uint32_t max, *t; ++ ++ max = ALIGN_POWER2(res.count_format_types); ++ if (!max || max > UINT16_MAX) { ++ log_debug("grdrm: %s: excessive plane resource limit: %" PRIu32, card->base.name, max); ++ return -ERANGE; ++ } ++ ++ t = realloc(plane->kern.formats, sizeof(*t) * max); ++ if (!t) ++ return -ENOMEM; ++ ++ plane->kern.formats = t; ++ plane->kern.max_formats = max; ++ resized = true; ++ } ++ ++ if (resized) ++ continue; ++ ++ plane->kern.n_formats = res.count_format_types; ++ plane->kern.used_crtc = res.crtc_id; ++ plane->kern.used_fb = res.fb_id; ++ plane->kern.gamma_size = res.gamma_size; ++ ++ break; ++ } ++ ++ if (tries >= GRDRM_MAX_TRIES) { ++ log_debug("grdrm: %s: plane %u not settled for retrieval", card->base.name, plane->object.id); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Connectors ++ */ ++ ++static void connector_free(grdrm_object *object) { ++ grdrm_connector *connector = connector_from_object(object); ++ ++ free(connector->kern.prop_values); ++ free(connector->kern.prop_ids); ++ free(connector->kern.modes); ++ free(connector->kern.encoders); ++ free(connector); ++} ++ ++int grdrm_connector_new(grdrm_connector **out, grdrm_card *card, uint32_t id, uint32_t index) { ++ _cleanup_(grdrm_object_freep) grdrm_object *object = NULL; ++ grdrm_connector *connector; ++ int r; ++ ++ assert(card); ++ ++ connector = new0(grdrm_connector, 1); ++ if (!connector) ++ return -ENOMEM; ++ ++ object = &connector->object; ++ *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_CONNECTOR, connector_free); ++ ++ connector->kern.max_encoders = 32; ++ connector->kern.encoders = new0(uint32_t, connector->kern.max_encoders); ++ if (!connector->kern.encoders) ++ return -ENOMEM; ++ ++ connector->kern.max_modes = 32; ++ connector->kern.modes = new0(struct drm_mode_modeinfo, connector->kern.max_modes); ++ if (!connector->kern.modes) ++ return -ENOMEM; ++ ++ connector->kern.max_props = 32; ++ connector->kern.prop_ids = new0(uint32_t, connector->kern.max_props); ++ connector->kern.prop_values = new0(uint64_t, connector->kern.max_props); ++ if (!connector->kern.prop_ids || !connector->kern.prop_values) ++ return -ENOMEM; ++ ++ r = grdrm_object_add(object); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = connector; ++ object = NULL; ++ return 0; ++} ++ ++static int grdrm_connector_resync(grdrm_connector *connector) { ++ grdrm_card *card = connector->object.card; ++ size_t tries; ++ int r; ++ ++ assert(connector); ++ ++ for (tries = 0; tries < GRDRM_MAX_TRIES; ++tries) { ++ struct drm_mode_get_connector res; ++ bool resized = false; ++ uint32_t max; ++ ++ zero(res); ++ res.connector_id = connector->object.id; ++ res.encoders_ptr = PTR_TO_UINT64(connector->kern.encoders); ++ res.props_ptr = PTR_TO_UINT64(connector->kern.prop_ids); ++ res.prop_values_ptr = PTR_TO_UINT64(connector->kern.prop_values); ++ res.count_encoders = connector->kern.max_encoders; ++ res.count_props = connector->kern.max_props; ++ ++ /* Retrieve modes only if we have none. This avoids expensive ++ * EDID reads in the kernel, that can slow down resyncs ++ * considerably! */ ++ if (connector->kern.n_modes == 0) { ++ res.modes_ptr = PTR_TO_UINT64(connector->kern.modes); ++ res.count_modes = connector->kern.max_modes; ++ } ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_GETCONNECTOR, &res); ++ if (r < 0) { ++ r = -errno; ++ if (r == -ENOENT) { ++ card->async_hotplug = true; ++ r = 0; ++ log_debug("grdrm: %s: connector %u removed during resync", card->base.name, connector->object.id); ++ } else { ++ log_debug("grdrm: %s: cannot retrieve connector %u: %m", card->base.name, connector->object.id); ++ } ++ ++ return r; ++ } ++ ++ if (res.count_encoders > connector->kern.max_encoders) { ++ uint32_t *t; ++ ++ max = ALIGN_POWER2(res.count_encoders); ++ if (!max || max > UINT16_MAX) { ++ log_debug("grdrm: %s: excessive connector resource limit: %" PRIu32, card->base.name, max); ++ return -ERANGE; ++ } ++ ++ t = realloc(connector->kern.encoders, sizeof(*t) * max); ++ if (!t) ++ return -ENOMEM; ++ ++ connector->kern.encoders = t; ++ connector->kern.max_encoders = max; ++ resized = true; ++ } ++ ++ if (res.count_modes > connector->kern.max_modes) { ++ struct drm_mode_modeinfo *t; ++ ++ max = ALIGN_POWER2(res.count_modes); ++ if (!max || max > UINT16_MAX) { ++ log_debug("grdrm: %s: excessive connector resource limit: %" PRIu32, card->base.name, max); ++ return -ERANGE; ++ } ++ ++ t = realloc(connector->kern.modes, sizeof(*t) * max); ++ if (!t) ++ return -ENOMEM; ++ ++ connector->kern.modes = t; ++ connector->kern.max_modes = max; ++ resized = true; ++ } ++ ++ if (res.count_props > connector->kern.max_props) { ++ uint32_t *tids; ++ uint64_t *tvals; ++ ++ max = ALIGN_POWER2(res.count_props); ++ if (!max || max > UINT16_MAX) { ++ log_debug("grdrm: %s: excessive connector resource limit: %" PRIu32, card->base.name, max); ++ return -ERANGE; ++ } ++ ++ tids = realloc(connector->kern.prop_ids, sizeof(*tids) * max); ++ if (!tids) ++ return -ENOMEM; ++ connector->kern.prop_ids = tids; ++ ++ tvals = realloc(connector->kern.prop_values, sizeof(*tvals) * max); ++ if (!tvals) ++ return -ENOMEM; ++ connector->kern.prop_values = tvals; ++ ++ connector->kern.max_props = max; ++ resized = true; ++ } ++ ++ if (resized) ++ continue; ++ ++ connector->kern.n_encoders = res.count_encoders; ++ connector->kern.n_modes = res.count_modes; ++ connector->kern.n_props = res.count_props; ++ connector->kern.type = res.connector_type; ++ connector->kern.type_id = res.connector_type_id; ++ connector->kern.used_encoder = res.encoder_id; ++ connector->kern.connection = res.connection; ++ connector->kern.mm_width = res.mm_width; ++ connector->kern.mm_height = res.mm_height; ++ connector->kern.subpixel = res.subpixel; ++ ++ break; ++ } ++ ++ if (tries >= GRDRM_MAX_TRIES) { ++ log_debug("grdrm: %s: connector %u not settled for retrieval", card->base.name, connector->object.id); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Encoders ++ */ ++ ++static void encoder_free(grdrm_object *object) { ++ grdrm_encoder *encoder = encoder_from_object(object); ++ ++ free(encoder->kern.clones); ++ free(encoder->kern.crtcs); ++ free(encoder); ++} ++ ++int grdrm_encoder_new(grdrm_encoder **out, grdrm_card *card, uint32_t id, uint32_t index) { ++ _cleanup_(grdrm_object_freep) grdrm_object *object = NULL; ++ grdrm_encoder *encoder; ++ int r; ++ ++ assert(card); ++ ++ encoder = new0(grdrm_encoder, 1); ++ if (!encoder) ++ return -ENOMEM; ++ ++ object = &encoder->object; ++ *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_ENCODER, encoder_free); ++ ++ encoder->kern.max_crtcs = 32; ++ encoder->kern.crtcs = new0(uint32_t, encoder->kern.max_crtcs); ++ if (!encoder->kern.crtcs) ++ return -ENOMEM; ++ ++ encoder->kern.max_clones = 32; ++ encoder->kern.clones = new0(uint32_t, encoder->kern.max_clones); ++ if (!encoder->kern.clones) ++ return -ENOMEM; ++ ++ r = grdrm_object_add(object); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = encoder; ++ object = NULL; ++ return 0; ++} ++ ++static int grdrm_encoder_resync(grdrm_encoder *encoder) { ++ grdrm_card *card = encoder->object.card; ++ struct drm_mode_get_encoder res; ++ grdrm_object *object; ++ Iterator iter; ++ int r; ++ ++ assert(encoder); ++ ++ zero(res); ++ res.encoder_id = encoder->object.id; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_GETENCODER, &res); ++ if (r < 0) { ++ r = -errno; ++ if (r == -ENOENT) { ++ card->async_hotplug = true; ++ r = 0; ++ log_debug("grdrm: %s: encoder %u removed during resync", card->base.name, encoder->object.id); ++ } else { ++ log_debug("grdrm: %s: cannot retrieve encoder %u: %m", card->base.name, encoder->object.id); ++ } ++ ++ return r; ++ } ++ ++ encoder->kern.type = res.encoder_type; ++ encoder->kern.used_crtc = res.crtc_id; ++ ++ encoder->kern.n_crtcs = 0; ++ memzero(encoder->kern.crtcs, sizeof(uint32_t) * encoder->kern.max_crtcs); ++ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (object->type != GRDRM_TYPE_CRTC || object->index >= 32) ++ continue; ++ if (!(res.possible_crtcs & (1 << object->index))) ++ continue; ++ if (encoder->kern.n_crtcs >= 32) { ++ log_debug("grdrm: %s: possible_crtcs exceeds 32bit mask", card->base.name); ++ continue; ++ } ++ ++ encoder->kern.crtcs[encoder->kern.n_crtcs++] = object->id; ++ } ++ ++ encoder->kern.n_clones = 0; ++ memzero(encoder->kern.clones, sizeof(uint32_t) * encoder->kern.max_clones); ++ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (object->type != GRDRM_TYPE_ENCODER || object->index >= 32) ++ continue; ++ if (!(res.possible_clones & (1 << object->index))) ++ continue; ++ if (encoder->kern.n_clones >= 32) { ++ log_debug("grdrm: %s: possible_encoders exceeds 32bit mask", card->base.name); ++ continue; ++ } ++ ++ encoder->kern.clones[encoder->kern.n_clones++] = object->id; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Crtcs ++ */ ++ ++static void crtc_free(grdrm_object *object) { ++ grdrm_crtc *crtc = crtc_from_object(object); ++ ++ if (crtc->pipe) ++ grdev_pipe_free(&crtc->pipe->base); ++ free(crtc->set.connectors); ++ free(crtc->old.connectors); ++ free(crtc->kern.used_connectors); ++ free(crtc); ++} ++ ++int grdrm_crtc_new(grdrm_crtc **out, grdrm_card *card, uint32_t id, uint32_t index) { ++ _cleanup_(grdrm_object_freep) grdrm_object *object = NULL; ++ grdrm_crtc *crtc; ++ int r; ++ ++ assert(card); ++ ++ crtc = new0(grdrm_crtc, 1); ++ if (!crtc) ++ return -ENOMEM; ++ ++ object = &crtc->object; ++ *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_CRTC, crtc_free); ++ ++ crtc->kern.max_used_connectors = 32; ++ crtc->kern.used_connectors = new0(uint32_t, crtc->kern.max_used_connectors); ++ if (!crtc->kern.used_connectors) ++ return -ENOMEM; ++ ++ crtc->old.connectors = new0(uint32_t, crtc->kern.max_used_connectors); ++ if (!crtc->old.connectors) ++ return -ENOMEM; ++ ++ r = grdrm_object_add(object); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = crtc; ++ object = NULL; ++ return 0; ++} ++ ++static int grdrm_crtc_resync(grdrm_crtc *crtc) { ++ grdrm_card *card = crtc->object.card; ++ struct drm_mode_crtc res = { .crtc_id = crtc->object.id }; ++ int r; ++ ++ assert(crtc); ++ ++ /* make sure we can cache any combination later */ ++ if (card->n_connectors > crtc->kern.max_used_connectors) { ++ uint32_t max, *t; ++ ++ max = ALIGN_POWER2(card->n_connectors); ++ if (!max) ++ return -ENOMEM; ++ ++ t = realloc_multiply(crtc->kern.used_connectors, sizeof(*t), max); ++ if (!t) ++ return -ENOMEM; ++ ++ crtc->kern.used_connectors = t; ++ crtc->kern.max_used_connectors = max; ++ ++ if (!crtc->old.set) { ++ crtc->old.connectors = calloc(sizeof(*t), max); ++ if (!crtc->old.connectors) ++ return -ENOMEM; ++ } ++ } ++ ++ /* GETCRTC doesn't return connectors. We have to read all ++ * encoder-state and deduce the setup ourselves.. */ ++ crtc->kern.n_used_connectors = 0; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_GETCRTC, &res); ++ if (r < 0) { ++ r = -errno; ++ if (r == -ENOENT) { ++ card->async_hotplug = true; ++ r = 0; ++ log_debug("grdrm: %s: crtc %u removed during resync", card->base.name, crtc->object.id); ++ } else { ++ log_debug("grdrm: %s: cannot retrieve crtc %u: %m", card->base.name, crtc->object.id); ++ } ++ ++ return r; ++ } ++ ++ crtc->kern.used_fb = res.fb_id; ++ crtc->kern.fb_offset_x = res.x; ++ crtc->kern.fb_offset_y = res.y; ++ crtc->kern.gamma_size = res.gamma_size; ++ crtc->kern.mode_set = res.mode_valid; ++ crtc->kern.mode = res.mode; ++ ++ return 0; ++} ++ ++static void grdrm_crtc_assign(grdrm_crtc *crtc, grdrm_connector *connector) { ++ uint32_t n_connectors; ++ int r; ++ ++ assert(crtc); ++ assert(!crtc->object.assigned); ++ assert(!connector || !connector->object.assigned); ++ ++ /* always mark both as assigned; even if assignments cannot be set */ ++ crtc->object.assigned = true; ++ if (connector) ++ connector->object.assigned = true; ++ ++ /* we will support hw clone mode in the future */ ++ n_connectors = connector ? 1 : 0; ++ ++ /* bail out if configuration is preserved */ ++ if (crtc->set.n_connectors == n_connectors && ++ (n_connectors == 0 || crtc->set.connectors[0] == connector->object.id)) ++ return; ++ ++ crtc->applied = false; ++ crtc->set.n_connectors = 0; ++ ++ if (n_connectors > crtc->set.max_connectors) { ++ uint32_t max, *t; ++ ++ max = ALIGN_POWER2(n_connectors); ++ if (!max) { ++ r = -ENOMEM; ++ goto error; ++ } ++ ++ t = realloc(crtc->set.connectors, sizeof(*t) * max); ++ if (!t) { ++ r = -ENOMEM; ++ goto error; ++ } ++ ++ crtc->set.connectors = t; ++ crtc->set.max_connectors = max; ++ } ++ ++ if (connector) { ++ struct drm_mode_modeinfo *m, *pref = NULL; ++ uint32_t i; ++ ++ for (i = 0; i < connector->kern.n_modes; ++i) { ++ m = &connector->kern.modes[i]; ++ ++ /* ignore 3D modes by default */ ++ if (m->flags & DRM_MODE_FLAG_3D_MASK) ++ continue; ++ ++ if (!pref) { ++ pref = m; ++ continue; ++ } ++ ++ /* use PREFERRED over non-PREFERRED */ ++ if ((pref->type & DRM_MODE_TYPE_PREFERRED) && ++ !(m->type & DRM_MODE_TYPE_PREFERRED)) ++ continue; ++ ++ /* use DRIVER over non-PREFERRED|DRIVER */ ++ if ((pref->type & DRM_MODE_TYPE_DRIVER) && ++ !(m->type & (DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED))) ++ continue; ++ ++ /* always prefer higher resolution */ ++ if (pref->hdisplay > m->hdisplay || ++ (pref->hdisplay == m->hdisplay && pref->vdisplay > m->vdisplay)) ++ continue; ++ ++ pref = m; ++ } ++ ++ if (pref) { ++ crtc->set.mode = *pref; ++ crtc->set.n_connectors = 1; ++ crtc->set.connectors[0] = connector->object.id; ++ log_debug("grdrm: %s: assigned connector %" PRIu32 " to crtc %" PRIu32 " with mode %s", ++ crtc->object.card->base.name, connector->object.id, crtc->object.id, pref->name); ++ } else { ++ log_debug("grdrm: %s: connector %" PRIu32 " to be assigned but has no valid mode", ++ crtc->object.card->base.name, connector->object.id); ++ } ++ } ++ ++ return; ++ ++error: ++ log_debug("grdrm: %s: cannot assign crtc %" PRIu32 ": %s", ++ crtc->object.card->base.name, crtc->object.id, strerror(-r)); ++} ++ ++static void grdrm_crtc_expose(grdrm_crtc *crtc) { ++ grdrm_pipe *pipe; ++ grdrm_fb *fb; ++ size_t i; ++ int r; ++ ++ assert(crtc); ++ assert(crtc->object.assigned); ++ ++ if (crtc->set.n_connectors < 1) { ++ if (crtc->pipe) ++ grdev_pipe_free(&crtc->pipe->base); ++ crtc->pipe = NULL; ++ return; ++ } ++ ++ pipe = crtc->pipe; ++ if (pipe) { ++ if (pipe->base.width != crtc->set.mode.hdisplay || ++ pipe->base.height != crtc->set.mode.vdisplay) { ++ grdev_pipe_free(&pipe->base); ++ crtc->pipe = NULL; ++ pipe = NULL; ++ } ++ } ++ ++ if (crtc->pipe) { ++ pipe->base.front = NULL; ++ pipe->base.back = NULL; ++ for (i = 0; i < pipe->base.max_fbs; ++i) { ++ fb = fb_from_base(pipe->base.fbs[i]); ++ if (fb->id == crtc->kern.used_fb) ++ pipe->base.front = &fb->base; ++ else if (!fb->flipid) ++ pipe->base.back = &fb->base; ++ } ++ } else { ++ r = grdrm_pipe_new(&pipe, crtc, &crtc->set.mode, 2); ++ if (r < 0) { ++ log_debug("grdrm: %s: cannot create pipe for crtc %" PRIu32 ": %s", ++ crtc->object.card->base.name, crtc->object.id, strerror(-r)); ++ return; ++ } ++ ++ for (i = 0; i < pipe->base.max_fbs; ++i) { ++ r = grdrm_fb_new(&fb, crtc->object.card, &crtc->set.mode); ++ if (r < 0) { ++ log_debug("grdrm: %s: cannot allocate framebuffer for crtc %" PRIu32 ": %s", ++ crtc->object.card->base.name, crtc->object.id, strerror(-r)); ++ grdev_pipe_free(&pipe->base); ++ return; ++ } ++ ++ pipe->base.fbs[i] = &fb->base; ++ } ++ ++ pipe->base.front = NULL; ++ pipe->base.back = pipe->base.fbs[0]; ++ crtc->pipe = pipe; ++ } ++ ++ grdev_pipe_ready(&crtc->pipe->base, true); ++} ++ ++static void grdrm_crtc_commit(grdrm_crtc *crtc) { ++ struct drm_mode_crtc_page_flip page_flip = { .crtc_id = crtc->object.id }; ++ struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id }; ++ grdrm_card *card = crtc->object.card; ++ grdrm_pipe *pipe; ++ grdev_fb **slot; ++ grdrm_fb *fb; ++ uint32_t cnt; ++ size_t i; ++ int r; ++ ++ assert(crtc); ++ assert(crtc->object.assigned); ++ ++ pipe = crtc->pipe; ++ if (!pipe) { ++ /* If a crtc is not assigned any connector, we want any ++ * previous setup to be cleared, so make sure the CRTC is ++ * disabled. Otherwise, there might be content on the CRTC ++ * while we run, which is not what we want. ++ * If you want to avoid modesets on specific CRTCs, you should ++ * still keep their assignment, but never enable the resulting ++ * pipe. This way, we wouldn't touch it at all. */ ++ if (!crtc->applied) { ++ crtc->applied = true; ++ r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot shutdown crtc %" PRIu32 ": %m", ++ card->base.name, crtc->object.id); ++ ++ grdrm_card_async(card, r); ++ return; ++ } ++ ++ log_debug("grdrm: %s: crtc %" PRIu32 " applied via shutdown", ++ card->base.name, crtc->object.id); ++ } ++ ++ return; ++ } ++ ++ /* we always fully ignore disabled pipes */ ++ if (!pipe->base.enabled) ++ return; ++ ++ assert(crtc->set.n_connectors > 0); ++ ++ if (pipe->base.flip) ++ slot = &pipe->base.back; ++ else if (!crtc->applied) ++ slot = &pipe->base.front; ++ else ++ return; ++ ++ if (!*slot) ++ return; ++ ++ fb = fb_from_base(*slot); ++ ++ if (crtc->applied || grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode)) { ++ cnt = ++pipe->counter ? : ++pipe->counter; ++ page_flip.fb_id = fb->id; ++ page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT; ++ page_flip.user_data = grdrm_encode_vblank_data(crtc->object.id, cnt); ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_PAGE_FLIP, &page_flip); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m", ++ card->base.name, crtc->object.id); ++ ++ if (grdrm_card_async(card, r)) ++ return; ++ ++ /* fall through to deep modeset */ ++ } else { ++ if (!crtc->applied) { ++ log_debug("grdrm: %s: crtc %" PRIu32 " applied via page flip", ++ card->base.name, crtc->object.id); ++ crtc->applied = true; ++ } ++ ++ pipe->base.flipping = true; ++ pipe->counter = cnt; ++ fb->flipid = cnt; ++ *slot = NULL; ++ ++ if (!pipe->base.back) { ++ for (i = 0; i < pipe->base.max_fbs; ++i) { ++ if (!pipe->base.fbs[i]) ++ continue; ++ ++ fb = fb_from_base(pipe->base.fbs[i]); ++ if (&fb->base == pipe->base.front) ++ continue; ++ if (fb->flipid) ++ continue; ++ ++ pipe->base.back = &fb->base; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (!crtc->applied) { ++ set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->set.connectors); ++ set_crtc.count_connectors = crtc->set.n_connectors; ++ set_crtc.fb_id = fb->id; ++ set_crtc.x = 0; ++ set_crtc.y = 0; ++ set_crtc.mode_valid = 1; ++ set_crtc.mode = crtc->set.mode; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot set crtc %" PRIu32 ": %m", ++ card->base.name, crtc->object.id); ++ ++ grdrm_card_async(card, r); ++ return; ++ } ++ ++ if (!crtc->applied) { ++ log_debug("grdrm: %s: crtc %" PRIu32 " applied via deep modeset", ++ card->base.name, crtc->object.id); ++ crtc->applied = true; ++ } ++ ++ *slot = NULL; ++ pipe->base.front = &fb->base; ++ fb->flipid = 0; ++ ++pipe->counter; ++ pipe->base.flipping = false; ++ ++ if (!pipe->base.back) { ++ for (i = 0; i < pipe->base.max_fbs; ++i) { ++ if (!pipe->base.fbs[i]) ++ continue; ++ ++ fb = fb_from_base(pipe->base.fbs[i]); ++ if (&fb->base == pipe->base.front) ++ continue; ++ ++ fb->flipid = 0; ++ pipe->base.back = &fb->base; ++ break; ++ } ++ } ++ } ++ ++ pipe->base.flip = false; ++} ++ ++static void grdrm_crtc_restore(grdrm_crtc *crtc) { ++ struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id }; ++ grdrm_card *card = crtc->object.card; ++ int r; ++ ++ if (!crtc->old.set) ++ return; ++ ++ set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->old.connectors); ++ set_crtc.count_connectors = crtc->old.n_connectors; ++ set_crtc.fb_id = crtc->old.fb; ++ set_crtc.x = crtc->old.fb_x; ++ set_crtc.y = crtc->old.fb_y; ++ set_crtc.gamma_size = crtc->old.gamma; ++ set_crtc.mode_valid = crtc->old.mode_set; ++ set_crtc.mode = crtc->old.mode; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot restore crtc %" PRIu32 ": %m", ++ card->base.name, crtc->object.id); ++ ++ grdrm_card_async(card, r); ++ return; ++ } ++ ++ if (crtc->pipe) { ++ ++crtc->pipe->counter; ++ crtc->pipe->base.front = NULL; ++ crtc->pipe->base.flipping = false; ++ } ++ ++ log_debug("grdrm: %s: crtc %" PRIu32 " restored", card->base.name, crtc->object.id); ++} ++ ++static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct drm_event_vblank *event) { ++ bool flipped = false; ++ grdrm_pipe *pipe; ++ grdrm_fb *back = NULL; ++ size_t i; ++ ++ assert(crtc); ++ assert(event); ++ ++ pipe = crtc->pipe; ++ if (!pipe) ++ return; ++ ++ /* We got a page-flip event. To be safe, we reset all FBs on the same ++ * pipe that have smaller flipids than the flip we got as we know they ++ * are executed in order. We need to do this to guarantee ++ * queue-overflows or other missed events don't cause starvation. ++ * Furthermore, if we find the exact FB this event is for, *and* this ++ * is the most recent event, we mark it as front FB and raise a ++ * frame event. */ ++ ++ for (i = 0; i < pipe->base.max_fbs; ++i) { ++ grdrm_fb *fb; ++ ++ if (!pipe->base.fbs[i]) ++ continue; ++ ++ fb = fb_from_base(pipe->base.fbs[i]); ++ if (counter != 0 && counter == pipe->counter && fb->flipid == counter) { ++ pipe->base.front = &fb->base; ++ flipped = true; ++ } ++ ++ if (counter - fb->flipid < UINT16_MAX) { ++ fb->flipid = 0; ++ back = fb; ++ } else if (fb->flipid == 0) { ++ back = fb; ++ } ++ } ++ ++ if (!pipe->base.back) ++ pipe->base.back = &back->base; ++ ++ if (flipped) { ++ crtc->pipe->base.flipping = false; ++ grdev_pipe_frame(&pipe->base); ++ } ++} ++ ++/* ++ * Framebuffers ++ */ ++ ++static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_modeinfo *mode) { ++ _cleanup_(grdrm_fb_freep) grdrm_fb *fb = NULL; ++ struct drm_mode_create_dumb create_dumb = { }; ++ struct drm_mode_map_dumb map_dumb = { }; ++ struct drm_mode_fb_cmd2 add_fb = { }; ++ unsigned int i; ++ int r; ++ ++ assert_return(out, -EINVAL); ++ assert_return(card, -EINVAL); ++ ++ fb = new0(grdrm_fb, 1); ++ if (!fb) ++ return -ENOMEM; ++ ++ /* TODO: we should choose a compatible format of the previous CRTC ++ * setting to allow page-flip to it. Only choose fallback if the ++ * previous setting was crap (non xrgb32'ish). */ ++ ++ fb->card = card; ++ fb->base.format = DRM_FORMAT_XRGB8888; ++ fb->base.width = mode->hdisplay; ++ fb->base.height = mode->vdisplay; ++ ++ for (i = 0; i < ELEMENTSOF(fb->base.maps); ++i) ++ fb->base.maps[i] = MAP_FAILED; ++ ++ create_dumb.width = fb->base.width; ++ create_dumb.height = fb->base.height; ++ create_dumb.bpp = 32; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot create dumb buffer %" PRIu32 "x%" PRIu32": %m", ++ card->base.name, fb->base.width, fb->base.height); ++ return r; ++ } ++ ++ fb->handles[0] = create_dumb.handle; ++ fb->base.strides[0] = create_dumb.pitch; ++ fb->sizes[0] = create_dumb.size; ++ ++ map_dumb.handle = fb->handles[0]; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot map dumb buffer %" PRIu32 "x%" PRIu32": %m", ++ card->base.name, fb->base.width, fb->base.height); ++ return r; ++ } ++ ++ fb->base.maps[0] = mmap(0, fb->sizes[0], PROT_WRITE, MAP_SHARED, card->fd, map_dumb.offset); ++ if (fb->base.maps[0] == MAP_FAILED) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot memory-map dumb buffer %" PRIu32 "x%" PRIu32": %m", ++ card->base.name, fb->base.width, fb->base.height); ++ return r; ++ } ++ ++ memzero(fb->base.maps[0], fb->sizes[0]); ++ ++ add_fb.width = fb->base.width; ++ add_fb.height = fb->base.height; ++ add_fb.pixel_format = fb->base.format; ++ add_fb.flags = 0; ++ memcpy(add_fb.handles, fb->handles, sizeof(fb->handles)); ++ memcpy(add_fb.pitches, fb->base.strides, sizeof(fb->base.strides)); ++ memcpy(add_fb.offsets, fb->offsets, sizeof(fb->offsets)); ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_ADDFB2, &add_fb); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot add framebuffer %" PRIu32 "x%" PRIu32": %m", ++ card->base.name, fb->base.width, fb->base.height); ++ return r; ++ } ++ ++ fb->id = add_fb.fb_id; ++ ++ *out = fb; ++ fb = NULL; ++ return 0; ++} ++ ++grdrm_fb *grdrm_fb_free(grdrm_fb *fb) { ++ unsigned int i; ++ ++ if (!fb) ++ return NULL; ++ ++ assert(fb->card); ++ ++ if (fb->id > 0 && fb->card->fd >= 0) ++ ioctl(fb->card->fd, DRM_IOCTL_MODE_RMFB, fb->id); ++ ++ for (i = 0; i < ELEMENTSOF(fb->handles); ++i) { ++ struct drm_mode_destroy_dumb destroy_dumb = { }; ++ ++ if (fb->base.maps[i] != MAP_FAILED) ++ munmap(fb->base.maps[i], fb->sizes[i]); ++ ++ if (fb->handles[i] > 0 && fb->card->fd >= 0) { ++ destroy_dumb.handle = fb->handles[i]; ++ ioctl(fb->card->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); ++ } ++ } ++ ++ free(fb); ++ ++ return NULL; ++} ++ ++/* ++ * Pipes ++ */ ++ ++static void grdrm_pipe_name(char *out, grdrm_crtc *crtc) { ++ /* @out must be at least of size GRDRM_PIPE_NAME_MAX */ ++ sprintf(out, "%s/%" PRIu32, crtc->object.card->base.name, crtc->object.id); ++} ++ ++static int grdrm_pipe_new(grdrm_pipe **out, grdrm_crtc *crtc, struct drm_mode_modeinfo *mode, size_t n_fbs) { ++ _cleanup_(grdev_pipe_freep) grdev_pipe *basepipe = NULL; ++ grdrm_card *card = crtc->object.card; ++ char name[GRDRM_PIPE_NAME_MAX]; ++ grdrm_pipe *pipe; ++ int r; ++ ++ assert_return(crtc, -EINVAL); ++ assert_return(grdev_is_drm_card(&card->base), -EINVAL); ++ ++ pipe = new0(grdrm_pipe, 1); ++ if (!pipe) ++ return -ENOMEM; ++ ++ basepipe = &pipe->base; ++ pipe->base = GRDEV_PIPE_INIT(&grdrm_pipe_vtable, &card->base); ++ pipe->crtc = crtc; ++ pipe->base.width = mode->hdisplay; ++ pipe->base.height = mode->vdisplay; ++ ++ grdrm_pipe_name(name, crtc); ++ r = grdev_pipe_add(&pipe->base, name, n_fbs); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = pipe; ++ basepipe = NULL; ++ return 0; ++} ++ ++static void grdrm_pipe_free(grdev_pipe *basepipe) { ++ grdrm_pipe *pipe = grdrm_pipe_from_base(basepipe); ++ size_t i; ++ ++ assert(pipe->crtc); ++ ++ for (i = 0; i < pipe->base.max_fbs; ++i) ++ if (pipe->base.fbs[i]) ++ grdrm_fb_free(fb_from_base(pipe->base.fbs[i])); ++ ++ free(pipe); ++} ++ ++static const grdev_pipe_vtable grdrm_pipe_vtable = { ++ .free = grdrm_pipe_free, ++}; ++ ++/* ++ * Cards ++ */ ++ ++static void grdrm_name(char *out, dev_t devnum) { ++ /* @out must be at least of size GRDRM_CARD_NAME_MAX */ ++ sprintf(out, "drm/%u:%u", major(devnum), minor(devnum)); ++} ++ ++static void grdrm_card_print(grdrm_card *card) { ++ grdrm_object *object; ++ grdrm_crtc *crtc; ++ grdrm_encoder *encoder; ++ grdrm_connector *connector; ++ grdrm_plane *plane; ++ Iterator iter; ++ uint32_t i; ++ char *p, *buf; ++ ++ log_debug("grdrm: %s: state dump", card->base.name); ++ ++ log_debug(" crtcs:"); ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (object->type != GRDRM_TYPE_CRTC) ++ continue; ++ ++ crtc = crtc_from_object(object); ++ log_debug(" (id: %u index: %d)", object->id, object->index); ++ ++ if (crtc->kern.mode_set) ++ log_debug(" mode: %dx%d", crtc->kern.mode.hdisplay, crtc->kern.mode.vdisplay); ++ else ++ log_debug(" mode: "); ++ } ++ ++ log_debug(" encoders:"); ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (object->type != GRDRM_TYPE_ENCODER) ++ continue; ++ ++ encoder = encoder_from_object(object); ++ log_debug(" (id: %u index: %d)", object->id, object->index); ++ ++ if (encoder->kern.used_crtc) ++ log_debug(" crtc: %u", encoder->kern.used_crtc); ++ else ++ log_debug(" crtc: "); ++ ++ buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * encoder->kern.n_crtcs + 1); ++ if (buf) { ++ buf[0] = 0; ++ p = buf; ++ ++ for (i = 0; i < encoder->kern.n_crtcs; ++i) ++ p += sprintf(p, " %" PRIu32, encoder->kern.crtcs[i]); ++ ++ log_debug(" possible crtcs:%s", buf); ++ free(buf); ++ } ++ ++ buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * encoder->kern.n_clones + 1); ++ if (buf) { ++ buf[0] = 0; ++ p = buf; ++ ++ for (i = 0; i < encoder->kern.n_clones; ++i) ++ p += sprintf(p, " %" PRIu32, encoder->kern.clones[i]); ++ ++ log_debug(" possible clones:%s", buf); ++ free(buf); ++ } ++ } ++ ++ log_debug(" connectors:"); ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (object->type != GRDRM_TYPE_CONNECTOR) ++ continue; ++ ++ connector = connector_from_object(object); ++ log_debug(" (id: %u index: %d)", object->id, object->index); ++ log_debug(" type: %" PRIu32 "-%" PRIu32 " connection: %" PRIu32 " subpixel: %" PRIu32 " extents: %" PRIu32 "x%" PRIu32, ++ connector->kern.type, connector->kern.type_id, connector->kern.connection, connector->kern.subpixel, ++ connector->kern.mm_width, connector->kern.mm_height); ++ ++ if (connector->kern.used_encoder) ++ log_debug(" encoder: %" PRIu32, connector->kern.used_encoder); ++ else ++ log_debug(" encoder: "); ++ ++ buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * connector->kern.n_encoders + 1); ++ if (buf) { ++ buf[0] = 0; ++ p = buf; ++ ++ for (i = 0; i < connector->kern.n_encoders; ++i) ++ p += sprintf(p, " %" PRIu32, connector->kern.encoders[i]); ++ ++ log_debug(" possible encoders:%s", buf); ++ free(buf); ++ } ++ ++ for (i = 0; i < connector->kern.n_modes; ++i) { ++ struct drm_mode_modeinfo *mode = &connector->kern.modes[i]; ++ log_debug(" mode: %" PRIu32 "x%" PRIu32, mode->hdisplay, mode->vdisplay); ++ } ++ } ++ ++ log_debug(" planes:"); ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (object->type != GRDRM_TYPE_PLANE) ++ continue; ++ ++ plane = plane_from_object(object); ++ log_debug(" (id: %u index: %d)", object->id, object->index); ++ log_debug(" gamma-size: %" PRIu32, plane->kern.gamma_size); ++ ++ if (plane->kern.used_crtc) ++ log_debug(" crtc: %" PRIu32, plane->kern.used_crtc); ++ else ++ log_debug(" crtc: "); ++ ++ buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * plane->kern.n_crtcs + 1); ++ if (buf) { ++ buf[0] = 0; ++ p = buf; ++ ++ for (i = 0; i < plane->kern.n_crtcs; ++i) ++ p += sprintf(p, " %" PRIu32, plane->kern.crtcs[i]); ++ ++ log_debug(" possible crtcs:%s", buf); ++ free(buf); ++ } ++ ++ buf = malloc((DECIMAL_STR_MAX(unsigned int) + 3) * plane->kern.n_formats + 1); ++ if (buf) { ++ buf[0] = 0; ++ p = buf; ++ ++ for (i = 0; i < plane->kern.n_formats; ++i) ++ p += sprintf(p, " 0x%x", (unsigned int)plane->kern.formats[i]); ++ ++ log_debug(" possible formats:%s", buf); ++ free(buf); ++ } ++ } ++} ++ ++static int grdrm_card_resync(grdrm_card *card) { ++ _cleanup_free_ uint32_t *crtc_ids = NULL, *encoder_ids = NULL, *connector_ids = NULL, *plane_ids = NULL; ++ uint32_t allocated = 0; ++ grdrm_object *object; ++ Iterator iter; ++ size_t tries; ++ int r; ++ ++ assert(card); ++ ++ card->async_hotplug = false; ++ allocated = 0; ++ ++ /* mark existing objects for possible removal */ ++ HASHMAP_FOREACH(object, card->object_map, iter) ++ object->present = false; ++ ++ for (tries = 0; tries < GRDRM_MAX_TRIES; ++tries) { ++ struct drm_mode_get_plane_res pres; ++ struct drm_mode_card_res res; ++ uint32_t i, max; ++ ++ if (allocated < card->max_ids) { ++ free(crtc_ids); ++ free(encoder_ids); ++ free(connector_ids); ++ free(plane_ids); ++ crtc_ids = new0(uint32_t, card->max_ids); ++ encoder_ids = new0(uint32_t, card->max_ids); ++ connector_ids = new0(uint32_t, card->max_ids); ++ plane_ids = new0(uint32_t, card->max_ids); ++ ++ if (!crtc_ids || !encoder_ids || !connector_ids || !plane_ids) ++ return -ENOMEM; ++ ++ allocated = card->max_ids; ++ } ++ ++ zero(res); ++ res.crtc_id_ptr = PTR_TO_UINT64(crtc_ids); ++ res.connector_id_ptr = PTR_TO_UINT64(connector_ids); ++ res.encoder_id_ptr = PTR_TO_UINT64(encoder_ids); ++ res.count_crtcs = allocated; ++ res.count_encoders = allocated; ++ res.count_connectors = allocated; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_GETRESOURCES, &res); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot retrieve drm resources: %m", card->base.name); ++ return r; ++ } ++ ++ zero(pres); ++ pres.plane_id_ptr = PTR_TO_UINT64(plane_ids); ++ pres.count_planes = allocated; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &pres); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot retrieve drm plane-resources: %m", card->base.name); ++ return r; ++ } ++ ++ max = MAX(MAX(res.count_crtcs, res.count_encoders), ++ MAX(res.count_connectors, pres.count_planes)); ++ if (max > allocated) { ++ uint32_t n; ++ ++ n = ALIGN_POWER2(max); ++ if (!n || n > UINT16_MAX) { ++ log_debug("grdrm: %s: excessive DRM resource limit: %" PRIu32, card->base.name, max); ++ return -ERANGE; ++ } ++ ++ /* retry with resized buffers */ ++ card->max_ids = n; ++ continue; ++ } ++ ++ /* mark available objects as present */ ++ ++ for (i = 0; i < res.count_crtcs; ++i) { ++ object = grdrm_find_object(card, crtc_ids[i]); ++ if (object && object->type == GRDRM_TYPE_CRTC) { ++ object->present = true; ++ object->index = i; ++ crtc_ids[i] = 0; ++ } ++ } ++ ++ for (i = 0; i < res.count_encoders; ++i) { ++ object = grdrm_find_object(card, encoder_ids[i]); ++ if (object && object->type == GRDRM_TYPE_ENCODER) { ++ object->present = true; ++ object->index = i; ++ encoder_ids[i] = 0; ++ } ++ } ++ ++ for (i = 0; i < res.count_connectors; ++i) { ++ object = grdrm_find_object(card, connector_ids[i]); ++ if (object && object->type == GRDRM_TYPE_CONNECTOR) { ++ object->present = true; ++ object->index = i; ++ connector_ids[i] = 0; ++ } ++ } ++ ++ for (i = 0; i < pres.count_planes; ++i) { ++ object = grdrm_find_object(card, plane_ids[i]); ++ if (object && object->type == GRDRM_TYPE_PLANE) { ++ object->present = true; ++ object->index = i; ++ plane_ids[i] = 0; ++ } ++ } ++ ++ /* drop removed objects */ ++ ++ HASHMAP_FOREACH(object, card->object_map, iter) ++ if (!object->present) ++ grdrm_object_free(object); ++ ++ /* add new objects */ ++ ++ card->n_crtcs = res.count_crtcs; ++ for (i = 0; i < res.count_crtcs; ++i) { ++ if (crtc_ids[i] < 1) ++ continue; ++ ++ r = grdrm_crtc_new(NULL, card, crtc_ids[i], i); ++ if (r < 0) ++ return r; ++ } ++ ++ card->n_encoders = res.count_encoders; ++ for (i = 0; i < res.count_encoders; ++i) { ++ if (encoder_ids[i] < 1) ++ continue; ++ ++ r = grdrm_encoder_new(NULL, card, encoder_ids[i], i); ++ if (r < 0) ++ return r; ++ } ++ ++ card->n_connectors = res.count_connectors; ++ for (i = 0; i < res.count_connectors; ++i) { ++ if (connector_ids[i] < 1) ++ continue; ++ ++ r = grdrm_connector_new(NULL, card, connector_ids[i], i); ++ if (r < 0) ++ return r; ++ } ++ ++ card->n_planes = pres.count_planes; ++ for (i = 0; i < pres.count_planes; ++i) { ++ if (plane_ids[i] < 1) ++ continue; ++ ++ r = grdrm_plane_new(NULL, card, plane_ids[i], i); ++ if (r < 0) ++ return r; ++ } ++ ++ /* re-sync objects after object_map is synced */ ++ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ switch (object->type) { ++ case GRDRM_TYPE_CRTC: ++ r = grdrm_crtc_resync(crtc_from_object(object)); ++ break; ++ case GRDRM_TYPE_ENCODER: ++ r = grdrm_encoder_resync(encoder_from_object(object)); ++ break; ++ case GRDRM_TYPE_CONNECTOR: ++ r = grdrm_connector_resync(connector_from_object(object)); ++ break; ++ case GRDRM_TYPE_PLANE: ++ r = grdrm_plane_resync(plane_from_object(object)); ++ break; ++ default: ++ assert_not_reached("grdrm: invalid object type"); ++ r = 0; ++ } ++ ++ if (r < 0) ++ return r; ++ ++ if (card->async_hotplug) ++ break; ++ } ++ ++ /* if modeset objects change during sync, start over */ ++ if (card->async_hotplug) { ++ card->async_hotplug = false; ++ continue; ++ } ++ ++ /* cache crtc/connector relationship */ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ grdrm_connector *connector; ++ grdrm_encoder *encoder; ++ grdrm_crtc *crtc; ++ ++ if (object->type != GRDRM_TYPE_CONNECTOR) ++ continue; ++ ++ connector = connector_from_object(object); ++ if (connector->kern.connection != 1 || connector->kern.used_encoder < 1) ++ continue; ++ ++ object = grdrm_find_object(card, connector->kern.used_encoder); ++ if (!object || object->type != GRDRM_TYPE_ENCODER) ++ continue; ++ ++ encoder = encoder_from_object(object); ++ if (encoder->kern.used_crtc < 1) ++ continue; ++ ++ object = grdrm_find_object(card, encoder->kern.used_crtc); ++ if (!object || object->type != GRDRM_TYPE_CRTC) ++ continue; ++ ++ crtc = crtc_from_object(object); ++ assert(crtc->kern.n_used_connectors < crtc->kern.max_used_connectors); ++ crtc->kern.used_connectors[crtc->kern.n_used_connectors++] = connector->object.id; ++ } ++ ++ /* cache old crtc settings for later restore */ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ grdrm_crtc *crtc; ++ ++ if (object->type != GRDRM_TYPE_CRTC) ++ continue; ++ ++ crtc = crtc_from_object(object); ++ ++ /* Save data if it is the first time we refresh the CRTC. This data can ++ * be used optionally to restore any previous configuration. For ++ * instance, it allows us to restore VT configurations after we close ++ * our session again. */ ++ if (!crtc->old.set) { ++ crtc->old.fb = crtc->kern.used_fb; ++ crtc->old.fb_x = crtc->kern.fb_offset_x; ++ crtc->old.fb_y = crtc->kern.fb_offset_y; ++ crtc->old.gamma = crtc->kern.gamma_size; ++ crtc->old.n_connectors = crtc->kern.n_used_connectors; ++ if (crtc->old.n_connectors) ++ memcpy(crtc->old.connectors, crtc->kern.used_connectors, sizeof(uint32_t) * crtc->old.n_connectors); ++ crtc->old.mode_set = crtc->kern.mode_set; ++ crtc->old.mode = crtc->kern.mode; ++ crtc->old.set = true; ++ } ++ } ++ ++ /* everything synced */ ++ break; ++ } ++ ++ if (tries >= GRDRM_MAX_TRIES) { ++ /* ++ * Ugh! We were unable to sync the DRM card state due to heavy ++ * hotplugging. This should never happen, so print a debug ++ * message and bail out. The next uevent will trigger ++ * this again. ++ */ ++ ++ log_debug("grdrm: %s: hotplug-storm when syncing card", card->base.name); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static bool card_configure_crtc(grdrm_crtc *crtc, grdrm_connector *connector) { ++ grdrm_card *card = crtc->object.card; ++ grdrm_encoder *encoder; ++ grdrm_object *object; ++ uint32_t i, j; ++ ++ if (crtc->object.assigned || connector->object.assigned) ++ return false; ++ if (connector->kern.connection != 1) ++ return false; ++ ++ for (i = 0; i < connector->kern.n_encoders; ++i) { ++ object = grdrm_find_object(card, connector->kern.encoders[i]); ++ if (!object || object->type != GRDRM_TYPE_ENCODER) ++ continue; ++ ++ encoder = encoder_from_object(object); ++ for (j = 0; j < encoder->kern.n_crtcs; ++j) { ++ if (encoder->kern.crtcs[j] == crtc->object.id) { ++ grdrm_crtc_assign(crtc, connector); ++ return true; ++ } ++ } ++ } ++ ++ return false; ++} ++ ++static void grdrm_card_configure(grdrm_card *card) { ++ /* ++ * Modeset Configuration ++ * This is where we update our modeset configuration and assign ++ * connectors to CRTCs. This means, each connector that we want to ++ * enable needs a CRTC, disabled (or unavailable) connectors are left ++ * alone in the dark. Once all CRTCs are assigned, the remaining CRTCs ++ * are disabled. ++ * Sounds trivial, but there're several caveats: ++ * ++ * * Multiple connectors can be driven by the same CRTC. This is ++ * known as 'hardware clone mode'. Advantage over software clone ++ * mode is that only a single CRTC is needed to drive multiple ++ * displays. However, few hardware supports this and it's a huge ++ * headache to configure on dynamic demands. Therefore, we only ++ * support it if configured statically beforehand. ++ * ++ * * CRTCs are not created equal. Some might be much more poweful ++ * than others, including more advanced plane support. So far, our ++ * CRTC selection is random. You need to supply static ++ * configuration if you want special setups. So far, there is no ++ * proper way to do advanced CRTC selection on dynamic demands. It ++ * is not really clear which demands require what CRTC, so, like ++ * everyone else, we do random CRTC selection unless explicitly ++ * states otherwise. ++ * ++ * * Each Connector has a list of possible encoders that can drive ++ * it, and each encoder has a list of possible CRTCs. If this graph ++ * is a tree, assignment is trivial. However, if not, we cannot ++ * reliably decide on configurations beforehand. The encoder is ++ * always selected by the kernel, so we have to actually set a mode ++ * to know which encoder is used. There is no way to ask the kernel ++ * whether a given configuration is possible. This will change with ++ * atomic-modesetting, but until then, we keep our configurations ++ * simple and assume they work all just fine. If one fails ++ * unexpectedly, we print a warning and disable it. ++ * ++ * Configuring a card consists of several steps: ++ * ++ * 1) First of all, we apply any user-configuration. If a user wants ++ * a fixed configuration, we apply it and preserve it. ++ * So far, we don't support user configuration files, so this step ++ * is skipped. ++ * ++ * 2) Secondly, we need to apply any quirks from hwdb. Some hardware ++ * might only support limited configurations or require special ++ * CRTC/Connector mappings. We read this from hwdb and apply it, if ++ * present. ++ * So far, we don't support this as there is no known quirk, so ++ * this step is skipped. ++ * ++ * 3) As deep modesets are expensive, we try to avoid them if ++ * possible. Therefore, we read the current configuration from the ++ * kernel and try to preserve it, if compatible with our demands. ++ * If not, we break it and reassign it in a following step. ++ * ++ * 4) The main step involves configuring all remaining objects. By ++ * default, all available connectors are enabled, except for those ++ * disabled by user-configuration. We lookup a suitable CRTC for ++ * each connector and assign them. As there might be more ++ * connectors than CRTCs, we apply some ordering so users can ++ * select which connectors are more important right now. ++ * So far, we only apply the default ordering, more might be added ++ * in the future. ++ */ ++ ++ grdrm_object *object; ++ grdrm_crtc *crtc; ++ Iterator i, j; ++ ++ /* clear assignments */ ++ HASHMAP_FOREACH(object, card->object_map, i) ++ object->assigned = false; ++ ++ /* preserve existing configurations */ ++ HASHMAP_FOREACH(object, card->object_map, i) { ++ if (object->type != GRDRM_TYPE_CRTC || object->assigned) ++ continue; ++ ++ crtc = crtc_from_object(object); ++ ++ if (crtc->applied) { ++ /* If our mode is set, preserve it. If no connector is ++ * set, modeset either failed or the pipe is unused. In ++ * both cases, leave it alone. It might be tried again ++ * below in case there're remaining connectors. ++ * Otherwise, try restoring the assignments. If they ++ * are no longer valid, leave the pipe untouched. */ ++ ++ if (crtc->set.n_connectors < 1) ++ continue; ++ ++ assert(crtc->set.n_connectors == 1); ++ ++ object = grdrm_find_object(card, crtc->set.connectors[0]); ++ if (!object || object->type != GRDRM_TYPE_CONNECTOR) ++ continue; ++ ++ card_configure_crtc(crtc, connector_from_object(object)); ++ } else if (crtc->kern.mode_set && crtc->kern.n_used_connectors != 1) { ++ /* If our mode is not set on the pipe, we know the kern ++ * information is valid. Try keeping it. If it's not ++ * possible, leave the pipe untouched for later ++ * assignements. */ ++ ++ object = grdrm_find_object(card, crtc->kern.used_connectors[0]); ++ if (!object || object->type != GRDRM_TYPE_CONNECTOR) ++ continue; ++ ++ card_configure_crtc(crtc, connector_from_object(object)); ++ } ++ } ++ ++ /* assign remaining objects */ ++ HASHMAP_FOREACH(object, card->object_map, i) { ++ if (object->type != GRDRM_TYPE_CRTC || object->assigned) ++ continue; ++ ++ crtc = crtc_from_object(object); ++ ++ HASHMAP_FOREACH(object, card->object_map, j) { ++ if (object->type != GRDRM_TYPE_CONNECTOR) ++ continue; ++ ++ if (card_configure_crtc(crtc, connector_from_object(object))) ++ break; ++ } ++ ++ if (!crtc->object.assigned) ++ grdrm_crtc_assign(crtc, NULL); ++ } ++ ++ /* expose configuration */ ++ HASHMAP_FOREACH(object, card->object_map, i) { ++ if (object->type != GRDRM_TYPE_CRTC) ++ continue; ++ ++ grdrm_crtc_expose(crtc_from_object(object)); ++ } ++} ++ ++static void grdrm_card_hotplug(grdrm_card *card) { ++ int r; ++ ++ assert(card); ++ assert(!card->ready); ++ ++ r = grdrm_card_resync(card); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: cannot re-sync card: %s", ++ card->base.session->name, card->base.name, strerror(-r)); ++ return; ++ } ++ ++ grdev_session_pin(card->base.session); ++ ++ grdrm_card_print(card); ++ grdrm_card_configure(card); ++ card->ready = true; ++ ++ grdev_session_unpin(card->base.session); ++} ++ ++static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ++ grdrm_card *card = userdata; ++ struct drm_event_vblank *vblank; ++ struct drm_event *event; ++ uint32_t id, counter; ++ grdrm_object *object; ++ char buf[4096]; ++ ssize_t l, i; ++ ++ if (revents & (EPOLLHUP | EPOLLERR)) { ++ /* Immediately close device on HUP; no need to flush pending ++ * data.. there're no events we care about here. */ ++ log_debug("grdrm: %s/%s: HUP", card->base.session->name, card->base.name); ++ grdrm_card_close(card); ++ return 0; ++ } ++ ++ if (revents & (EPOLLIN)) { ++ l = read(card->fd, buf, sizeof(buf)); ++ if (l < 0) { ++ if (errno == EAGAIN || errno == EINTR) ++ return 0; ++ ++ log_debug("grdrm: %s/%s: read error: %m", card->base.session->name, card->base.name); ++ grdrm_card_close(card); ++ return 0; ++ } else if ((size_t)l < sizeof(*event)) { ++ log_debug("grdrm: %s/%s: short read of %zd bytes", card->base.session->name, card->base.name, l); ++ return 0; ++ } ++ ++ for (i = 0; i < l; i += event->length) { ++ event = (void*)&buf[i]; ++ ++ if (i + event->length > l) { ++ log_debug("grdrm: %s/%s: truncated event", card->base.session->name, card->base.name); ++ break; ++ } ++ ++ switch (event->type) { ++ case DRM_EVENT_FLIP_COMPLETE: ++ vblank = (void*)event; ++ if (event->length < sizeof(*vblank)) { ++ log_debug("grdrm: %s/%s: truncated vblank event", card->base.session->name, card->base.name); ++ break; ++ } ++ ++ grdrm_decode_vblank_data(vblank->user_data, &id, &counter); ++ object = grdrm_find_object(card, id); ++ if (!object || object->type != GRDRM_TYPE_CRTC) ++ break; ++ ++ grdrm_crtc_flip_complete(crtc_from_object(object), counter, vblank); ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int grdrm_card_add(grdrm_card *card, const char *name) { ++ assert(card); ++ assert(card->fd < 0); ++ ++ card->object_map = hashmap_new(&trivial_hash_ops); ++ if (!card->object_map) ++ return -ENOMEM; ++ ++ return grdev_card_add(&card->base, name); ++} ++ ++static void grdrm_card_destroy(grdrm_card *card) { ++ assert(card); ++ assert(!card->running); ++ assert(card->fd < 0); ++ assert(hashmap_size(card->object_map) == 0); ++ ++ hashmap_free(card->object_map); ++} ++ ++static void grdrm_card_commit(grdev_card *basecard) { ++ grdrm_card *card = grdrm_card_from_base(basecard); ++ grdrm_object *object; ++ Iterator iter; ++ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (!card->ready) ++ break; ++ ++ if (object->type != GRDRM_TYPE_CRTC) ++ continue; ++ ++ grdrm_crtc_commit(crtc_from_object(object)); ++ } ++} ++ ++static void grdrm_card_restore(grdev_card *basecard) { ++ grdrm_card *card = grdrm_card_from_base(basecard); ++ grdrm_object *object; ++ Iterator iter; ++ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ if (!card->ready) ++ break; ++ ++ if (object->type != GRDRM_TYPE_CRTC) ++ continue; ++ ++ grdrm_crtc_restore(crtc_from_object(object)); ++ } ++} ++ ++static void grdrm_card_enable(grdrm_card *card) { ++ assert(card); ++ ++ if (card->fd < 0 || card->running) ++ return; ++ ++ /* ignore cards without DUMB_BUFFER capability */ ++ if (!card->cap_dumb) ++ return; ++ ++ assert(card->fd_src); ++ ++ log_debug("grdrm: %s/%s: enable", card->base.session->name, card->base.name); ++ ++ card->running = true; ++ sd_event_source_set_enabled(card->fd_src, SD_EVENT_ON); ++ grdrm_card_hotplug(card); ++} ++ ++static void grdrm_card_disable(grdrm_card *card) { ++ grdrm_object *object; ++ Iterator iter; ++ ++ assert(card); ++ ++ if (card->fd < 0 || !card->running) ++ return; ++ ++ assert(card->fd_src); ++ ++ log_debug("grdrm: %s/%s: disable", card->base.session->name, card->base.name); ++ ++ card->running = false; ++ card->ready = false; ++ sd_event_source_set_enabled(card->fd_src, SD_EVENT_OFF); ++ ++ /* stop all pipes */ ++ HASHMAP_FOREACH(object, card->object_map, iter) { ++ grdrm_crtc *crtc; ++ ++ if (object->type != GRDRM_TYPE_CRTC) ++ continue; ++ ++ crtc = crtc_from_object(object); ++ crtc->applied = false; ++ if (crtc->pipe) ++ grdev_pipe_ready(&crtc->pipe->base, false); ++ } ++} ++ ++static int grdrm_card_open(grdrm_card *card, int dev_fd) { ++ _cleanup_(grdev_session_unpinp) grdev_session *pin = NULL; ++ _cleanup_close_ int fd = dev_fd; ++ struct drm_get_cap cap; ++ int r, flags; ++ ++ assert(card); ++ assert(dev_fd >= 0); ++ assert(card->fd != dev_fd); ++ ++ pin = grdev_session_pin(card->base.session); ++ grdrm_card_close(card); ++ ++ log_debug("grdrm: %s/%s: open", card->base.session->name, card->base.name); ++ ++ r = fd_nonblock(fd, true); ++ if (r < 0) ++ return r; ++ ++ r = fd_cloexec(fd, true); ++ if (r < 0) ++ return r; ++ ++ flags = fcntl(fd, F_GETFL, 0); ++ if (flags < 0) ++ return -errno; ++ if ((flags & O_ACCMODE) != O_RDWR) ++ return -EACCES; ++ ++ r = sd_event_add_io(card->base.session->context->event, ++ &card->fd_src, ++ fd, ++ EPOLLHUP | EPOLLERR | EPOLLIN, ++ grdrm_card_io_fn, ++ card); ++ if (r < 0) ++ return r; ++ ++ sd_event_source_set_enabled(card->fd_src, SD_EVENT_OFF); ++ ++ card->fd = fd; ++ fd = -1; ++ ++ /* cache DUMB_BUFFER capability */ ++ cap.capability = DRM_CAP_DUMB_BUFFER; ++ cap.value = 0; ++ r = ioctl(card->fd, DRM_IOCTL_GET_CAP, &cap); ++ card->cap_dumb = r >= 0 && cap.value; ++ if (r < 0) ++ log_debug("grdrm: %s/%s: cannot retrieve DUMB_BUFFER capability: %s", ++ card->base.session->name, card->base.name, strerror(-r)); ++ else if (!card->cap_dumb) ++ log_debug("grdrm: %s/%s: DUMB_BUFFER capability not supported", ++ card->base.session->name, card->base.name); ++ ++ /* cache TIMESTAMP_MONOTONIC capability */ ++ cap.capability = DRM_CAP_TIMESTAMP_MONOTONIC; ++ cap.value = 0; ++ r = ioctl(card->fd, DRM_IOCTL_GET_CAP, &cap); ++ card->cap_monotonic = r >= 0 && cap.value; ++ if (r < 0) ++ log_debug("grdrm: %s/%s: cannot retrieve TIMESTAMP_MONOTONIC capability: %s", ++ card->base.session->name, card->base.name, strerror(-r)); ++ else if (!card->cap_monotonic) ++ log_debug("grdrm: %s/%s: TIMESTAMP_MONOTONIC is disabled globally, fix this NOW!", ++ card->base.session->name, card->base.name); ++ ++ return 0; ++} ++ ++static void grdrm_card_close(grdrm_card *card) { ++ grdrm_object *object; ++ ++ if (card->fd < 0) ++ return; ++ ++ log_debug("grdrm: %s/%s: close", card->base.session->name, card->base.name); ++ ++ grdrm_card_disable(card); ++ ++ card->fd_src = sd_event_source_unref(card->fd_src); ++ card->fd = safe_close(card->fd); ++ ++ grdev_session_pin(card->base.session); ++ while ((object = hashmap_first(card->object_map))) ++ grdrm_object_free(object); ++ grdev_session_unpin(card->base.session); ++} ++ ++static bool grdrm_card_async(grdrm_card *card, int r) { ++ switch (r) { ++ case -EACCES: ++ /* If we get EACCES on runtime DRM calls, we lost DRM-Master ++ * (or we did something terribly wrong). Immediately disable ++ * the card, so we stop all pipes and wait to be activated ++ * again. */ ++ grdrm_card_disable(card); ++ break; ++ case -ENOENT: ++ /* DRM objects can be hotplugged at any time. If an object is ++ * removed that we use, we remember that state so a following ++ * call can test for this. ++ * Note that we also get a uevent as followup, this will resync ++ * the whole device. */ ++ card->async_hotplug = true; ++ break; ++ } ++ ++ return !card->ready; ++} ++ ++/* ++ * Unmanaged Cards ++ * The unmanaged DRM card opens the device node for a given DRM device ++ * directly (/dev/dri/cardX) and thus needs sufficient privileges. It opens ++ * the device only if we really require it and releases it as soon as we're ++ * disabled or closed. ++ * The unmanaged element can be used in all situations where you have direct ++ * access to DRM device nodes. Unlike managed DRM elements, it can be used ++ * outside of user sessions and in emergency situations where logind is not ++ * available. ++ */ ++ ++static void unmanaged_card_enable(grdev_card *basecard) { ++ unmanaged_card *cu = unmanaged_card_from_base(basecard); ++ int r, fd; ++ ++ if (cu->card.fd < 0) { ++ /* try open on activation if it failed during allocation */ ++ fd = open(cu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); ++ if (fd < 0) { ++ /* not fatal; simply ignore the device */ ++ log_debug("grdrm: %s/%s: cannot open node %s: %m", ++ basecard->session->name, basecard->name, cu->devnode); ++ return; ++ } ++ ++ /* we might already be DRM-Master by open(); that's fine */ ++ ++ r = grdrm_card_open(&cu->card, fd); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: cannot open: %s", ++ basecard->session->name, basecard->name, strerror(-r)); ++ return; ++ } ++ } ++ ++ r = ioctl(cu->card.fd, DRM_IOCTL_SET_MASTER, 0); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: cannot acquire DRM-Master: %m", ++ basecard->session->name, basecard->name); ++ return; ++ } ++ ++ grdrm_card_enable(&cu->card); ++} ++ ++static void unmanaged_card_disable(grdev_card *basecard) { ++ unmanaged_card *cu = unmanaged_card_from_base(basecard); ++ ++ grdrm_card_disable(&cu->card); ++} ++ ++static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud) { ++ _cleanup_(grdev_card_freep) grdev_card *basecard = NULL; ++ char name[GRDRM_CARD_NAME_MAX]; ++ unmanaged_card *cu; ++ const char *devnode; ++ dev_t devnum; ++ int r, fd; ++ ++ assert_return(session, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ devnode = udev_device_get_devnode(ud); ++ devnum = udev_device_get_devnum(ud); ++ if (!devnode || devnum == 0) ++ return -ENODEV; ++ ++ grdrm_name(name, devnum); ++ ++ cu = new0(unmanaged_card, 1); ++ if (!cu) ++ return -ENOMEM; ++ ++ basecard = &cu->card.base; ++ cu->card = GRDRM_CARD_INIT(&unmanaged_card_vtable, session); ++ ++ cu->devnode = strdup(devnode); ++ if (!cu->devnode) ++ return -ENOMEM; ++ ++ r = grdrm_card_add(&cu->card, name); ++ if (r < 0) ++ return r; ++ ++ /* try to open but ignore errors */ ++ fd = open(cu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); ++ if (fd < 0) { ++ /* not fatal; allow uaccess based control on activation */ ++ log_debug("grdrm: %s/%s: cannot open node %s: %m", ++ basecard->session->name, basecard->name, cu->devnode); ++ } else { ++ /* We might get DRM-Master implicitly on open(); drop it immediately ++ * so we acquire it only once we're actually enabled. */ ++ ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); ++ ++ r = grdrm_card_open(&cu->card, fd); ++ if (r < 0) ++ log_debug("grdrm: %s/%s: cannot open: %s", ++ basecard->session->name, basecard->name, strerror(-r)); ++ } ++ ++ if (out) ++ *out = basecard; ++ basecard = NULL; ++ return 0; ++} ++ ++static void unmanaged_card_free(grdev_card *basecard) { ++ unmanaged_card *cu = unmanaged_card_from_base(basecard); ++ ++ assert(!basecard->enabled); ++ ++ grdrm_card_close(&cu->card); ++ grdrm_card_destroy(&cu->card); ++ free(cu->devnode); ++ free(cu); ++} ++ ++static const grdev_card_vtable unmanaged_card_vtable = { ++ .free = unmanaged_card_free, ++ .enable = unmanaged_card_enable, ++ .disable = unmanaged_card_disable, ++ .commit = grdrm_card_commit, ++ .restore = grdrm_card_restore, ++}; ++ ++/* ++ * Managed Cards ++ * The managed DRM card uses systemd-logind to acquire DRM devices. This ++ * means, we do not open the device node /dev/dri/cardX directly. Instead, ++ * logind passes us a file-descriptor whenever our session is activated. Thus, ++ * we don't need access to the device node directly. ++ * Furthermore, whenever the session is put asleep, logind revokes the ++ * file-descriptor so we loose access to the device. ++ * Managed DRM cards should be preferred over unmanaged DRM cards whenever ++ * you run inside a user session with exclusive device access. ++ */ ++ ++static void managed_card_enable(grdev_card *card) { ++ managed_card *cm = managed_card_from_base(card); ++ ++ /* If the device is manually re-enabled, we try to resume our card ++ * management. Note that we have no control over DRM-Master and the fd, ++ * so we have to take over the state from the last logind event. */ ++ ++ if (cm->master) ++ grdrm_card_enable(&cm->card); ++} ++ ++static void managed_card_disable(grdev_card *card) { ++ managed_card *cm = managed_card_from_base(card); ++ ++ /* If the device is manually disabled, we keep the FD but put our card ++ * management asleep. This way, we can wake up at any time, but don't ++ * touch the device while asleep. */ ++ ++ grdrm_card_disable(&cm->card); ++} ++ ++static int managed_card_pause_device_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ managed_card *cm = userdata; ++ grdev_session *session = cm->card.base.session; ++ uint32_t major, minor; ++ const char *mode; ++ int r; ++ ++ /* ++ * We get PauseDevice() signals from logind whenever a device we ++ * requested was, or is about to be, paused. Arguments are major/minor ++ * number of the device and the mode of the operation. ++ * In case the event is not about our device, we ignore it. Otherwise, ++ * we treat it as asynchronous DRM-DROP-MASTER. Note that we might have ++ * already handled an EACCES error from a modeset ioctl, in which case ++ * we already disabled the device. ++ * ++ * @mode can be one of the following: ++ * "pause": The device is about to be paused. We must react ++ * immediately and respond with PauseDeviceComplete(). Once ++ * we replied, logind will pause the device. Note that ++ * logind might apply any kind of timeout and force pause ++ * the device if we don't respond in a timely manner. In ++ * this case, we will receive a second PauseDevice event ++ * with @mode set to "force" (or similar). ++ * "force": The device was disabled forecfully by logind. DRM-Master ++ * was already dropped. This is just an asynchronous ++ * notification so we can put the device asleep (in case ++ * we didn't already notice the dropped DRM-Master). ++ * "gone": This is like "force" but is sent if the device was ++ * paused due to a device-removal event. ++ * ++ * We always handle PauseDevice signals as "force" as we properly ++ * support asynchronously dropping DRM-Master, anyway. But in case ++ * logind sent mode "pause", we also call PauseDeviceComplete() to ++ * immediately acknowledge the request. ++ */ ++ ++ r = sd_bus_message_read(signal, "uus", &major, &minor, &mode); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: erroneous PauseDevice signal", ++ session->name, cm->card.base.name); ++ return 0; ++ } ++ ++ /* not our device? */ ++ if (makedev(major, minor) != cm->devnum) ++ return 0; ++ ++ cm->master = false; ++ grdrm_card_disable(&cm->card); ++ ++ if (streq(mode, "pause")) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ ++ /* ++ * Sending PauseDeviceComplete() is racy if logind triggers the ++ * timeout. That is, if we take too long and logind pauses the ++ * device by sending a forced PauseDevice, our ++ * PauseDeviceComplete call will be stray. That's fine, though. ++ * logind ignores such stray calls. Only if logind also sent a ++ * further PauseDevice() signal, it might match our call ++ * incorrectly to the newer PauseDevice(). That's fine, too, as ++ * we handle that event asynchronously, anyway. Therefore, ++ * whatever happens, we're fine. Yay! ++ */ ++ ++ r = sd_bus_message_new_method_call(session->context->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ session->path, ++ "org.freedesktop.login1.Session", ++ "PauseDeviceComplete"); ++ if (r >= 0) { ++ r = sd_bus_message_append(m, "uu", major, minor); ++ if (r >= 0) ++ r = sd_bus_send(session->context->sysbus, m, NULL); ++ } ++ ++ if (r < 0) ++ log_debug("grdrm: %s/%s: cannot send PauseDeviceComplete: %s", ++ session->name, cm->card.base.name, strerror(-r)); ++ } ++ ++ return 0; ++} ++ ++static int managed_card_resume_device_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ managed_card *cm = userdata; ++ grdev_session *session = cm->card.base.session; ++ uint32_t major, minor; ++ int r, fd; ++ ++ /* ++ * We get ResumeDevice signals whenever logind resumed a previously ++ * paused device. The arguments contain the major/minor number of the ++ * related device and a new file-descriptor for the freshly opened ++ * device-node. ++ * If the signal is not about our device, we simply ignore it. ++ * Otherwise, we immediately resume the device. Note that we drop the ++ * new file-descriptor as we already have one from TakeDevice(). logind ++ * preserves the file-context across pause/resume for DRM but only ++ * drops/acquires DRM-Master accordingly. This way, our context (like ++ * DRM-FBs and BOs) is preserved. ++ */ ++ ++ r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: erroneous ResumeDevice signal", ++ session->name, cm->card.base.name); ++ return 0; ++ } ++ ++ /* not our device? */ ++ if (makedev(major, minor) != cm->devnum) ++ return 0; ++ ++ if (cm->card.fd < 0) { ++ /* This shouldn't happen. We should already own an FD from ++ * TakeDevice(). However, lets be safe and use this FD in case ++ * we really don't have one. There is no harm in doing this ++ * and our code works fine this way. */ ++ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); ++ if (fd < 0) { ++ log_debug("grdrm: %s/%s: cannot duplicate fd: %m", ++ session->name, cm->card.base.name); ++ return 0; ++ } ++ ++ r = grdrm_card_open(&cm->card, fd); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: cannot open: %s", ++ session->name, cm->card.base.name, strerror(-r)); ++ return 0; ++ } ++ } ++ ++ cm->master = true; ++ if (cm->card.base.enabled) ++ grdrm_card_enable(&cm->card); ++ ++ return 0; ++} ++ ++static int managed_card_setup_bus(managed_card *cm) { ++ grdev_session *session = cm->card.base.session; ++ _cleanup_free_ char *match = NULL; ++ int r; ++ ++ match = strjoin("type='signal'," ++ "sender='org.freedesktop.login1'," ++ "interface='org.freedesktop.login1.Session'," ++ "member='PauseDevice'," ++ "path='", session->path, "'", ++ NULL); ++ if (!match) ++ return -ENOMEM; ++ ++ r = sd_bus_add_match(session->context->sysbus, ++ &cm->slot_pause_device, ++ match, ++ managed_card_pause_device_fn, ++ cm); ++ if (r < 0) ++ return r; ++ ++ free(match); ++ match = strjoin("type='signal'," ++ "sender='org.freedesktop.login1'," ++ "interface='org.freedesktop.login1.Session'," ++ "member='ResumeDevice'," ++ "path='", session->path, "'", ++ NULL); ++ if (!match) ++ return -ENOMEM; ++ ++ r = sd_bus_add_match(session->context->sysbus, ++ &cm->slot_resume_device, ++ match, ++ managed_card_resume_device_fn, ++ cm); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ ++static int managed_card_take_device_fn(sd_bus *bus, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ managed_card *cm = userdata; ++ grdev_session *session = cm->card.base.session; ++ int r, paused, fd; ++ ++ cm->slot_take_device = sd_bus_slot_unref(cm->slot_take_device); ++ ++ if (sd_bus_message_is_method_error(reply, NULL)) { ++ const sd_bus_error *error = sd_bus_message_get_error(reply); ++ ++ log_debug("grdrm: %s/%s: TakeDevice failed: %s: %s", ++ session->name, cm->card.base.name, error->name, error->message); ++ return 0; ++ } ++ ++ cm->acquired = true; ++ ++ r = sd_bus_message_read(reply, "hb", &fd, &paused); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: erroneous TakeDevice reply", ++ session->name, cm->card.base.name); ++ return 0; ++ } ++ ++ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); ++ if (fd < 0) { ++ log_debug("grdrm: %s/%s: cannot duplicate fd: %m", ++ session->name, cm->card.base.name); ++ return 0; ++ } ++ ++ r = grdrm_card_open(&cm->card, fd); ++ if (r < 0) { ++ log_debug("grdrm: %s/%s: cannot open: %s", ++ session->name, cm->card.base.name, strerror(-r)); ++ return 0; ++ } ++ ++ if (!paused && cm->card.base.enabled) ++ grdrm_card_enable(&cm->card); ++ ++ return 0; ++} ++ ++static void managed_card_take_device(managed_card *cm) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ grdev_session *session = cm->card.base.session; ++ int r; ++ ++ r = sd_bus_message_new_method_call(session->context->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ session->path, ++ "org.freedesktop.login1.Session", ++ "TakeDevice"); ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_message_append(m, "uu", major(cm->devnum), minor(cm->devnum)); ++ if (r < 0) ++ goto error; ++ ++ r = sd_bus_call_async(session->context->sysbus, ++ &cm->slot_take_device, ++ m, ++ managed_card_take_device_fn, ++ cm, ++ 0); ++ if (r < 0) ++ goto error; ++ ++ cm->requested = true; ++ return; ++ ++error: ++ log_debug("grdrm: %s/%s: cannot send TakeDevice request: %s", ++ session->name, cm->card.base.name, strerror(-r)); ++} ++ ++static void managed_card_release_device(managed_card *cm) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ grdev_session *session = cm->card.base.session; ++ int r; ++ ++ /* ++ * If TakeDevice() is pending or was successful, make sure to ++ * release the device again. We don't care for return-values, ++ * so send it without waiting or callbacks. ++ * If a failed TakeDevice() is pending, but someone else took ++ * the device on the same bus-connection, we might incorrectly ++ * release their device. This is an unlikely race, though. ++ * Furthermore, you really shouldn't have two users of the ++ * controller-API on the same session, on the same devices, *AND* on ++ * the same bus-connection. So we don't care for that race.. ++ */ ++ ++ grdrm_card_close(&cm->card); ++ cm->requested = false; ++ ++ if (!cm->acquired && !cm->slot_take_device) ++ return; ++ ++ cm->slot_take_device = sd_bus_slot_unref(cm->slot_take_device); ++ cm->acquired = false; ++ ++ r = sd_bus_message_new_method_call(session->context->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ session->path, ++ "org.freedesktop.login1.Session", ++ "ReleaseDevice"); ++ if (r >= 0) { ++ r = sd_bus_message_append(m, "uu", major(cm->devnum), minor(cm->devnum)); ++ if (r >= 0) ++ r = sd_bus_send(session->context->sysbus, m, NULL); ++ } ++ ++ if (r < 0 && r != -ENOTCONN) ++ log_debug("grdrm: %s/%s: cannot send ReleaseDevice: %s", ++ session->name, cm->card.base.name, strerror(-r)); ++} ++ ++static int managed_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud) { ++ _cleanup_(grdev_card_freep) grdev_card *basecard = NULL; ++ char name[GRDRM_CARD_NAME_MAX]; ++ managed_card *cm; ++ dev_t devnum; ++ int r; ++ ++ assert_return(session, -EINVAL); ++ assert_return(session->managed, -EINVAL); ++ assert_return(session->context->sysbus, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ return -ENODEV; ++ ++ grdrm_name(name, devnum); ++ ++ cm = new0(managed_card, 1); ++ if (!cm) ++ return -ENOMEM; ++ ++ basecard = &cm->card.base; ++ cm->card = GRDRM_CARD_INIT(&managed_card_vtable, session); ++ cm->devnum = devnum; ++ ++ r = managed_card_setup_bus(cm); ++ if (r < 0) ++ return r; ++ ++ r = grdrm_card_add(&cm->card, name); ++ if (r < 0) ++ return r; ++ ++ managed_card_take_device(cm); ++ ++ if (out) ++ *out = basecard; ++ basecard = NULL; ++ return 0; ++} ++ ++static void managed_card_free(grdev_card *basecard) { ++ managed_card *cm = managed_card_from_base(basecard); ++ ++ assert(!basecard->enabled); ++ ++ managed_card_release_device(cm); ++ cm->slot_resume_device = sd_bus_slot_unref(cm->slot_resume_device); ++ cm->slot_pause_device = sd_bus_slot_unref(cm->slot_pause_device); ++ grdrm_card_destroy(&cm->card); ++ free(cm); ++} ++ ++static const grdev_card_vtable managed_card_vtable = { ++ .free = managed_card_free, ++ .enable = managed_card_enable, ++ .disable = managed_card_disable, ++ .commit = grdrm_card_commit, ++ .restore = grdrm_card_restore, ++}; ++ ++/* ++ * Generic Constructor ++ * Instead of relying on the caller to choose between managed and unmanaged ++ * DRM devices, the grdev_drm_new() constructor does that for you (by ++ * looking at session->managed). ++ */ ++ ++bool grdev_is_drm_card(grdev_card *basecard) { ++ return basecard && (basecard->vtable == &unmanaged_card_vtable || ++ basecard->vtable == &managed_card_vtable); ++} ++ ++grdev_card *grdev_find_drm_card(grdev_session *session, dev_t devnum) { ++ char name[GRDRM_CARD_NAME_MAX]; ++ ++ assert_return(session, NULL); ++ assert_return(devnum != 0, NULL); ++ ++ grdrm_name(name, devnum); ++ return grdev_find_card(session, name); ++} ++ ++int grdev_drm_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud) { ++ assert_return(session, -EINVAL); ++ assert_return(ud, -EINVAL); ++ ++ return session->managed ? managed_card_new(out, session, ud) : unmanaged_card_new(out, session, ud); ++} +diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h +index 7e69c49b63..0064f0be02 100644 +--- a/src/libsystemd-terminal/grdev-internal.h ++++ b/src/libsystemd-terminal/grdev-internal.h +@@ -22,6 +22,7 @@ + #pragma once + + #include ++#include + #include + #include + #include +@@ -40,6 +41,14 @@ typedef struct grdev_card_vtable grdev_card_vtable; + typedef struct grdev_card grdev_card; + + /* ++ * DRM cards ++ */ ++ ++bool grdev_is_drm_card(grdev_card *card); ++grdev_card *grdev_find_drm_card(grdev_session *session, dev_t devnum); ++int grdev_drm_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud); ++ ++/* + * Displays + */ + +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index ab1c407ecb..1e02a6799c 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -20,6 +20,7 @@ + ***/ + + #include ++#include + #include + #include + #include +@@ -30,6 +31,7 @@ + #include "hashmap.h" + #include "login-shared.h" + #include "macro.h" ++#include "udev-util.h" + #include "util.h" + + static void pipe_enable(grdev_pipe *pipe); +@@ -1083,6 +1085,68 @@ void grdev_session_restore(grdev_session *session) { + card->vtable->restore(card); + } + ++void grdev_session_add_drm(grdev_session *session, struct udev_device *ud) { ++ grdev_card *card; ++ dev_t devnum; ++ int r; ++ ++ assert(session); ++ assert(ud); ++ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ return; ++ ++ card = grdev_find_drm_card(session, devnum); ++ if (card) ++ return; ++ ++ r = grdev_drm_card_new(&card, session, ud); ++ if (r < 0) { ++ log_debug("grdev: %s: cannot add DRM device for %s: %s", ++ session->name, udev_device_get_syspath(ud), strerror(-r)); ++ return; ++ } ++ ++ session_add_card(session, card); ++} ++ ++void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud) { ++ grdev_card *card; ++ dev_t devnum; ++ ++ assert(session); ++ assert(ud); ++ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ return; ++ ++ card = grdev_find_drm_card(session, devnum); ++ if (!card) ++ return; ++ ++ session_remove_card(session, card); ++} ++ ++void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud) { ++ grdev_card *card; ++ dev_t devnum; ++ ++ assert(session); ++ assert(ud); ++ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ return; ++ ++ card = grdev_find_drm_card(session, devnum); ++ if (!card) ++ return; ++ ++ /* TODO: hotplug card */ ++} ++ + static void session_configure(grdev_session *session) { + grdev_display *display; + grdev_tile *tile; +diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h +index 2645b12113..9924a257b6 100644 +--- a/src/libsystemd-terminal/grdev.h ++++ b/src/libsystemd-terminal/grdev.h +@@ -55,6 +55,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -171,6 +172,10 @@ void grdev_session_disable(grdev_session *session); + void grdev_session_commit(grdev_session *session); + void grdev_session_restore(grdev_session *session); + ++void grdev_session_add_drm(grdev_session *session, struct udev_device *ud); ++void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud); ++void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud); ++ + /* + * Contexts + */ diff --git a/0325-terminal-add-systemd-modeset-debugging-tool.patch b/0325-terminal-add-systemd-modeset-debugging-tool.patch new file mode 100644 index 0000000..69c3b9b --- /dev/null +++ b/0325-terminal-add-systemd-modeset-debugging-tool.patch @@ -0,0 +1,559 @@ +From 810626a80de8361dfbe27110d585023b3d6167a6 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 19 Sep 2014 14:48:54 +0200 +Subject: [PATCH] terminal: add systemd-modeset debugging tool + +The systemd-modeset tool is meant to debug grdev issues. It simply +displays morphing colors on any found display. This is pretty handy to +look for tearing in the backends and debug hotplug issues. + +Note that this tool requires systemd-logind to be compiled from git +(there're important fixes that haven't been released, yet). +--- + .gitignore | 1 + + Makefile.am | 14 ++ + src/libsystemd-terminal/modeset.c | 491 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 506 insertions(+) + create mode 100644 src/libsystemd-terminal/modeset.c + +diff --git a/.gitignore b/.gitignore +index f8650870a3..288946029b 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -90,6 +90,7 @@ + /systemd-logind + /systemd-machine-id-setup + /systemd-machined ++/systemd-modeset + /systemd-modules-load + /systemd-multi-seat-x + /systemd-networkd +diff --git a/Makefile.am b/Makefile.am +index be25023c75..f80ffc6749 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2987,6 +2987,7 @@ noinst_LTLIBRARIES += \ + + noinst_PROGRAMS += \ + systemd-evcat \ ++ systemd-modeset \ + systemd-subterm + + unifontdatadir=$(datadir)/unifont +@@ -3045,6 +3046,19 @@ systemd_evcat_LDADD = \ + libsystemd-shared.la \ + $(TERMINAL_LIBS) + ++systemd_modeset_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(TERMINAL_CFLAGS) ++ ++systemd_modeset_SOURCES = \ ++ src/libsystemd-terminal/modeset.c ++ ++systemd_modeset_LDADD = \ ++ libsystemd-terminal.la \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la \ ++ $(TERMINAL_LIBS) ++ + systemd_subterm_SOURCES = \ + src/libsystemd-terminal/subterm.c + +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +new file mode 100644 +index 0000000000..02ed1a8987 +--- /dev/null ++++ b/src/libsystemd-terminal/modeset.c +@@ -0,0 +1,491 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++/* ++ * Modeset Testing ++ * The modeset tool attaches to the session of the caller and shows a ++ * test-pattern on all displays of this session. It is meant as debugging tool ++ * for the grdev infrastructure. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "build.h" ++#include "bus-util.h" ++#include "event-util.h" ++#include "grdev.h" ++#include "grdev-internal.h" ++#include "macro.h" ++#include "sysview.h" ++#include "util.h" ++ ++typedef struct Modeset Modeset; ++ ++struct Modeset { ++ char *session; ++ char *seat; ++ sd_event *event; ++ sd_bus *bus; ++ sd_event_source *exit_src; ++ sysview_context *sysview; ++ grdev_context *grdev; ++ grdev_session *grdev_session; ++ ++ uint8_t r, g, b; ++ bool r_up, g_up, b_up; ++ ++ bool my_tty : 1; ++ bool managed : 1; ++}; ++ ++static int modeset_exit_fn(sd_event_source *source, void *userdata) { ++ Modeset *m = userdata; ++ ++ if (m->grdev_session) ++ grdev_session_restore(m->grdev_session); ++ ++ return 0; ++} ++ ++static Modeset *modeset_free(Modeset *m) { ++ if (!m) ++ return NULL; ++ ++ m->grdev_session = grdev_session_free(m->grdev_session); ++ m->grdev = grdev_context_unref(m->grdev); ++ m->sysview = sysview_context_free(m->sysview); ++ m->exit_src = sd_event_source_unref(m->exit_src); ++ m->bus = sd_bus_unref(m->bus); ++ m->event = sd_event_unref(m->event); ++ free(m->seat); ++ free(m->session); ++ free(m); ++ ++ return NULL; ++} ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Modeset*, modeset_free); ++ ++static bool is_my_tty(const char *session) { ++ unsigned int vtnr; ++ struct stat st; ++ long mode; ++ int r; ++ ++ /* Using logind's Controller API is highly fragile if there is already ++ * a session controller running. If it is registered as controller ++ * itself, TakeControl will simply fail. But if its a legacy controller ++ * that does not use logind's controller API, we must never register ++ * our own controller. Otherwise, we really mess up the VT. Therefore, ++ * only run in managed mode if there's no-one else. Furthermore, never ++ * try to access graphics devices if there's someone else. Unlike input ++ * devices, graphics devies cannot be shared easily. */ ++ ++ if (!isatty(1)) ++ return false; ++ ++ if (!session) ++ return false; ++ ++ r = sd_session_get_vt(session, &vtnr); ++ if (r < 0 || vtnr < 1 || vtnr > 63) ++ return false; ++ ++ mode = 0; ++ r = ioctl(1, KDGETMODE, &mode); ++ if (r < 0 || mode != KD_TEXT) ++ return false; ++ ++ r = fstat(1, &st); ++ if (r < 0 || minor(st.st_rdev) != vtnr) ++ return false; ++ ++ return true; ++} ++ ++static int modeset_new(Modeset **out) { ++ _cleanup_(modeset_freep) Modeset *m = NULL; ++ int r; ++ ++ assert(out); ++ ++ m = new0(Modeset, 1); ++ if (!m) ++ return log_oom(); ++ ++ r = sd_pid_get_session(getpid(), &m->session); ++ if (r < 0) { ++ log_error("Cannot retrieve logind session: %s", strerror(-r)); ++ return r; ++ } ++ ++ r = sd_session_get_seat(m->session, &m->seat); ++ if (r < 0) { ++ log_error("Cannot retrieve seat of logind session: %s", strerror(-r)); ++ return r; ++ } ++ ++ m->my_tty = is_my_tty(m->session); ++ m->managed = m->my_tty && geteuid() > 0; ++ ++ m->r = rand() % 0xff; ++ m->g = rand() % 0xff; ++ m->b = rand() % 0xff; ++ m->r_up = m->g_up = m->b_up = true; ++ ++ r = sd_event_default(&m->event); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_open_system(&m->bus); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL); ++ if (r < 0) ++ return r; ++ ++ r = sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_exit(m->event, &m->exit_src, modeset_exit_fn, m); ++ if (r < 0) ++ return r; ++ ++ /* schedule before sd-bus close */ ++ r = sd_event_source_set_priority(m->exit_src, -10); ++ if (r < 0) ++ return r; ++ ++ r = sysview_context_new(&m->sysview, ++ SYSVIEW_CONTEXT_SCAN_LOGIND | ++ SYSVIEW_CONTEXT_SCAN_DRM, ++ m->event, ++ m->bus, ++ NULL); ++ if (r < 0) ++ return r; ++ ++ r = grdev_context_new(&m->grdev, m->event, m->bus); ++ if (r < 0) ++ return r; ++ ++ *out = m; ++ m = NULL; ++ return 0; ++} ++ ++static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod) { ++ uint8_t next; ++ ++ /* generate smoothly morphing colors */ ++ ++ next = cur + (*up ? 1 : -1) * (rand() % mod); ++ if ((*up && next < cur) || (!*up && next > cur)) { ++ *up = !*up; ++ next = cur; ++ } ++ ++ return next; ++} ++ ++static void modeset_draw(Modeset *m, const grdev_display_target *t) { ++ uint32_t j, k, *b; ++ uint8_t *l; ++ ++ assert(t->fb->format == DRM_FORMAT_XRGB8888 || t->fb->format == DRM_FORMAT_ARGB8888); ++ assert(!t->rotate); ++ assert(!t->flip); ++ ++ l = t->fb->maps[0]; ++ for (j = 0; j < t->height; ++j) { ++ for (k = 0; k < t->width; ++k) { ++ b = (uint32_t*)l; ++ b[k] = (0xff << 24) | (m->r << 16) | (m->g << 8) | m->b; ++ } ++ ++ l += t->fb->strides[0]; ++ } ++} ++ ++static void modeset_render(Modeset *m, grdev_display *d) { ++ const grdev_display_target *t; ++ ++ m->r = next_color(&m->r_up, m->r, 20); ++ m->g = next_color(&m->g_up, m->g, 10); ++ m->b = next_color(&m->b_up, m->b, 5); ++ ++ GRDEV_DISPLAY_FOREACH_TARGET(d, t, 0) { ++ modeset_draw(m, t); ++ grdev_display_flip_target(d, t, 1); ++ } ++ ++ grdev_session_commit(m->grdev_session); ++} ++ ++static void modeset_grdev_fn(grdev_session *session, void *userdata, grdev_event *ev) { ++ Modeset *m = userdata; ++ ++ switch (ev->type) { ++ case GRDEV_EVENT_DISPLAY_ADD: ++ grdev_display_enable(ev->display_add.display); ++ modeset_render(m, ev->display_add.display); ++ break; ++ case GRDEV_EVENT_DISPLAY_REMOVE: ++ break; ++ case GRDEV_EVENT_DISPLAY_CHANGE: ++ modeset_render(m, ev->display_change.display); ++ break; ++ case GRDEV_EVENT_DISPLAY_FRAME: ++ modeset_render(m, ev->display_frame.display); ++ break; ++ } ++} ++ ++static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event *ev) { ++ unsigned int flags, type; ++ Modeset *m = userdata; ++ sysview_device *d; ++ const char *name; ++ int r; ++ ++ switch (ev->type) { ++ case SYSVIEW_EVENT_SESSION_FILTER: ++ if (streq_ptr(m->session, ev->session_filter.id)) ++ return 1; ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_ADD: ++ assert(!m->grdev_session); ++ ++ name = sysview_session_get_name(ev->session_add.session); ++ flags = 0; ++ ++ if (m->managed) ++ flags |= GRDEV_SESSION_MANAGED; ++ ++ r = grdev_session_new(&m->grdev_session, ++ m->grdev, ++ flags, ++ name, ++ modeset_grdev_fn, ++ m); ++ if (r < 0) { ++ log_error("Cannot create grdev session: %s", strerror(-r)); ++ return r; ++ } ++ ++ if (m->managed) { ++ r = sysview_session_take_control(ev->session_add.session); ++ if (r < 0) { ++ log_error("Cannot request session control: %s", strerror(-r)); ++ return r; ++ } ++ } ++ ++ grdev_session_enable(m->grdev_session); ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_REMOVE: ++ if (!m->grdev_session) ++ return 0; ++ ++ grdev_session_restore(m->grdev_session); ++ grdev_session_disable(m->grdev_session); ++ m->grdev_session = grdev_session_free(m->grdev_session); ++ sd_event_exit(m->event, 0); ++ break; ++ case SYSVIEW_EVENT_SESSION_ATTACH: ++ d = ev->session_attach.device; ++ type = sysview_device_get_type(d); ++ if (type == SYSVIEW_DEVICE_DRM) ++ grdev_session_add_drm(m->grdev_session, sysview_device_get_ud(d)); ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_DETACH: ++ d = ev->session_detach.device; ++ type = sysview_device_get_type(d); ++ if (type == SYSVIEW_DEVICE_DRM) ++ grdev_session_remove_drm(m->grdev_session, sysview_device_get_ud(d)); ++ ++ break; ++ case SYSVIEW_EVENT_SESSION_CONTROL: ++ r = ev->session_control.error; ++ if (r < 0) { ++ log_error("Cannot acquire session control: %s", strerror(-r)); ++ return r; ++ } ++ ++ r = ioctl(1, KDSKBMODE, K_UNICODE); ++ if (r < 0) { ++ log_error("Cannot set K_UNICODE on stdout: %m"); ++ return -errno; ++ } ++ ++ break; ++ } ++ ++ return 0; ++} ++ ++static int modeset_run(Modeset *m) { ++ struct termios in_attr, saved_attr; ++ int r; ++ ++ assert(m); ++ ++ if (!m->my_tty) { ++ log_warning("You need to run this program on a free VT"); ++ return -EACCES; ++ } ++ ++ if (!m->managed && geteuid() > 0) ++ log_warning("You run in unmanaged mode without being root. This is likely to fail.."); ++ ++ printf("modeset - Show test pattern on selected graphics devices\n" ++ " Running on seat '%s' in user-session '%s'\n" ++ " Exit by pressing ^C\n\n", ++ m->seat ? : "seat0", m->session ? : ""); ++ ++ r = sysview_context_start(m->sysview, modeset_sysview_fn, m); ++ if (r < 0) ++ goto out; ++ ++ r = tcgetattr(0, &in_attr); ++ if (r < 0) { ++ r = -errno; ++ goto out; ++ } ++ ++ saved_attr = in_attr; ++ in_attr.c_lflag &= ~ECHO; ++ ++ r = tcsetattr(0, TCSANOW, &in_attr); ++ if (r < 0) { ++ r = -errno; ++ goto out; ++ } ++ ++ r = sd_event_loop(m->event); ++ tcsetattr(0, TCSANOW, &saved_attr); ++ printf("exiting..\n"); ++ ++out: ++ sysview_context_stop(m->sysview); ++ return r; ++} ++ ++static int help(void) { ++ printf("%s [OPTIONS...]\n\n" ++ "Show test pattern on all selected graphics devices.\n\n" ++ " -h --help Show this help\n" ++ " --version Show package version\n" ++ , program_invocation_short_name); ++ ++ return 0; ++} ++ ++static int parse_argv(int argc, char *argv[]) { ++ enum { ++ ARG_VERSION = 0x100, ++ }; ++ static const struct option options[] = { ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, ARG_VERSION }, ++ {}, ++ }; ++ int c; ++ ++ assert(argc >= 0); ++ assert(argv); ++ ++ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) ++ switch (c) { ++ case 'h': ++ help(); ++ return 0; ++ ++ case ARG_VERSION: ++ puts(PACKAGE_STRING); ++ puts(SYSTEMD_FEATURES); ++ return 0; ++ ++ case '?': ++ return -EINVAL; ++ ++ default: ++ assert_not_reached("Unhandled option"); ++ } ++ ++ if (argc > optind) { ++ log_error("Too many arguments"); ++ return -EINVAL; ++ } ++ ++ return 1; ++} ++ ++int main(int argc, char *argv[]) { ++ _cleanup_(modeset_freep) Modeset *m = NULL; ++ int r; ++ ++ log_set_target(LOG_TARGET_AUTO); ++ log_parse_environment(); ++ log_open(); ++ ++ srand(time(NULL)); ++ ++ r = parse_argv(argc, argv); ++ if (r <= 0) ++ goto finish; ++ ++ r = modeset_new(&m); ++ if (r < 0) ++ goto finish; ++ ++ r = modeset_run(m); ++ ++finish: ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} diff --git a/0326-nspawn-don-t-try-to-create-veth-link-with-too-long-i.patch b/0326-nspawn-don-t-try-to-create-veth-link-with-too-long-i.patch new file mode 100644 index 0000000..74dc3fa --- /dev/null +++ b/0326-nspawn-don-t-try-to-create-veth-link-with-too-long-i.patch @@ -0,0 +1,23 @@ +From c00524c9cc7fb498c7244350e25823b8352f078c Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 19 Sep 2014 23:02:00 +0200 +Subject: [PATCH] nspawn: don't try to create veth link with too long ifname + +Reported by: James Lott +--- + 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 5af89c9b32..c22d0cb598 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -1657,7 +1657,7 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) { + + /* Use two different interface name prefixes depending whether + * we are in bridge mode or not. */ +- snprintf(iface_name, IFNAMSIZ, "%s-%s", ++ snprintf(iface_name, IFNAMSIZ - 1, "%s-%s", + arg_network_bridge ? "vb" : "ve", arg_machine); + + r = generate_mac(&mac_container, CONTAINER_HASH_KEY); diff --git a/0327-terminal-parse-ID_SEAT-not-only-for-parents-but-the-.patch b/0327-terminal-parse-ID_SEAT-not-only-for-parents-but-the-.patch new file mode 100644 index 0000000..28c22bb --- /dev/null +++ b/0327-terminal-parse-ID_SEAT-not-only-for-parents-but-the-.patch @@ -0,0 +1,33 @@ +From 3e7f6cf9565e007545112f245e69b2bf45866258 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 09:29:11 +0200 +Subject: [PATCH] terminal: parse ID_SEAT not only for parents but the device + itself + +When deciding what seat a device is on, we have to traverse all parents +to find one with an ID_SEAT tag, otherwise, input devices plugged on a +seated USB-hub are not automatically attached to the right seat. But any +tags on the main device still overwrite the tags of the childs, so fix our +logic to check the device itself first, before traversing the parents. +--- + src/libsystemd-terminal/sysview.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index fde87d1117..6c1a9543b9 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -893,11 +893,11 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { + + p = d; + seatname = NULL; +- while ((p = udev_device_get_parent(p))) { ++ do { + seatname = udev_device_get_property_value(p, "ID_SEAT"); + if (seatname) + break; +- } ++ } while ((p = udev_device_get_parent(p))); + + seat = sysview_find_seat(c, seatname ? : "seat0"); + if (!seat) diff --git a/0328-terminal-forward-DEVICE_CHANGE-events-via-sysview.patch b/0328-terminal-forward-DEVICE_CHANGE-events-via-sysview.patch new file mode 100644 index 0000000..faa6212 --- /dev/null +++ b/0328-terminal-forward-DEVICE_CHANGE-events-via-sysview.patch @@ -0,0 +1,71 @@ +From 965f7a3f9bf7afb85be62198fabc70ffa033d8b1 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 09:43:16 +0200 +Subject: [PATCH] terminal: forward DEVICE_CHANGE events via sysview + +Whe need to react to "change" events on devices, but we want to avoid +duplicating udev-monitors everywhere. Therefore, make sysview forward +change events to the sysview controllers, which can then properly react +to it. +--- + src/libsystemd-terminal/sysview.c | 14 +++++++++++++- + src/libsystemd-terminal/sysview.h | 7 +++++++ + 2 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 6c1a9543b9..23d564d6a0 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -517,6 +517,18 @@ static int context_raise_session_detach(sysview_context *c, sysview_session *ses + return context_raise(c, &event, 0); + } + ++static int context_raise_device_change(sysview_context *c, sysview_device *device, struct udev_device *ud) { ++ sysview_event event = { ++ .type = SYSVIEW_EVENT_DEVICE_CHANGE, ++ .device_change = { ++ .device = device, ++ .ud = ud, ++ } ++ }; ++ ++ return context_raise(c, &event, 0); ++} ++ + static int context_add_device(sysview_context *c, sysview_device *device) { + sysview_session *session; + int r, error = 0; +@@ -872,7 +884,7 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { + if (!device) + return 0; + +- /* TODO: send REFRESH event */ ++ return context_raise_device_change(c, device, d); + } else if (!action || streq_ptr(action, "add")) { + struct udev_device *p; + unsigned int type, t; +diff --git a/src/libsystemd-terminal/sysview.h b/src/libsystemd-terminal/sysview.h +index de6ff371db..b9452fab89 100644 +--- a/src/libsystemd-terminal/sysview.h ++++ b/src/libsystemd-terminal/sysview.h +@@ -64,6 +64,8 @@ enum { + SYSVIEW_EVENT_SESSION_ATTACH, + SYSVIEW_EVENT_SESSION_DETACH, + SYSVIEW_EVENT_SESSION_CONTROL, ++ ++ SYSVIEW_EVENT_DEVICE_CHANGE, + }; + + struct sysview_event { +@@ -94,6 +96,11 @@ struct sysview_event { + sysview_session *session; + int error; + } session_control; ++ ++ struct { ++ sysview_device *device; ++ struct udev_device *ud; ++ } device_change; + }; + }; + diff --git a/0329-terminal-make-drm-connectors-first-level-devices.patch b/0329-terminal-make-drm-connectors-first-level-devices.patch new file mode 100644 index 0000000..c0d364e --- /dev/null +++ b/0329-terminal-make-drm-connectors-first-level-devices.patch @@ -0,0 +1,25 @@ +From c1102405c1c151b693cf92f1b704a4eb8aacee73 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 09:44:14 +0200 +Subject: [PATCH] terminal: make drm-connectors first-level devices + +So far, we only forward DRM cards via sysview APIs. However, with MST, +connectors can be hotplugged, too. Forward the connectors as first-level +devices via sysview so API users can react to changing DRM connectors. +--- + src/libsystemd-terminal/sysview.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 23d564d6a0..161ea117a4 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -895,7 +895,7 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { + + if (streq(subsystem, "input") && startswith(sysname, "event") && safe_atou(sysname + 5, &t) >= 0) + type = SYSVIEW_DEVICE_EVDEV; +- else if (streq(subsystem, "drm") && startswith(sysname, "card") && safe_atou(sysname + 4, &t) >= 0) ++ else if (streq(subsystem, "drm") && startswith(sysname, "card")) + type = SYSVIEW_DEVICE_DRM; + else + type = (unsigned)-1; diff --git a/0330-terminal-reduce-speed-of-morphing-colors-in-modeset-.patch b/0330-terminal-reduce-speed-of-morphing-colors-in-modeset-.patch new file mode 100644 index 0000000..8736a17 --- /dev/null +++ b/0330-terminal-reduce-speed-of-morphing-colors-in-modeset-.patch @@ -0,0 +1,29 @@ +From 39cf40e846754fe37f5c8a948f37227ce1ef8472 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 09:45:26 +0200 +Subject: [PATCH] terminal: reduce speed of morphing colors in modeset test + +The high frequency of the color-morphing is kinda irritating. Reduce it +to a much lower frequency so you can actually look at it longer than few +seconds. +--- + src/libsystemd-terminal/modeset.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +index 02ed1a8987..c1119c9e0f 100644 +--- a/src/libsystemd-terminal/modeset.c ++++ b/src/libsystemd-terminal/modeset.c +@@ -252,9 +252,9 @@ static void modeset_draw(Modeset *m, const grdev_display_target *t) { + static void modeset_render(Modeset *m, grdev_display *d) { + const grdev_display_target *t; + +- m->r = next_color(&m->r_up, m->r, 20); +- m->g = next_color(&m->g_up, m->g, 10); +- m->b = next_color(&m->b_up, m->b, 5); ++ m->r = next_color(&m->r_up, m->r, 4); ++ m->g = next_color(&m->g_up, m->g, 3); ++ m->b = next_color(&m->b_up, m->b, 2); + + GRDEV_DISPLAY_FOREACH_TARGET(d, t, 0) { + modeset_draw(m, t); diff --git a/0331-terminal-modeset-forward-DEVICE_CHANGE-events-into-g.patch b/0331-terminal-modeset-forward-DEVICE_CHANGE-events-into-g.patch new file mode 100644 index 0000000..ac3af06 --- /dev/null +++ b/0331-terminal-modeset-forward-DEVICE_CHANGE-events-into-g.patch @@ -0,0 +1,29 @@ +From 46c9a12780ea24ef311682897077423f1825c519 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 09:46:13 +0200 +Subject: [PATCH] terminal: modeset: forward DEVICE_CHANGE events into grdev + +Properly forward DEVICE_CHANGE events into grdev so we can react to +changing display setups. +--- + src/libsystemd-terminal/modeset.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +index c1119c9e0f..57bf299df5 100644 +--- a/src/libsystemd-terminal/modeset.c ++++ b/src/libsystemd-terminal/modeset.c +@@ -364,6 +364,13 @@ static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event + } + + break; ++ case SYSVIEW_EVENT_DEVICE_CHANGE: ++ d = ev->device_change.device; ++ type = sysview_device_get_type(d); ++ if (type == SYSVIEW_DEVICE_DRM) ++ grdev_session_hotplug_drm(m->grdev_session, ev->device_change.ud); ++ ++ break; + } + + return 0; diff --git a/0332-terminal-grdev-treat-udev-devices-without-devnum-as-.patch b/0332-terminal-grdev-treat-udev-devices-without-devnum-as-.patch new file mode 100644 index 0000000..6aba1c8 --- /dev/null +++ b/0332-terminal-grdev-treat-udev-devices-without-devnum-as-.patch @@ -0,0 +1,66 @@ +From a3eabec96b872bbf581c9bfa81ecc9c2819b8de8 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 09:48:22 +0200 +Subject: [PATCH] terminal: grdev: treat udev-devices without devnum as hotplug + +If we get udev-device events via sysview, but they lack devnum +annotations, we know it cannot be a DRM card. Look through it's parents +and treat it as hotplug event in case we find such a card. + +This will treat any new/removed connectors as sub-devices of the real +card, instead of as devices on its own. +--- + src/libsystemd-terminal/grdev.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index 1e02a6799c..bb89ee7170 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -1095,7 +1095,7 @@ void grdev_session_add_drm(grdev_session *session, struct udev_device *ud) { + + devnum = udev_device_get_devnum(ud); + if (devnum == 0) +- return; ++ return grdev_session_hotplug_drm(session, ud); + + card = grdev_find_drm_card(session, devnum); + if (card) +@@ -1120,7 +1120,7 @@ void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud) { + + devnum = udev_device_get_devnum(ud); + if (devnum == 0) +- return; ++ return grdev_session_hotplug_drm(session, ud); + + card = grdev_find_drm_card(session, devnum); + if (!card) +@@ -1130,17 +1130,23 @@ void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud) { + } + + void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud) { +- grdev_card *card; ++ grdev_card *card = NULL; ++ struct udev_device *p; + dev_t devnum; + + assert(session); + assert(ud); + +- devnum = udev_device_get_devnum(ud); +- if (devnum == 0) +- return; ++ for (p = ud; p; p = udev_device_get_parent_with_subsystem_devtype(p, "drm", NULL)) { ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ continue; ++ ++ card = grdev_find_drm_card(session, devnum); ++ if (card) ++ break; ++ } + +- card = grdev_find_drm_card(session, devnum); + if (!card) + return; + diff --git a/0333-terminal-grdev-refresh-device-state-on-hotplug-event.patch b/0333-terminal-grdev-refresh-device-state-on-hotplug-event.patch new file mode 100644 index 0000000..f735e34 --- /dev/null +++ b/0333-terminal-grdev-refresh-device-state-on-hotplug-event.patch @@ -0,0 +1,86 @@ +From 6221d249d1f03d235a23a284c597c86676b32d2f Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 09:50:10 +0200 +Subject: [PATCH] terminal: grdev: refresh device state on hotplug events + +Whenever we get udev hotplug events, re-read the device state so we +properly detect any changed in the display setups. +--- + src/libsystemd-terminal/grdev-drm.c | 32 +++++++++++++++++++++++++++++++- + src/libsystemd-terminal/grdev-internal.h | 1 + + src/libsystemd-terminal/grdev.c | 2 +- + 3 files changed, 33 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 3481584fbf..f0f0448635 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -2096,8 +2096,11 @@ static void grdrm_card_hotplug(grdrm_card *card) { + int r; + + assert(card); +- assert(!card->ready); + ++ if (!card->running) ++ return; ++ ++ card->ready = false; + r = grdrm_card_resync(card); + if (r < 0) { + log_debug("grdrm: %s/%s: cannot re-sync card: %s", +@@ -2955,3 +2958,30 @@ int grdev_drm_card_new(grdev_card **out, grdev_session *session, struct udev_dev + + return session->managed ? managed_card_new(out, session, ud) : unmanaged_card_new(out, session, ud); + } ++ ++void grdev_drm_card_hotplug(grdev_card *basecard, struct udev_device *ud) { ++ const char *p, *action; ++ grdrm_card *card; ++ dev_t devnum; ++ ++ assert(basecard); ++ assert(grdev_is_drm_card(basecard)); ++ assert(ud); ++ ++ card = grdrm_card_from_base(basecard); ++ ++ action = udev_device_get_action(ud); ++ if (!action || streq(action, "add") || streq(action, "remove")) { ++ /* If we get add/remove events on DRM nodes without devnum, we ++ * got hotplugged DRM objects so refresh the device. */ ++ devnum = udev_device_get_devnum(ud); ++ if (devnum == 0) ++ grdrm_card_hotplug(card); ++ } else if (streq_ptr(action, "change")) { ++ /* A change event with HOTPLUG=1 is sent whenever a connector ++ * changed state. Refresh the device to update our state. */ ++ p = udev_device_get_property_value(ud, "HOTPLUG"); ++ if (streq_ptr(p, "1")) ++ grdrm_card_hotplug(card); ++ } ++} +diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h +index 0064f0be02..96830a714c 100644 +--- a/src/libsystemd-terminal/grdev-internal.h ++++ b/src/libsystemd-terminal/grdev-internal.h +@@ -47,6 +47,7 @@ typedef struct grdev_card grdev_card; + bool grdev_is_drm_card(grdev_card *card); + grdev_card *grdev_find_drm_card(grdev_session *session, dev_t devnum); + int grdev_drm_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud); ++void grdev_drm_card_hotplug(grdev_card *card, struct udev_device *ud); + + /* + * Displays +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index bb89ee7170..3e3833fc95 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -1150,7 +1150,7 @@ void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud) { + if (!card) + return; + +- /* TODO: hotplug card */ ++ grdev_drm_card_hotplug(card, ud); + } + + static void session_configure(grdev_session *session) { diff --git a/0334-terminal-split-grdrm_crtc_commit-apart.patch b/0334-terminal-split-grdrm_crtc_commit-apart.patch new file mode 100644 index 0000000..7158f5b --- /dev/null +++ b/0334-terminal-split-grdrm_crtc_commit-apart.patch @@ -0,0 +1,262 @@ +From 95dbf6b19e8f25e28224b954ef99d96225b4e6e7 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 11:10:04 +0200 +Subject: [PATCH] terminal: split grdrm_crtc_commit() apart + +This helper is quite huge, split it apart to make it easier to follow. +--- + src/libsystemd-terminal/grdev-drm.c | 228 ++++++++++++++++++++---------------- + 1 file changed, 129 insertions(+), 99 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index f0f0448635..00aac292d2 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -1083,15 +1083,136 @@ static void grdrm_crtc_expose(grdrm_crtc *crtc) { + grdev_pipe_ready(&crtc->pipe->base, true); + } + +-static void grdrm_crtc_commit(grdrm_crtc *crtc) { ++static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) { ++ struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id }; ++ grdrm_card *card = crtc->object.card; ++ grdrm_pipe *pipe = crtc->pipe; ++ grdrm_fb *fb = fb_from_base(*slot); ++ size_t i; ++ int r; ++ ++ assert(crtc); ++ assert(slot); ++ assert(*slot); ++ assert(pipe); ++ ++ set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->set.connectors); ++ set_crtc.count_connectors = crtc->set.n_connectors; ++ set_crtc.fb_id = fb->id; ++ set_crtc.x = 0; ++ set_crtc.y = 0; ++ set_crtc.mode_valid = 1; ++ set_crtc.mode = crtc->set.mode; ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot set crtc %" PRIu32 ": %m", ++ card->base.name, crtc->object.id); ++ ++ grdrm_card_async(card, r); ++ return; ++ } ++ ++ if (!crtc->applied) { ++ log_debug("grdrm: %s: crtc %" PRIu32 " applied via deep modeset", ++ card->base.name, crtc->object.id); ++ crtc->applied = true; ++ } ++ ++ *slot = NULL; ++ pipe->base.front = &fb->base; ++ fb->flipid = 0; ++ ++pipe->counter; ++ pipe->base.flipping = false; ++ pipe->base.flip = false; ++ ++ if (!pipe->base.back) { ++ for (i = 0; i < pipe->base.max_fbs; ++i) { ++ if (!pipe->base.fbs[i]) ++ continue; ++ ++ fb = fb_from_base(pipe->base.fbs[i]); ++ if (&fb->base == pipe->base.front) ++ continue; ++ ++ fb->flipid = 0; ++ pipe->base.back = &fb->base; ++ break; ++ } ++ } ++} ++ ++static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) { + struct drm_mode_crtc_page_flip page_flip = { .crtc_id = crtc->object.id }; ++ grdrm_card *card = crtc->object.card; ++ grdrm_pipe *pipe = crtc->pipe; ++ grdrm_fb *fb = fb_from_base(*slot); ++ uint32_t cnt; ++ size_t i; ++ int r; ++ ++ assert(crtc); ++ assert(slot); ++ assert(*slot); ++ assert(pipe); ++ ++ if (!crtc->applied && !grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode)) ++ return 0; ++ ++ cnt = ++pipe->counter ? : ++pipe->counter; ++ page_flip.fb_id = fb->id; ++ page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT; ++ page_flip.user_data = grdrm_encode_vblank_data(crtc->object.id, cnt); ++ ++ r = ioctl(card->fd, DRM_IOCTL_MODE_PAGE_FLIP, &page_flip); ++ if (r < 0) { ++ r = -errno; ++ log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m", ++ card->base.name, crtc->object.id); ++ ++ if (grdrm_card_async(card, r)) ++ return r; ++ ++ return 0; ++ } ++ ++ if (!crtc->applied) { ++ log_debug("grdrm: %s: crtc %" PRIu32 " applied via page flip", ++ card->base.name, crtc->object.id); ++ crtc->applied = true; ++ } ++ ++ pipe->base.flipping = true; ++ pipe->base.flip = false; ++ pipe->counter = cnt; ++ fb->flipid = cnt; ++ *slot = NULL; ++ ++ if (!pipe->base.back) { ++ for (i = 0; i < pipe->base.max_fbs; ++i) { ++ if (!pipe->base.fbs[i]) ++ continue; ++ ++ fb = fb_from_base(pipe->base.fbs[i]); ++ if (&fb->base == pipe->base.front) ++ continue; ++ if (fb->flipid) ++ continue; ++ ++ pipe->base.back = &fb->base; ++ break; ++ } ++ } ++ ++ return 1; ++} ++ ++static void grdrm_crtc_commit(grdrm_crtc *crtc) { + struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id }; + grdrm_card *card = crtc->object.card; + grdrm_pipe *pipe; + grdev_fb **slot; +- grdrm_fb *fb; +- uint32_t cnt; +- size_t i; + int r; + + assert(crtc); +@@ -1141,102 +1262,11 @@ static void grdrm_crtc_commit(grdrm_crtc *crtc) { + if (!*slot) + return; + +- fb = fb_from_base(*slot); +- +- if (crtc->applied || grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode)) { +- cnt = ++pipe->counter ? : ++pipe->counter; +- page_flip.fb_id = fb->id; +- page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT; +- page_flip.user_data = grdrm_encode_vblank_data(crtc->object.id, cnt); +- +- r = ioctl(card->fd, DRM_IOCTL_MODE_PAGE_FLIP, &page_flip); +- if (r < 0) { +- r = -errno; +- log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m", +- card->base.name, crtc->object.id); +- +- if (grdrm_card_async(card, r)) +- return; +- +- /* fall through to deep modeset */ +- } else { +- if (!crtc->applied) { +- log_debug("grdrm: %s: crtc %" PRIu32 " applied via page flip", +- card->base.name, crtc->object.id); +- crtc->applied = true; +- } +- +- pipe->base.flipping = true; +- pipe->counter = cnt; +- fb->flipid = cnt; +- *slot = NULL; +- +- if (!pipe->base.back) { +- for (i = 0; i < pipe->base.max_fbs; ++i) { +- if (!pipe->base.fbs[i]) +- continue; +- +- fb = fb_from_base(pipe->base.fbs[i]); +- if (&fb->base == pipe->base.front) +- continue; +- if (fb->flipid) +- continue; +- +- pipe->base.back = &fb->base; +- break; +- } +- } +- } +- } +- +- if (!crtc->applied) { +- set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->set.connectors); +- set_crtc.count_connectors = crtc->set.n_connectors; +- set_crtc.fb_id = fb->id; +- set_crtc.x = 0; +- set_crtc.y = 0; +- set_crtc.mode_valid = 1; +- set_crtc.mode = crtc->set.mode; +- +- r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc); +- if (r < 0) { +- r = -errno; +- log_debug("grdrm: %s: cannot set crtc %" PRIu32 ": %m", +- card->base.name, crtc->object.id); +- +- grdrm_card_async(card, r); +- return; +- } +- +- if (!crtc->applied) { +- log_debug("grdrm: %s: crtc %" PRIu32 " applied via deep modeset", +- card->base.name, crtc->object.id); +- crtc->applied = true; +- } +- +- *slot = NULL; +- pipe->base.front = &fb->base; +- fb->flipid = 0; +- ++pipe->counter; +- pipe->base.flipping = false; +- +- if (!pipe->base.back) { +- for (i = 0; i < pipe->base.max_fbs; ++i) { +- if (!pipe->base.fbs[i]) +- continue; +- +- fb = fb_from_base(pipe->base.fbs[i]); +- if (&fb->base == pipe->base.front) +- continue; +- +- fb->flipid = 0; +- pipe->base.back = &fb->base; +- break; +- } +- } ++ r = grdrm_crtc_commit_flip(crtc, slot); ++ if (r == 0) { ++ /* in case we couldn't page-flip, perform deep modeset */ ++ grdrm_crtc_commit_deep(crtc, slot); + } +- +- pipe->base.flip = false; + } + + static void grdrm_crtc_restore(grdrm_crtc *crtc) { diff --git a/0335-terminal-grdev-raise-frame-event-after-DISPLAY_ADD-C.patch b/0335-terminal-grdev-raise-frame-event-after-DISPLAY_ADD-C.patch new file mode 100644 index 0000000..0b4e91b --- /dev/null +++ b/0335-terminal-grdev-raise-frame-event-after-DISPLAY_ADD-C.patch @@ -0,0 +1,56 @@ +From 3ec19e5d91d3d705682fee62a509801737c56c1e Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 11:11:07 +0200 +Subject: [PATCH] terminal: grdev: raise frame event after DISPLAY_ADD/CHANGE + +Whenever a display is added or changed, we suppressed any frame events. +Make sure to raise them manually so we can avoid rendering when handling +anything but FRAME events. +--- + src/libsystemd-terminal/grdev.c | 11 +++++++---- + src/libsystemd-terminal/modeset.c | 2 -- + 2 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index 3e3833fc95..397da1b205 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -921,14 +921,17 @@ static void session_change_display(grdev_session *session, grdev_display *displa + + changed = display_cache(display); + +- if (display->n_leafs == 0) ++ if (display->n_leafs == 0) { + session_remove_display(session, display); +- else if (!display->public) ++ } else if (!display->public) { + session_add_display(session, display); +- else if (changed) ++ session_frame(session, display); ++ } else if (changed) { + session_raise_display_change(session, display); +- else if (display->framed) + session_frame(session, display); ++ } else if (display->framed) { ++ session_frame(session, display); ++ } + } + + static void session_frame(grdev_session *session, grdev_display *display) { +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +index 57bf299df5..33c79a2036 100644 +--- a/src/libsystemd-terminal/modeset.c ++++ b/src/libsystemd-terminal/modeset.c +@@ -270,12 +270,10 @@ static void modeset_grdev_fn(grdev_session *session, void *userdata, grdev_event + switch (ev->type) { + case GRDEV_EVENT_DISPLAY_ADD: + grdev_display_enable(ev->display_add.display); +- modeset_render(m, ev->display_add.display); + break; + case GRDEV_EVENT_DISPLAY_REMOVE: + break; + case GRDEV_EVENT_DISPLAY_CHANGE: +- modeset_render(m, ev->display_change.display); + break; + case GRDEV_EVENT_DISPLAY_FRAME: + modeset_render(m, ev->display_frame.display); diff --git a/0336-terminal-grdev-schedule-virtual-frame-events-if-hw-d.patch b/0336-terminal-grdev-schedule-virtual-frame-events-if-hw-d.patch new file mode 100644 index 0000000..2085cd2 --- /dev/null +++ b/0336-terminal-grdev-schedule-virtual-frame-events-if-hw-d.patch @@ -0,0 +1,221 @@ +From 7b12a45b2dc6993e3f31642df2cc9b528294da40 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 11:12:44 +0200 +Subject: [PATCH] terminal: grdev: schedule virtual frame events if hw doesn't + support it + +Whenever we cannot use hardware frame events, we now schedule a virtual +frame event to make sure applications don't have to do this. Usually, +applications render only on data changes, but we can further reduce +render-time by also limiting rendering to vsyncs. +--- + src/libsystemd-terminal/grdev-drm.c | 17 +++++++- + src/libsystemd-terminal/grdev-internal.h | 3 ++ + src/libsystemd-terminal/grdev.c | 69 +++++++++++++++++++++++++++----- + 3 files changed, 79 insertions(+), 10 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 00aac292d2..3936a029fa 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -346,6 +346,8 @@ static bool grdrm_modes_compatible(const struct drm_mode_modeinfo *a, const stru + return false; + if (a->vdisplay != b->vdisplay) + return false; ++ if (a->vrefresh != b->vrefresh) ++ return false; + + return true; + } +@@ -1038,7 +1040,8 @@ static void grdrm_crtc_expose(grdrm_crtc *crtc) { + pipe = crtc->pipe; + if (pipe) { + if (pipe->base.width != crtc->set.mode.hdisplay || +- pipe->base.height != crtc->set.mode.vdisplay) { ++ pipe->base.height != crtc->set.mode.vdisplay || ++ pipe->base.vrefresh != crtc->set.mode.vrefresh) { + grdev_pipe_free(&pipe->base); + crtc->pipe = NULL; + pipe = NULL; +@@ -1127,6 +1130,12 @@ static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) { + pipe->base.flipping = false; + pipe->base.flip = false; + ++ /* We cannot schedule dummy page-flips on pipes, hence, the ++ * application would have to schedule their own frame-timers. ++ * To avoid duplicating that everywhere, we schedule our own ++ * timer and raise a fake FRAME event when it fires. */ ++ grdev_pipe_schedule(&pipe->base, 1); ++ + if (!pipe->base.back) { + for (i = 0; i < pipe->base.max_fbs; ++i) { + if (!pipe->base.fbs[i]) +@@ -1189,6 +1198,11 @@ static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) { + fb->flipid = cnt; + *slot = NULL; + ++ /* Raise fake FRAME event if it takes longer than 2 ++ * frames to receive the pageflip event. We assume the ++ * queue ran over or some other error happened. */ ++ grdev_pipe_schedule(&pipe->base, 2); ++ + if (!pipe->base.back) { + for (i = 0; i < pipe->base.max_fbs; ++i) { + if (!pipe->base.fbs[i]) +@@ -1501,6 +1515,7 @@ static int grdrm_pipe_new(grdrm_pipe **out, grdrm_crtc *crtc, struct drm_mode_mo + pipe->crtc = crtc; + pipe->base.width = mode->hdisplay; + pipe->base.height = mode->vdisplay; ++ pipe->base.vrefresh = mode->vrefresh ? : 25; + + grdrm_pipe_name(name, crtc); + r = grdev_pipe_add(&pipe->base, name, n_fbs); +diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h +index 96830a714c..f5915b16e8 100644 +--- a/src/libsystemd-terminal/grdev-internal.h ++++ b/src/libsystemd-terminal/grdev-internal.h +@@ -142,9 +142,11 @@ struct grdev_pipe { + + grdev_tile *tile; + grdev_display_cache *cache; ++ sd_event_source *vsync_src; + + uint32_t width; + uint32_t height; ++ uint32_t vrefresh; + + size_t max_fbs; + grdev_fb *front; +@@ -171,6 +173,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_pipe*, grdev_pipe_free); + + void grdev_pipe_ready(grdev_pipe *pipe, bool running); + void grdev_pipe_frame(grdev_pipe *pipe); ++void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames); + + /* + * Cards +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index 397da1b205..43d0c7c9bf 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -574,6 +574,13 @@ grdev_pipe *grdev_find_pipe(grdev_card *card, const char *name) { + return hashmap_get(card->pipe_map, name); + } + ++static int pipe_vsync_fn(sd_event_source *src, uint64_t usec, void *userdata) { ++ grdev_pipe *pipe = userdata; ++ ++ grdev_pipe_frame(pipe); ++ return 0; ++} ++ + int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) { + int r; + +@@ -585,6 +592,7 @@ int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) { + assert_return(!pipe->cache, -EINVAL); + assert_return(pipe->width > 0, -EINVAL); + assert_return(pipe->height > 0, -EINVAL); ++ assert_return(pipe->vrefresh > 0, -EINVAL); + assert_return(!pipe->enabled, -EINVAL); + assert_return(!pipe->running, -EINVAL); + assert_return(name, -EINVAL); +@@ -605,6 +613,20 @@ int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) { + if (r < 0) + return r; + ++ r = sd_event_add_time(pipe->card->session->context->event, ++ &pipe->vsync_src, ++ CLOCK_MONOTONIC, ++ 0, ++ 10 * USEC_PER_MSEC, ++ pipe_vsync_fn, ++ pipe); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF); ++ if (r < 0) ++ return r; ++ + r = hashmap_put(pipe->card->pipe_map, pipe->name, pipe); + if (r < 0) + return r; +@@ -633,6 +655,7 @@ grdev_pipe *grdev_pipe_free(grdev_pipe *pipe) { + tmp = *pipe; + pipe->vtable->free(pipe); + ++ sd_event_source_unref(tmp.vsync_src); + grdev_tile_free(tmp.tile); + card_modified(tmp.card); + free(tmp.fbs); +@@ -676,17 +699,15 @@ void grdev_pipe_ready(grdev_pipe *pipe, bool running) { + pipe->running = running; + + /* runtime events for unused pipes are not interesting */ +- if (pipe->cache) { ++ if (pipe->cache && pipe->enabled) { + grdev_display *display = pipe->tile->display; + + assert(display); + +- if (running) { +- if (pipe->enabled) +- session_frame(display->session, display); +- } else { ++ if (running) ++ session_frame(display->session, display); ++ else + pipe->cache->incomplete = true; +- } + } + } + +@@ -696,14 +717,44 @@ void grdev_pipe_frame(grdev_pipe *pipe) { + assert(pipe); + + /* if pipe is unused, ignore any frame events */ +- if (!pipe->cache) ++ if (!pipe->cache || !pipe->enabled) + return; + + display = pipe->tile->display; + assert(display); + +- if (pipe->enabled) +- session_frame(display->session, display); ++ grdev_pipe_schedule(pipe, 0); ++ session_frame(display->session, display); ++} ++ ++void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames) { ++ int r; ++ uint64_t ts; ++ ++ if (!frames) { ++ sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF); ++ return; ++ } ++ ++ r = sd_event_now(pipe->card->session->context->event, CLOCK_MONOTONIC, &ts); ++ if (r < 0) ++ goto error; ++ ++ ts += frames * USEC_PER_MSEC * 1000ULL / pipe->vrefresh; ++ ++ r = sd_event_source_set_time(pipe->vsync_src, ts); ++ if (r < 0) ++ goto error; ++ ++ r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_ONESHOT); ++ if (r < 0) ++ goto error; ++ ++ return; ++ ++error: ++ log_debug("grdev: %s/%s/%s: cannot schedule vsync timer: %s", ++ pipe->card->session->name, pipe->card->name, pipe->name, strerror(-r)); + } + + /* diff --git a/0337-terminal-restructure-some-logging-calls-in-grdrm.patch b/0337-terminal-restructure-some-logging-calls-in-grdrm.patch new file mode 100644 index 0000000..29274b1 --- /dev/null +++ b/0337-terminal-restructure-some-logging-calls-in-grdrm.patch @@ -0,0 +1,58 @@ +From f919ad9d3dc3e25f6eed268fe7eb5e922bcdb3b6 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 11:41:34 +0200 +Subject: [PATCH] terminal: restructure some logging calls in grdrm + +Multiple issues here: + 1) Don't print excessive card dumps on each resync. Disable it and make + developers add it themselves. + 2) Ignore EINVAL on page-flips. Some cards don't support page-flips, so + we'd print it on each frame. Maybe, at some point, the kernel will add + support to retrieve capabilities for that. Until then, simply ignore + it. + 3) Replace the now dropped card-dump with a short message about resyncing + the card. +--- + src/libsystemd-terminal/grdev-drm.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 3936a029fa..5cebb0609e 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -1177,8 +1177,12 @@ static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) { + r = ioctl(card->fd, DRM_IOCTL_MODE_PAGE_FLIP, &page_flip); + if (r < 0) { + r = -errno; +- log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m", +- card->base.name, crtc->object.id); ++ /* Avoid excessive logging on EINVAL; it is currently not ++ * possible to see whether cards support page-flipping, so ++ * avoid logging on each frame. */ ++ if (r != -EINVAL) ++ log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m", ++ card->base.name, crtc->object.id); + + if (grdrm_card_async(card, r)) + return r; +@@ -2145,6 +2149,8 @@ static void grdrm_card_hotplug(grdrm_card *card) { + if (!card->running) + return; + ++ log_debug("grdrm: %s/%s: reconfigure card", card->base.session->name, card->base.name); ++ + card->ready = false; + r = grdrm_card_resync(card); + if (r < 0) { +@@ -2155,7 +2161,10 @@ static void grdrm_card_hotplug(grdrm_card *card) { + + grdev_session_pin(card->base.session); + +- grdrm_card_print(card); ++ /* debug statement to print card information */ ++ if (0) ++ grdrm_card_print(card); ++ + grdrm_card_configure(card); + card->ready = true; + diff --git a/0338-terminal-fix-mode-sync-for-connectors.patch b/0338-terminal-fix-mode-sync-for-connectors.patch new file mode 100644 index 0000000..e52a4cb --- /dev/null +++ b/0338-terminal-fix-mode-sync-for-connectors.patch @@ -0,0 +1,115 @@ +From 0fbd4d113e0d2123e896e8005d1b7fe407c28c05 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 11:43:32 +0200 +Subject: [PATCH] terminal: fix mode sync for connectors + +The GETXY ioctls of DRM are usually called twice by libdrm: Once to +retrieve the number of objects, a second time with suitably sized buffers +to actually retrieve all objects. In grdrm, we avoid these excessive calls +and instead just call ioctls with cached buffers and resize them if they +were too small. + +However, connectors need to read the mode list via EDID, which is horribly +slow. As the kernel still cannot do that asynchronously (seriously, we +need to fix this!), it has a hack to only do it if count_modes==0. This is +fine with libdrm, as it calls every ioctl twice, anyway. However, we fail +horribly with this as we usually never pass 0. + +Fix this by calling into GETCONNECTOR ioctls twice in case we received an +hotplug event. Only in those cases, we need to re-read modes, so this +should be totally fine. +--- + src/libsystemd-terminal/grdev-drm.c | 33 ++++++++++++++++++++++++--------- + 1 file changed, 24 insertions(+), 9 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 5cebb0609e..2e55ad326b 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -264,6 +264,7 @@ struct grdrm_card { + Hashmap *object_map; + + bool async_hotplug : 1; ++ bool hotplug : 1; + bool running : 1; + bool ready : 1; + bool cap_dumb : 1; +@@ -603,12 +604,19 @@ static int grdrm_connector_resync(grdrm_connector *connector) { + res.count_encoders = connector->kern.max_encoders; + res.count_props = connector->kern.max_props; + +- /* Retrieve modes only if we have none. This avoids expensive +- * EDID reads in the kernel, that can slow down resyncs +- * considerably! */ +- if (connector->kern.n_modes == 0) { +- res.modes_ptr = PTR_TO_UINT64(connector->kern.modes); +- res.count_modes = connector->kern.max_modes; ++ /* The kernel reads modes from the EDID information only if we ++ * pass count_modes==0. This is a legacy hack for libdrm (which ++ * called every ioctl twice). Now we have to adopt.. *sigh*. ++ * If we never received an hotplug event, there's no reason to ++ * sync modes. EDID reads are heavy, so skip that if not ++ * required. */ ++ if (card->hotplug) { ++ if (tries > 0) { ++ res.modes_ptr = PTR_TO_UINT64(connector->kern.modes); ++ res.count_modes = connector->kern.max_modes; ++ } else { ++ resized = true; ++ } + } + + r = ioctl(card->fd, DRM_IOCTL_MODE_GETCONNECTOR, &res); +@@ -689,7 +697,6 @@ static int grdrm_connector_resync(grdrm_connector *connector) { + continue; + + connector->kern.n_encoders = res.count_encoders; +- connector->kern.n_modes = res.count_modes; + connector->kern.n_props = res.count_props; + connector->kern.type = res.connector_type; + connector->kern.type_id = res.connector_type_id; +@@ -698,6 +705,8 @@ static int grdrm_connector_resync(grdrm_connector *connector) { + connector->kern.mm_width = res.mm_width; + connector->kern.mm_height = res.mm_height; + connector->kern.subpixel = res.subpixel; ++ if (res.modes_ptr == PTR_TO_UINT64(connector->kern.modes)) ++ connector->kern.n_modes = res.count_modes; + + break; + } +@@ -2167,6 +2176,7 @@ static void grdrm_card_hotplug(grdrm_card *card) { + + grdrm_card_configure(card); + card->ready = true; ++ card->hotplug = false; + + grdev_session_unpin(card->base.session); + } +@@ -2374,6 +2384,7 @@ static int grdrm_card_open(grdrm_card *card, int dev_fd) { + + sd_event_source_set_enabled(card->fd_src, SD_EVENT_OFF); + ++ card->hotplug = true; + card->fd = fd; + fd = -1; + +@@ -3029,13 +3040,17 @@ void grdev_drm_card_hotplug(grdev_card *basecard, struct udev_device *ud) { + /* If we get add/remove events on DRM nodes without devnum, we + * got hotplugged DRM objects so refresh the device. */ + devnum = udev_device_get_devnum(ud); +- if (devnum == 0) ++ if (devnum == 0) { ++ card->hotplug = true; + grdrm_card_hotplug(card); ++ } + } else if (streq_ptr(action, "change")) { + /* A change event with HOTPLUG=1 is sent whenever a connector + * changed state. Refresh the device to update our state. */ + p = udev_device_get_property_value(ud, "HOTPLUG"); +- if (streq_ptr(p, "1")) ++ if (streq_ptr(p, "1")) { ++ card->hotplug = true; + grdrm_card_hotplug(card); ++ } + } + } diff --git a/0339-test-udev-restrict-nemuric-uid-s-to-existing-ones.patch b/0339-test-udev-restrict-nemuric-uid-s-to-existing-ones.patch new file mode 100644 index 0000000..01119d4 --- /dev/null +++ b/0339-test-udev-restrict-nemuric-uid-s-to-existing-ones.patch @@ -0,0 +1,158 @@ +From 9158d03e4042876b7627947b3489fd4d49c7553a Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 20 Sep 2014 18:12:53 +0200 +Subject: [PATCH] test: udev - restrict nemuric uid's to existing ones + +We now verify the existence of uid's before applying them to devicenodes, so change the +test accordingly. We assume that both uid/gid 1 and 2 exist on the test system. +--- + test/udev-test.pl | 62 +++++++++++++++++++++++++++---------------------------- + 1 file changed, 31 insertions(+), 31 deletions(-) + +diff --git a/test/udev-test.pl b/test/udev-test.pl +index 23f1b726e0..14f11df8af 100755 +--- a/test/udev-test.pl ++++ b/test/udev-test.pl +@@ -549,21 +549,21 @@ KERNEL=="tty33", OWNER="bad", GROUP="name" + EOF + }, + { +- desc => "permissions OWNER=5000", ++ desc => "permissions OWNER=1", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", +- exp_perms => "5000::0600", ++ exp_perms => "1::0600", + rules => < "permissions GROUP=100", ++ desc => "permissions GROUP=1", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", +- exp_perms => ":100:0660", ++ exp_perms => ":1:0660", + rules => < "permissions OWNER=5000 GROUP=100 MODE=0777", ++ desc => "permissions OWNER=1 GROUP=1 MODE=0777", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", +- exp_perms => "5000:100:0777", ++ exp_perms => "1:1:0777", + rules => < "permissions OWNER to 5000", ++ desc => "permissions OWNER to 1", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", +- exp_perms => "5000::", ++ exp_perms => "1::", + rules => < "permissions GROUP to 100", ++ desc => "permissions GROUP to 1", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", +- exp_perms => ":100:0660", ++ exp_perms => ":1:0660", + rules => < "permissions OWNER, GROUP, MODE", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", +- exp_perms => "5000:100:0777", ++ exp_perms => "1:1:0777", + rules => < "permissions only rule", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", +- exp_perms => "5000:100:0777", ++ exp_perms => "1:1:0777", + rules => < "multiple permissions only rule", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", +- exp_perms => "3000:4000:0777", ++ exp_perms => "1:1:0777", + rules => < "permissions only rule with override at SYMLINK+ rule", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", +- exp_perms => "3000:8000:0777", ++ exp_perms => "1:2:0777", + rules => < "TEST PROGRAM feeds OWNER, GROUP, MODE", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "sda", +- exp_perms => "5000:100:0400", ++ exp_perms => "1:1:0400", + exp_rem_error => "yes", + rules => < +Date: Fri, 19 Sep 2014 17:50:41 +0200 +Subject: [PATCH] bus-policy: story mandatory items in right list + +--- + src/bus-proxyd/bus-policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index d2eace9405..8676d31f62 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -332,7 +332,7 @@ static int file_load(Policy *p, const char *path) { + if (policy_category == POLICY_CATEGORY_DEFAULT) + LIST_PREPEND(items, p->default_items, i); + else if (policy_category == POLICY_CATEGORY_MANDATORY) +- LIST_PREPEND(items, p->default_items, i); ++ LIST_PREPEND(items, p->mandatory_items, i); + else if (policy_category == POLICY_CATEGORY_USER) { + const char *u = policy_user; + diff --git a/0341-bus-policy-append-items-rather-than-prepending-them.patch b/0341-bus-policy-append-items-rather-than-prepending-them.patch new file mode 100644 index 0000000..c584cd9 --- /dev/null +++ b/0341-bus-policy-append-items-rather-than-prepending-them.patch @@ -0,0 +1,60 @@ +From e7eb49db071f9aab2a9bad0660962f2aa4d0c7d1 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 19 Sep 2014 22:05:01 +0200 +Subject: [PATCH] bus-policy: append items rather than prepending them + +In the D-Bus policy, the order of items matters, so make sure to store them +in the same order as they are parsed by the sax parser. +--- + src/bus-proxyd/bus-policy.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 8676d31f62..eed542d8f8 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -39,6 +39,14 @@ static void policy_item_free(PolicyItem *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; +@@ -330,9 +338,9 @@ static int file_load(Policy *p, const char *path) { + } + + if (policy_category == POLICY_CATEGORY_DEFAULT) +- LIST_PREPEND(items, p->default_items, i); ++ item_append(i, &p->default_items); + else if (policy_category == POLICY_CATEGORY_MANDATORY) +- LIST_PREPEND(items, p->mandatory_items, i); ++ item_append(i, &p->mandatory_items); + else if (policy_category == POLICY_CATEGORY_USER) { + const char *u = policy_user; + +@@ -355,7 +363,7 @@ static int file_load(Policy *p, const char *path) { + PolicyItem *first; + + first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid)); +- LIST_PREPEND(items, first, i); ++ item_append(i, &first); + + r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first); + if (r < 0) { +@@ -386,7 +394,7 @@ static int file_load(Policy *p, const char *path) { + PolicyItem *first; + + first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid)); +- LIST_PREPEND(items, first, i); ++ item_append(i, &first); + + r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first); + if (r < 0) { diff --git a/0342-bus_policy-set-i-ug-id_valid.patch b/0342-bus_policy-set-i-ug-id_valid.patch new file mode 100644 index 0000000..e178d05 --- /dev/null +++ b/0342-bus_policy-set-i-ug-id_valid.patch @@ -0,0 +1,29 @@ +From c3502b59ec4e58a877003050e6c2fc668eee3129 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Sat, 20 Sep 2014 16:34:31 +0200 +Subject: [PATCH] bus_policy: set i->[ug]id_valid + +--- + src/bus-proxyd/bus-policy.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index eed542d8f8..2c4708dd77 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -364,6 +364,7 @@ static int file_load(Policy *p, const char *path) { + + 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) { +@@ -395,6 +396,7 @@ static int file_load(Policy *p, const char *path) { + + 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) { diff --git a/0343-bus-policy-resolve-ug-id-of-POLICY_ITEM_-USER-GROUP.patch b/0343-bus-policy-resolve-ug-id-of-POLICY_ITEM_-USER-GROUP.patch new file mode 100644 index 0000000..605f9d9 --- /dev/null +++ b/0343-bus-policy-resolve-ug-id-of-POLICY_ITEM_-USER-GROUP.patch @@ -0,0 +1,52 @@ +From 9eacea6b51bb86fb2c066bd4fa7cba28a17d12f3 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Sat, 20 Sep 2014 04:34:30 +0200 +Subject: [PATCH] bus-policy: resolve [ug]id of POLICY_ITEM_{USER,GROUP} + +Do the lookup during parsing already, and set i->uid, or i->gid to the +numerical values. +--- + src/bus-proxyd/bus-policy.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 2c4708dd77..ab16cda32b 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -525,8 +525,36 @@ static int file_load(Policy *p, const char *path) { + 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("Failed to resolve user %s: %s", name, strerror(-r)); ++ 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("Failed to resolve group %s: %s", name, strerror(-r)); ++ else ++ i->gid_valid = true; ++ } ++ break; ++ default: ++ break; ++ } ++ + i->name = name; + name = NULL; ++ + state = STATE_ALLOW_DENY; + } else { + log_error("Unexpected token (14) in %s:%u.", path, line); diff --git a/0344-bus-policy-implement-dump_items-with-LIST_FOREACH.patch b/0344-bus-policy-implement-dump_items-with-LIST_FOREACH.patch new file mode 100644 index 0000000..68eebeb --- /dev/null +++ b/0344-bus-policy-implement-dump_items-with-LIST_FOREACH.patch @@ -0,0 +1,118 @@ +From 080edb3484dc3ecf8d914526fdd3090b40fdf5b6 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 19 Sep 2014 14:05:18 +0200 +Subject: [PATCH] bus-policy: implement dump_items() with LIST_FOREACH + +Instead of making the function call itself recursively. +--- + src/bus-proxyd/bus-policy.c | 78 ++++++++++++++++++++++----------------------- + 1 file changed, 39 insertions(+), 39 deletions(-) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index ab16cda32b..227742ba74 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -658,64 +658,64 @@ void policy_free(Policy *p) { + p->user_items = p->group_items = NULL; + } + +-static void dump_items(PolicyItem *i, const char *prefix) { ++static void dump_items(PolicyItem *items, const char *prefix) { + +- if (!i) ++ PolicyItem *i; ++ ++ if (!items) + return; + + if (!prefix) + prefix = ""; + +- printf("%sType: %s\n" +- "%sClass: %s\n", +- prefix, policy_item_type_to_string(i->type), +- prefix, policy_item_class_to_string(i->class)); ++ LIST_FOREACH(items, i, items) { + +- if (i->interface) +- printf("%sInterface: %s\n", +- prefix, i->interface); ++ 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->member) +- printf("%sMember: %s\n", +- prefix, i->member); ++ if (i->interface) ++ printf("%sInterface: %s\n", ++ prefix, i->interface); + +- if (i->error) +- printf("%sError: %s\n", +- prefix, i->error); ++ if (i->member) ++ printf("%sMember: %s\n", ++ prefix, i->member); + +- if (i->path) +- printf("%sPath: %s\n", +- prefix, i->path); ++ if (i->error) ++ printf("%sError: %s\n", ++ prefix, i->error); + +- if (i->name) +- printf("%sName: %s\n", +- prefix, i->name); ++ if (i->path) ++ printf("%sPath: %s\n", ++ prefix, i->path); + +- if (i->message_type != 0) +- printf("%sMessage Type: %s\n", +- prefix, bus_message_type_to_string(i->message_type)); ++ if (i->name) ++ printf("%sName: %s\n", ++ prefix, i->name); + +- if (i->uid_valid) { +- _cleanup_free_ char *user; ++ if (i->message_type != 0) ++ printf("%sMessage Type: %s\n", ++ prefix, bus_message_type_to_string(i->message_type)); + +- user = uid_to_name(i->uid); ++ if (i->uid_valid) { ++ _cleanup_free_ char *user; + +- printf("%sUser: %s\n", +- prefix, strna(user)); +- } ++ user = uid_to_name(i->uid); + +- if (i->gid_valid) { +- _cleanup_free_ char *group; ++ printf("%sUser: %s\n", ++ prefix, strna(user)); ++ } + +- group = gid_to_name(i->gid); ++ if (i->gid_valid) { ++ _cleanup_free_ char *group; + +- printf("%sGroup: %s\n", +- prefix, strna(group)); +- } ++ group = gid_to_name(i->gid); + +- if (i->items_next) { +- printf("%s%s\n", prefix, draw_special_char(DRAW_DASH)); +- dump_items(i->items_next, prefix); ++ printf("%sGroup: %s\n", ++ prefix, strna(group)); ++ } + } + } + diff --git a/0345-bus-policy-do-not-exit-from-policy_dump.patch b/0345-bus-policy-do-not-exit-from-policy_dump.patch new file mode 100644 index 0000000..21a117b --- /dev/null +++ b/0345-bus-policy-do-not-exit-from-policy_dump.patch @@ -0,0 +1,33 @@ +From e42bb8d4ed7c81abbe416ef30436f7b4b9e07bad Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Sat, 20 Sep 2014 15:59:40 +0200 +Subject: [PATCH] bus-policy: do not exit() from policy_dump() + +This function is quite useful for debugging. Exiting from it seems +unnecessary. +--- + src/bus-proxyd/bus-policy.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 227742ba74..4bc575f3ab 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -730,7 +730,7 @@ static void dump_hashmap_items(Hashmap *h) { + } + } + +-noreturn void policy_dump(Policy *p) { ++void policy_dump(Policy *p) { + + printf("%s Default Items:\n", draw_special_char(DRAW_ARROW)); + dump_items(p->default_items, "\t"); +@@ -743,8 +743,6 @@ noreturn void policy_dump(Policy *p) { + + printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW)); + dump_items(p->mandatory_items, "\t"); +- +- exit(0); + } + + static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = { diff --git a/0346-bus-policy-print-numeric-gu-id-in-dump_items.patch b/0346-bus-policy-print-numeric-gu-id-in-dump_items.patch new file mode 100644 index 0000000..20e9de0 --- /dev/null +++ b/0346-bus-policy-print-numeric-gu-id-in-dump_items.patch @@ -0,0 +1,35 @@ +From ed91202f1c237a41a3ee3754a4a1d37139d7f34f Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Sat, 20 Sep 2014 18:09:00 +0200 +Subject: [PATCH] bus-policy: print numeric [gu]id in dump_items() + +--- + src/bus-proxyd/bus-policy.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 4bc575f3ab..e870fbc948 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -704,8 +704,8 @@ static void dump_items(PolicyItem *items, const char *prefix) { + + user = uid_to_name(i->uid); + +- printf("%sUser: %s\n", +- prefix, strna(user)); ++ printf("%sUser: %s (%d)\n", ++ prefix, strna(user), i->uid); + } + + if (i->gid_valid) { +@@ -713,8 +713,8 @@ static void dump_items(PolicyItem *items, const char *prefix) { + + group = gid_to_name(i->gid); + +- printf("%sGroup: %s\n", +- prefix, strna(group)); ++ printf("%sGroup: %s (%d)\n", ++ prefix, strna(group), i->gid); + } + } + } diff --git a/0347-bus-policy-add-policy-check-function.patch b/0347-bus-policy-add-policy-check-function.patch new file mode 100644 index 0000000..4a9acd8 --- /dev/null +++ b/0347-bus-policy-add-policy-check-function.patch @@ -0,0 +1,199 @@ +From 38349552d8d6418229fee9ee68b1f470b4ad7a52 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 19 Sep 2014 14:38:52 +0200 +Subject: [PATCH] bus-policy: add policy check function + +Add policy_check() to actually check whether an incoming message is allowed +by the policy. The code is not yet used from the proxy daemon, though. +--- + src/bus-proxyd/bus-policy.c | 156 ++++++++++++++++++++++++++++++++++++++++++++ + src/bus-proxyd/bus-policy.h | 2 + + 2 files changed, 158 insertions(+) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index e870fbc948..151d679f6b 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -24,6 +24,7 @@ + #include "strv.h" + #include "conf-files.h" + #include "bus-internal.h" ++#include "bus-message.h" + #include "bus-policy.h" + + static void policy_item_free(PolicyItem *i) { +@@ -591,6 +592,161 @@ static int file_load(Policy *p, const char *path) { + } + } + ++static bool is_matching_name_request(sd_bus_message *m, const char *name, bool prefix) { ++ ++ char *n = NULL; ++ int r; ++ ++ if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) ++ return false; ++ ++ r = sd_bus_message_read(m, "s", &n); ++ if (r < 0) ++ return false; ++ ++ r = sd_bus_message_rewind(m, true); ++ if (r < 0) ++ return false; ++ ++ if (prefix) ++ return startswith(name, n); ++ else ++ return streq_ptr(name, n); ++} ++ ++static bool is_matching_call(PolicyItem *i, sd_bus_message *m, const char *name) { ++ ++ if (i->message_type && (i->message_type != m->header->type)) ++ return false; ++ ++ if (i->path && (!m->path || !streq(i->path, m->path))) ++ return false; ++ ++ if (i->member && (!m->member || !streq(i->member, m->member))) ++ return false; ++ ++ if (i->interface && (!m->interface || !streq(i->interface, m->interface))) ++ return false; ++ ++ if (i->name && (!name || !streq(i->name, name))) ++ return false; ++ ++ return true; ++} ++ ++enum { ++ ALLOW, ++ DUNNO, ++ DENY, ++}; ++ ++static int is_permissive(PolicyItem *i) { ++ ++ return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY; ++} ++ ++static int check_policy_item(PolicyItem *i, sd_bus_message *m, const struct ucred *ucred) { ++ ++ switch (i->class) { ++ case POLICY_ITEM_SEND: ++ if ((m->bus->is_kernel && is_matching_call(i, m, m->destination)) || ++ (!m->bus->is_kernel && is_matching_call(i, m, m->sender))) ++ return is_permissive(i); ++ break; ++ ++ case POLICY_ITEM_RECV: ++ if ((m->bus->is_kernel && is_matching_call(i, m, m->sender)) || ++ (!m->bus->is_kernel && is_matching_call(i, m, m->destination))) ++ return is_permissive(i); ++ break; ++ ++ case POLICY_ITEM_OWN: ++ if (is_matching_name_request(m, i->name, false)) ++ return is_permissive(i); ++ break; ++ ++ case POLICY_ITEM_OWN_PREFIX: ++ if (is_matching_name_request(m, i->name, true)) ++ return is_permissive(i); ++ break; ++ ++ case POLICY_ITEM_USER: ++ if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && ++ (streq_ptr(i->name, "*") || (i->uid_valid && i->uid == ucred->uid))) ++ return is_permissive(i); ++ break; ++ ++ case POLICY_ITEM_GROUP: ++ if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && ++ (streq_ptr(i->name, "*") || (i->gid_valid && i->gid == ucred->gid))) ++ return is_permissive(i); ++ break; ++ ++ case POLICY_ITEM_IGNORE: ++ default: ++ break; ++ } ++ ++ return DUNNO; ++} ++ ++static int check_policy_items(PolicyItem *items, sd_bus_message *m, const struct ucred *ucred) { ++ ++ PolicyItem *i; ++ int r, ret = DUNNO; ++ ++ /* 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) { ++ r = check_policy_item(i, m, ucred); ++ if (r != DUNNO) ++ ret = r; ++ } ++ ++ return ret; ++} ++ ++bool policy_check(Policy *p, sd_bus_message *m, const struct ucred *ucred) { ++ ++ PolicyItem *items; ++ int r; ++ ++ /* ++ * The policy check is implemented by the following logic: ++ * ++ * 1. Check mandatory items. If the message matches any of these, it is decisive. ++ * 2. See if the passed ucred match against the user/group hashmaps. A matching entry is also decisive. ++ * 3. Consult the defaults if non of the above matched with a more specific rule. ++ * 4. If the message isn't caught be the defaults either, reject it. ++ */ ++ ++ r = check_policy_items(p->mandatory_items, m, ucred); ++ if (r != DUNNO) ++ return r == ALLOW; ++ ++ if (ucred->pid > 0) { ++ items = hashmap_get(p->user_items, UINT32_TO_PTR(ucred->uid)); ++ if (items) { ++ r = check_policy_items(items, m, ucred); ++ if (r != DUNNO) ++ return r == ALLOW; ++ } ++ ++ items = hashmap_get(p->group_items, UINT32_TO_PTR(ucred->gid)); ++ if (items) { ++ r = check_policy_items(items, m, ucred); ++ if (r != DUNNO) ++ return r == ALLOW; ++ } ++ } ++ ++ r = check_policy_items(p->default_items, m, ucred); ++ if (r != DUNNO) ++ return r == ALLOW; ++ ++ return false; ++} ++ + int policy_load(Policy *p, char **files) { + char **i; + int r; +diff --git a/src/bus-proxyd/bus-policy.h b/src/bus-proxyd/bus-policy.h +index a6ff5c37f6..2222716e7a 100644 +--- a/src/bus-proxyd/bus-policy.h ++++ b/src/bus-proxyd/bus-policy.h +@@ -76,6 +76,8 @@ typedef struct Policy { + int policy_load(Policy *p, char **files); + void policy_free(Policy *p); + ++bool policy_check(Policy *p, sd_bus_message *m, const struct ucred *c); ++ + void policy_dump(Policy *p); + + const char* policy_item_type_to_string(PolicyItemType t) _const_; diff --git a/0348-bus-policy-add-test-utility.patch b/0348-bus-policy-add-test-utility.patch new file mode 100644 index 0000000..b08ca1f --- /dev/null +++ b/0348-bus-policy-add-test-utility.patch @@ -0,0 +1,341 @@ +From 20725d929ff566e53d7a857d6f0ee94aa8383469 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 19 Sep 2014 14:50:53 +0200 +Subject: [PATCH] bus-policy: add test utility + +Add some test files and routines for dbus policy checking. +--- + .gitignore | 1 + + Makefile.am | 20 ++++- + src/bus-proxyd/test-bus-policy.c | 165 +++++++++++++++++++++++++++++++++++++++ + test/bus-policy/hello.conf | 14 ++++ + test/bus-policy/methods.conf | 15 ++++ + test/bus-policy/ownerships.conf | 24 ++++++ + test/bus-policy/signals.conf | 15 ++++ + 7 files changed, 252 insertions(+), 2 deletions(-) + create mode 100644 src/bus-proxyd/test-bus-policy.c + create mode 100644 test/bus-policy/hello.conf + create mode 100644 test/bus-policy/methods.conf + create mode 100644 test/bus-policy/ownerships.conf + create mode 100644 test/bus-policy/signals.conf + +diff --git a/.gitignore b/.gitignore +index 288946029b..b78a4cb4e1 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -146,6 +146,7 @@ + /test-bus-match + /test-bus-memfd + /test-bus-objects ++/test-bus-policy + /test-bus-server + /test-bus-signature + /test-bus-zero-copy +diff --git a/Makefile.am b/Makefile.am +index f80ffc6749..6b2ca29ce8 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1342,7 +1342,8 @@ tests += \ + test-async \ + test-ratelimit \ + test-condition-util \ +- test-uid-range ++ test-uid-range \ ++ test-bus-policy + + EXTRA_DIST += \ + test/a.service \ +@@ -1374,7 +1375,12 @@ EXTRA_DIST += \ + test/sysinit.target \ + test/testsuite.target \ + test/timers.target \ +- test/unstoppable.service ++ test/unstoppable.service \ ++ test/bus-policy/hello.conf \ ++ test/bus-policy/methods.conf \ ++ test/bus-policy/ownerships.conf \ ++ test/bus-policy/signals.conf ++ + + EXTRA_DIST += \ + src/test/test-helper.h +@@ -1782,6 +1788,16 @@ test_conf_files_SOURCES = \ + test_conf_files_LDADD = \ + libsystemd-shared.la + ++test_bus_policy_SOURCES = \ ++ src/bus-proxyd/test-bus-policy.c \ ++ src/bus-proxyd/bus-policy.c \ ++ src/bus-proxyd/bus-policy.h ++ ++test_bus_policy_LDADD = \ ++ libsystemd-capability.la \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la ++ + # ------------------------------------------------------------------------------ + ## .PHONY so it always rebuilds it + .PHONY: coverage lcov-run lcov-report coverage-sync +diff --git a/src/bus-proxyd/test-bus-policy.c b/src/bus-proxyd/test-bus-policy.c +new file mode 100644 +index 0000000000..ed17bfe96e +--- /dev/null ++++ b/src/bus-proxyd/test-bus-policy.c +@@ -0,0 +1,165 @@ ++/*-*- 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 "bus-internal.h" ++#include "build.h" ++#include "strv.h" ++#include "def.h" ++#include "capability.h" ++ ++#include ++ ++static int make_name_request(sd_bus *bus, ++ const char *name, ++ sd_bus_message **ret) { ++ ++ int r; ++ sd_bus_message *m = NULL; ++ ++ r = sd_bus_message_new_method_call(bus, &m, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "RequestName"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append_basic(m, 's', name); ++ if (r < 0) ++ return r; ++ ++ m->sealed = 1; ++ sd_bus_message_rewind(m, true); ++ ++ *ret = m; ++ return 0; ++} ++ ++int main(int argc, char *argv[]) { ++ ++ Policy p = {}; ++ sd_bus_message *m; ++ struct ucred ucred = {}; ++ _cleanup_bus_close_unref_ sd_bus *bus = NULL;; ++ ++ assert_se(sd_bus_default_system(&bus) >= 0); ++ ++ /* Fake pid for policy checks */ ++ ucred.pid = 1; ++ ++ /* Ownership tests */ ++ assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/ownerships.conf")) == 0); ++ ++ assert_se(make_name_request(bus, "org.test.test1", &m) == 0); ++ ucred.uid = 0; ++ assert_se(policy_check(&p, m, &ucred) == true); ++ ucred.uid = 1; ++ assert_se(policy_check(&p, m, &ucred) == true); ++ assert_se(sd_bus_message_unref(m) == 0); ++ ++ assert_se(make_name_request(bus, "org.test.test2", &m) == 0); ++ ucred.uid = 0; ++ assert_se(policy_check(&p, m, &ucred) == true); ++ ucred.uid = 1; ++ assert_se(policy_check(&p, m, &ucred) == false); ++ assert_se(sd_bus_message_unref(m) == 0); ++ ++ assert_se(make_name_request(bus, "org.test.test3", &m) == 0); ++ ucred.uid = 0; ++ assert_se(policy_check(&p, m, &ucred) == false); ++ ucred.uid = 1; ++ assert_se(policy_check(&p, m, &ucred) == false); ++ assert_se(sd_bus_message_unref(m) == 0); ++ ++ assert_se(make_name_request(bus, "org.test.test4", &m) == 0); ++ ucred.uid = 0; ++ assert_se(policy_check(&p, m, &ucred) == false); ++ ucred.uid = 1; ++ assert_se(policy_check(&p, m, &ucred) == true); ++ assert_se(sd_bus_message_unref(m) == 0); ++ ++ policy_free(&p); ++ ++ /* Signal test */ ++ assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/signals.conf")) == 0); ++ ++ assert_se(sd_bus_message_new_signal(bus, &m, "/an/object/path", "bli.bla.blubb", "Name") == 0); ++ ucred.uid = 0; ++ assert_se(policy_check(&p, m, &ucred) == true); ++ ++ ucred.uid = 1; ++ assert_se(policy_check(&p, m, &ucred) == false); ++ assert_se(sd_bus_message_unref(m) == 0); ++ ++ policy_free(&p); ++ ++ /* Method calls */ ++ assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/methods.conf")) == 0); ++ ++ ucred.uid = 0; ++ assert_se(sd_bus_message_new_method_call(bus, &m, "org.foo.bar", "/an/object/path", "bli.bla.blubb", "Member") == 0); ++ assert_se(policy_check(&p, m, &ucred) == false); ++ ++ assert_se(sd_bus_message_new_method_call(bus, &m, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == 0); ++ assert_se(policy_check(&p, m, &ucred) == false); ++ ++ bus->is_kernel = 1; ++ assert_se(sd_bus_message_new_method_call(bus, &m, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == 0); ++ assert_se(policy_check(&p, m, &ucred) == true); ++ ++ assert_se(sd_bus_message_new_method_call(bus, &m, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == 0); ++ assert_se(policy_check(&p, m, &ucred) == true); ++ ++ policy_free(&p); ++ ++ /* User and groups */ ++ assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/hello.conf")) == 0); ++ assert_se(sd_bus_message_new_method_call(bus, &m, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "Hello") == 0); ++ policy_dump(&p); ++ ++ ucred.uid = 0; ++ assert_se(policy_check(&p, m, &ucred) == true); ++ ++ ucred.uid = 1; ++ assert_se(policy_check(&p, m, &ucred) == false); ++ ++ ucred.uid = 0; ++ ucred.gid = 1; ++ assert_se(policy_check(&p, m, &ucred) == false); ++ ++ policy_free(&p); ++ ++ ++ return EXIT_SUCCESS; ++} +diff --git a/test/bus-policy/hello.conf b/test/bus-policy/hello.conf +new file mode 100644 +index 0000000000..af09893de6 +--- /dev/null ++++ b/test/bus-policy/hello.conf +@@ -0,0 +1,14 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/test/bus-policy/methods.conf b/test/bus-policy/methods.conf +new file mode 100644 +index 0000000000..d6c28c71bc +--- /dev/null ++++ b/test/bus-policy/methods.conf +@@ -0,0 +1,15 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/test/bus-policy/ownerships.conf b/test/bus-policy/ownerships.conf +new file mode 100644 +index 0000000000..bc3a230a26 +--- /dev/null ++++ b/test/bus-policy/ownerships.conf +@@ -0,0 +1,24 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/test/bus-policy/signals.conf b/test/bus-policy/signals.conf +new file mode 100644 +index 0000000000..440e3fe6d0 +--- /dev/null ++++ b/test/bus-policy/signals.conf +@@ -0,0 +1,15 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ diff --git a/0349-terminal-print-RESYNC-state-in-evcat.patch b/0349-terminal-print-RESYNC-state-in-evcat.patch new file mode 100644 index 0000000..104d925 --- /dev/null +++ b/0349-terminal-print-RESYNC-state-in-evcat.patch @@ -0,0 +1,25 @@ +From 4c4e4128f3763eb3d4836a23b9c46b6122e81d62 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 12:33:18 +0200 +Subject: [PATCH] terminal: print RESYNC state in evcat + +Whenever a key-event is part of a RESYNC, we should print that verbosely +as those events are out-of-order. +--- + src/libsystemd-terminal/evcat.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c +index 8c27fb2c54..b3f08e60bf 100644 +--- a/src/libsystemd-terminal/evcat.c ++++ b/src/libsystemd-terminal/evcat.c +@@ -203,6 +203,9 @@ static void kdata_print(idev_data *data) { + k->value == 1 ? "DOWN" : + "REPEAT"); + ++ /* Resync state */ ++ printf(" | %-6s", data->resync ? "RESYNC" : ""); ++ + /* Keycode that triggered the event */ + printf(" | %5u", (unsigned)k->keycode); + diff --git a/0350-terminal-always-call-_enable-_disable-on-evdev-devic.patch b/0350-terminal-always-call-_enable-_disable-on-evdev-devic.patch new file mode 100644 index 0000000..fb43272 --- /dev/null +++ b/0350-terminal-always-call-_enable-_disable-on-evdev-devic.patch @@ -0,0 +1,93 @@ +From 6022343476982439dfc2e06bf54db78a0c8c6bff Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 12:34:43 +0200 +Subject: [PATCH] terminal: always call _enable/_disable on evdev devices + +The current pause/resume logic kinda intertwines the resume/pause and +enable/disable functions. Lets avoid that non-obvious behavior and always +make resume call into enable, and pause call into disable, if appropriate. +--- + src/libsystemd-terminal/idev-evdev.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index 18c48ee592..25ac849b8d 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -49,6 +49,7 @@ struct idev_evdev { + + bool unsync : 1; /* not in-sync with kernel */ + bool resync : 1; /* re-syncing with kernel */ ++ bool running : 1; + }; + + struct unmanaged_evdev { +@@ -268,6 +269,12 @@ static void idev_evdev_enable(idev_evdev *evdev) { + assert(evdev->fd_src); + assert(evdev->idle_src); + ++ if (evdev->running) ++ return; ++ if (evdev->fd < 0 || evdev->element.n_open < 1 || !evdev->element.enabled) ++ return; ++ ++ evdev->running = true; + sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_ON); + sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_ONESHOT); + } +@@ -277,6 +284,10 @@ static void idev_evdev_disable(idev_evdev *evdev) { + assert(evdev->fd_src); + assert(evdev->idle_src); + ++ if (!evdev->running) ++ return; ++ ++ evdev->running = false; + sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); + sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); + } +@@ -288,9 +299,7 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { + + if (fd < 0 || evdev->fd == fd) { + fd = -1; +- if (evdev->fd >= 0 && e->n_open > 0 && e->enabled) +- idev_evdev_enable(evdev); +- ++ idev_evdev_enable(evdev); + return 0; + } + +@@ -351,15 +360,14 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { + return r; + } + +- if (e->n_open < 1 || !e->enabled) { +- sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); +- sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); +- } ++ sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); ++ sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); + + evdev->unsync = true; + evdev->fd = fd; +- + fd = -1; ++ ++ idev_evdev_enable(evdev); + return 0; + } + +@@ -371,12 +379,11 @@ static void idev_evdev_pause(idev_evdev *evdev, bool release) { + + log_debug("idev-evdev: %s/%s: pause", e->session->name, e->name); + ++ idev_evdev_disable(evdev); + if (release) { + evdev->idle_src = sd_event_source_unref(evdev->idle_src); + evdev->fd_src = sd_event_source_unref(evdev->fd_src); + evdev->fd = safe_close(evdev->fd); +- } else { +- idev_evdev_disable(evdev); + } + } + diff --git a/0351-terminal-forward-evdev-RESYNC-events-to-linked-devic.patch b/0351-terminal-forward-evdev-RESYNC-events-to-linked-devic.patch new file mode 100644 index 0000000..3280346 --- /dev/null +++ b/0351-terminal-forward-evdev-RESYNC-events-to-linked-devic.patch @@ -0,0 +1,76 @@ +From 89febb631a4710992cd41e402a643451b19c11a7 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 12:39:59 +0200 +Subject: [PATCH] terminal: forward evdev RESYNC events to linked devices + +Whenever we resync an evdev device (or disable it), we should send RESYNC +events to the linked upper layers. This allows to disable key-repeat and +assume some events got dropped. +--- + src/libsystemd-terminal/idev-evdev.c | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index 25ac849b8d..719e18c316 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -102,7 +102,16 @@ static void idev_evdev_name(char *out, dev_t devnum) { + sprintf(out, "evdev/%u:%u", major(devnum), minor(devnum)); + } + +-static int idev_evdev_raise(idev_evdev *evdev, struct input_event *event) { ++static int idev_evdev_feed_resync(idev_evdev *evdev) { ++ idev_data data = { ++ .type = IDEV_DATA_RESYNC, ++ .resync = evdev->resync, ++ }; ++ ++ return idev_element_feed(&evdev->element, &data); ++} ++ ++static int idev_evdev_feed_evdev(idev_evdev *evdev, struct input_event *event) { + idev_data data = { + .type = IDEV_DATA_EVDEV, + .resync = evdev->resync, +@@ -156,7 +165,6 @@ static int idev_evdev_io(idev_evdev *evdev) { + * case we cannot keep up with the kernel. + * TODO: Make sure libevdev always reports SYN_DROPPED to us, regardless + * whether any event was synced afterwards. +- * TODO: Forward SYN_DROPPED to attached devices. + */ + + flags = LIBEVDEV_READ_FLAG_NORMAL; +@@ -191,7 +199,7 @@ static int idev_evdev_io(idev_evdev *evdev) { + } else if (r == LIBEVDEV_READ_STATUS_SYNC) { + if (evdev->resync) { + /* sync-event */ +- r = idev_evdev_raise(evdev, &ev); ++ r = idev_evdev_feed_evdev(evdev, &ev); + if (r != 0) { + error = r; + break; +@@ -200,10 +208,15 @@ static int idev_evdev_io(idev_evdev *evdev) { + /* start of sync */ + evdev->resync = true; + flags = LIBEVDEV_READ_FLAG_SYNC; ++ r = idev_evdev_feed_resync(evdev); ++ if (r != 0) { ++ error = r; ++ break; ++ } + } + } else { + /* normal event */ +- r = idev_evdev_raise(evdev, &ev); ++ r = idev_evdev_feed_evdev(evdev, &ev); + if (r != 0) { + error = r; + break; +@@ -288,6 +301,7 @@ static void idev_evdev_disable(idev_evdev *evdev) { + return; + + evdev->running = false; ++ idev_evdev_feed_resync(evdev); + sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); + sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); + } diff --git a/0352-terminal-raise-sysview-DEVICE_CHANGE-events-per-atta.patch b/0352-terminal-raise-sysview-DEVICE_CHANGE-events-per-atta.patch new file mode 100644 index 0000000..c098d55 --- /dev/null +++ b/0352-terminal-raise-sysview-DEVICE_CHANGE-events-per-atta.patch @@ -0,0 +1,142 @@ +From f6e3ee1493f20823b2c33465458b92f3581af88d Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 17:47:56 +0200 +Subject: [PATCH] terminal: raise sysview DEVICE_CHANGE events per attachment + +Instead of raising DEVICE_CHANGE only per device, we now raise it per +device-session attachment. This is what we want for all sysview users, +anyway, as sessions are meant to be independent of each other. Lets avoid +any external session iterators and just do that in sysview itself. +--- + src/libsystemd-terminal/modeset.c | 14 +++++++------- + src/libsystemd-terminal/sysview.c | 34 ++++++++++++++++++++++++++++++---- + src/libsystemd-terminal/sysview.h | 14 +++++++------- + 3 files changed, 44 insertions(+), 18 deletions(-) + +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +index 33c79a2036..7a28e7ab97 100644 +--- a/src/libsystemd-terminal/modeset.c ++++ b/src/libsystemd-terminal/modeset.c +@@ -348,6 +348,13 @@ static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event + grdev_session_remove_drm(m->grdev_session, sysview_device_get_ud(d)); + + break; ++ case SYSVIEW_EVENT_SESSION_REFRESH: ++ d = ev->session_refresh.device; ++ type = sysview_device_get_type(d); ++ if (type == SYSVIEW_DEVICE_DRM) ++ grdev_session_hotplug_drm(m->grdev_session, ev->session_refresh.ud); ++ ++ break; + case SYSVIEW_EVENT_SESSION_CONTROL: + r = ev->session_control.error; + if (r < 0) { +@@ -362,13 +369,6 @@ static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event + } + + break; +- case SYSVIEW_EVENT_DEVICE_CHANGE: +- d = ev->device_change.device; +- type = sysview_device_get_type(d); +- if (type == SYSVIEW_DEVICE_DRM) +- grdev_session_hotplug_drm(m->grdev_session, ev->device_change.ud); +- +- break; + } + + return 0; +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 161ea117a4..5b623c1e6c 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -517,10 +517,11 @@ static int context_raise_session_detach(sysview_context *c, sysview_session *ses + return context_raise(c, &event, 0); + } + +-static int context_raise_device_change(sysview_context *c, sysview_device *device, struct udev_device *ud) { ++static int context_raise_session_refresh(sysview_context *c, sysview_session *session, sysview_device *device, struct udev_device *ud) { + sysview_event event = { +- .type = SYSVIEW_EVENT_DEVICE_CHANGE, +- .device_change = { ++ .type = SYSVIEW_EVENT_SESSION_REFRESH, ++ .session_refresh = { ++ .session = session, + .device = device, + .ud = ud, + } +@@ -581,6 +582,31 @@ static int context_remove_device(sysview_context *c, sysview_device *device) { + return error; + } + ++static int context_change_device(sysview_context *c, sysview_device *device, struct udev_device *ud) { ++ sysview_session *session; ++ int r, error = 0; ++ Iterator i; ++ ++ assert(c); ++ assert(device); ++ ++ log_debug("sysview: change device '%s'", device->name); ++ ++ HASHMAP_FOREACH(session, device->seat->session_map, i) { ++ if (!session->public) ++ continue; ++ ++ r = context_raise_session_refresh(c, session, device, ud); ++ if (r != 0) ++ error = r; ++ } ++ ++ if (error < 0) ++ log_debug("sysview: error while changing device '%s': %s", ++ device->name, strerror(-r)); ++ return error; ++} ++ + static int context_add_session(sysview_context *c, sysview_seat *seat, const char *id) { + sysview_session *session; + sysview_device *device; +@@ -884,7 +910,7 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { + if (!device) + return 0; + +- return context_raise_device_change(c, device, d); ++ return context_change_device(c, device, d); + } else if (!action || streq_ptr(action, "add")) { + struct udev_device *p; + unsigned int type, t; +diff --git a/src/libsystemd-terminal/sysview.h b/src/libsystemd-terminal/sysview.h +index b9452fab89..4d800f8d69 100644 +--- a/src/libsystemd-terminal/sysview.h ++++ b/src/libsystemd-terminal/sysview.h +@@ -63,9 +63,8 @@ enum { + SYSVIEW_EVENT_SESSION_REMOVE, + SYSVIEW_EVENT_SESSION_ATTACH, + SYSVIEW_EVENT_SESSION_DETACH, ++ SYSVIEW_EVENT_SESSION_REFRESH, + SYSVIEW_EVENT_SESSION_CONTROL, +- +- SYSVIEW_EVENT_DEVICE_CHANGE, + }; + + struct sysview_event { +@@ -94,13 +93,14 @@ struct sysview_event { + + struct { + sysview_session *session; +- int error; +- } session_control; +- +- struct { + sysview_device *device; + struct udev_device *ud; +- } device_change; ++ } session_refresh; ++ ++ struct { ++ sysview_session *session; ++ int error; ++ } session_control; + }; + }; + diff --git a/0353-test-util-make-valgrind-happy.patch b/0353-test-util-make-valgrind-happy.patch new file mode 100644 index 0000000..5b1145c --- /dev/null +++ b/0353-test-util-make-valgrind-happy.patch @@ -0,0 +1,62 @@ +From eee846339d2f76f568c62b3725bf75bcee728115 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 22 Sep 2014 11:27:22 +0200 +Subject: [PATCH] test-util: make valgrind happy + +Properly free all temporary resources to make valgrind not complain about +lost records. +--- + src/test/test-util.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 80425ca61a..f8e42f3a55 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -843,11 +843,27 @@ static void test_is_valid_documentation_url(void) { + } + + static void test_file_in_same_dir(void) { +- assert_se(streq(file_in_same_dir("/", "a"), "/a")); +- assert_se(streq(file_in_same_dir("/", "/a"), "/a")); +- assert_se(streq(file_in_same_dir("", "a"), "a")); +- assert_se(streq(file_in_same_dir("a/", "a"), "a/a")); +- assert_se(streq(file_in_same_dir("bar/foo", "bar"), "bar/bar")); ++ char *t; ++ ++ t = file_in_same_dir("/", "a"); ++ assert_se(streq(t, "/a")); ++ free(t); ++ ++ t = file_in_same_dir("/", "/a"); ++ assert_se(streq(t, "/a")); ++ free(t); ++ ++ t = file_in_same_dir("", "a"); ++ assert_se(streq(t, "a")); ++ free(t); ++ ++ t = file_in_same_dir("a/", "a"); ++ assert_se(streq(t, "a/a")); ++ free(t); ++ ++ t = file_in_same_dir("bar/foo", "bar"); ++ assert_se(streq(t, "bar/bar")); ++ free(t); + } + + static void test_endswith(void) { +@@ -1239,11 +1255,13 @@ static void test_unquote_many_words(void) { + assert_se(unquote_many_words(&p, &a, NULL) == 1); + assert_se(p == original+7); + assert_se(streq_ptr(a, "foobar")); ++ free(a); + + p = original = " foobar "; + assert_se(unquote_many_words(&p, &a, NULL) == 1); + assert_se(p == original+15); + assert_se(streq_ptr(a, "foobar")); ++ free(a); + } + + int main(int argc, char *argv[]) { diff --git a/0354-util-add-alloca_align.patch b/0354-util-add-alloca_align.patch new file mode 100644 index 0000000..80c2233 --- /dev/null +++ b/0354-util-add-alloca_align.patch @@ -0,0 +1,76 @@ +From 95d78c7e7c81a6b788f28c33ef2cafd87471a0d7 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 22 Sep 2014 12:05:16 +0200 +Subject: [PATCH] util: add alloca_align() + +The alloca_align() helper is the alloca() equivalent of posix_memalign(). +As there is no such function provided by glibc, we simply account for +additional memory and return a pointer offset into the allocated memory to +grant the alignment. + +Furthermore, alloca0_align() is added, which simply clears the allocated +memory. +--- + src/shared/util.h | 16 ++++++++++++++++ + src/test/test-util.c | 14 ++++++++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/src/shared/util.h b/src/shared/util.h +index 08d556fc92..a1d5657237 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -852,6 +852,22 @@ int unlink_noerrno(const char *path); + (void *) memset(_new_, 0, _len_); \ + }) + ++#define alloca_align(size, align) \ ++ ({ \ ++ void *_ptr_; \ ++ size_t _mask_ = (align) - 1; \ ++ _ptr_ = alloca((size) + _mask_); \ ++ (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ ++ }) ++ ++#define alloca0_align(size, align) \ ++ ({ \ ++ void *_new_; \ ++ size_t _size_ = (size); \ ++ _new_ = alloca_align(_size_, (align)); \ ++ (void*)memset(_new_, 0, _size_); \ ++ }) ++ + #define strappenda(a, ...) \ + ({ \ + int _len = strlen(a); \ +diff --git a/src/test/test-util.c b/src/test/test-util.c +index f8e42f3a55..1311184815 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -131,6 +131,19 @@ static void test_container_of(void) { + v1) == &myval); + } + ++static void test_alloca(void) { ++ static const uint8_t zero[997] = { }; ++ char *t; ++ ++ t = alloca_align(17, 512); ++ assert_se(!((uintptr_t)t & 0xff)); ++ memzero(t, 17); ++ ++ t = alloca0_align(997, 1024); ++ assert_se(!((uintptr_t)t & 0x1ff)); ++ assert_se(!memcmp(t, zero, 997)); ++} ++ + static void test_first_word(void) { + assert_se(first_word("Hello", "")); + assert_se(first_word("Hello", "Hello")); +@@ -1272,6 +1285,7 @@ int main(int argc, char *argv[]) { + test_align_power2(); + test_max(); + test_container_of(); ++ test_alloca(); + test_first_word(); + test_close_many(); + test_parse_boolean(); diff --git a/0355-bus-align-kdbus-ioctl-parameters-to-8byte.patch b/0355-bus-align-kdbus-ioctl-parameters-to-8byte.patch new file mode 100644 index 0000000..8c1ca1c --- /dev/null +++ b/0355-bus-align-kdbus-ioctl-parameters-to-8byte.patch @@ -0,0 +1,172 @@ +From 7f3d3ba1a61f28a951ca5fbe59ed15c7ce55219c Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 22 Sep 2014 12:49:47 +0200 +Subject: [PATCH] bus: align kdbus ioctl parameters to 8byte + +All kdbus ioctl arguments must be 8byte aligned. Make sure we use +alloca_align() and _alignas_(8) in all situations where gcc doesn't +guarantee 8-byte alignment. + +Note that objects on the stack are always 8byte aligned as we put +_alignas_(8) into the structure definition in kdbus.h. +--- + src/libsystemd/sd-bus/bus-control.c | 14 +++++++------- + src/libsystemd/sd-bus/bus-kernel.c | 26 ++++++++++++++------------ + src/libsystemd/sd-bus/bus-message.c | 2 +- + 3 files changed, 22 insertions(+), 20 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c +index ad372f6772..5ac48c081f 100644 +--- a/src/libsystemd/sd-bus/bus-control.c ++++ b/src/libsystemd/sd-bus/bus-control.c +@@ -60,7 +60,7 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags + + l = strlen(name); + size = offsetof(struct kdbus_cmd_name, name) + l + 1; +- n = alloca0(size); ++ n = alloca0_align(size, 8); + n->size = size; + kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags); + memcpy(n->name, name, l+1); +@@ -151,7 +151,7 @@ static int bus_release_name_kernel(sd_bus *bus, const char *name) { + assert(name); + + l = strlen(name); +- n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1); ++ n = alloca0_align(offsetof(struct kdbus_cmd_name, name) + l + 1, 8); + n->size = offsetof(struct kdbus_cmd_name, name) + l + 1; + memcpy(n->name, name, l+1); + +@@ -376,11 +376,11 @@ static int bus_get_owner_kdbus( + return r; + if (r > 0) { + size = offsetof(struct kdbus_cmd_conn_info, name); +- cmd = alloca0(size); ++ cmd = alloca0_align(size, 8); + cmd->id = id; + } else { + size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1; +- cmd = alloca0(size); ++ cmd = alloca0_align(size, 8); + strcpy(cmd->name, name); + } + +@@ -827,7 +827,7 @@ static int add_name_change_match(sd_bus *bus, + offsetof(struct kdbus_notify_name_change, name) + + l); + +- m = alloca0(sz); ++ m = alloca0_align(sz, 8); + m->size = sz; + m->cookie = cookie; + +@@ -887,7 +887,7 @@ static int add_name_change_match(sd_bus *bus, + offsetof(struct kdbus_item, id_change) + + sizeof(struct kdbus_notify_id_change)); + +- m = alloca0(sz); ++ m = alloca0_align(sz, 8); + m->size = sz; + m->cookie = cookie; + +@@ -1057,7 +1057,7 @@ int bus_add_match_internal_kernel( + if (using_bloom) + sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size); + +- m = alloca0(sz); ++ m = alloca0_align(sz, 8); + m->size = sz; + m->cookie = cookie; + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index b3cc996b1e..c30491e687 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -709,7 +709,7 @@ int bus_kernel_take_fd(sd_bus *b) { + sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1); + } + +- hello = alloca0(sz); ++ hello = alloca0_align(sz, 8); + hello->size = sz; + hello->conn_flags = b->hello_flags; + hello->attach_flags = b->attach_flags; +@@ -796,7 +796,7 @@ int bus_kernel_connect(sd_bus *b) { + } + + static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { +- uint64_t off; ++ uint64_t off _alignas_(8); + struct kdbus_item *d; + + assert(bus); +@@ -1268,10 +1268,11 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) { + if (fd < 0) + return -errno; + +- make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) + +- offsetof(struct kdbus_item, data64) + sizeof(uint64_t) + +- offsetof(struct kdbus_item, str) + +- DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1)); ++ make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd_make, items) + ++ offsetof(struct kdbus_item, data64) + sizeof(uint64_t) + ++ offsetof(struct kdbus_item, str) + ++ DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1), ++ 8); + + make->size = offsetof(struct kdbus_cmd_make, items); + +@@ -1423,7 +1424,7 @@ int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char * + size = ALIGN8(offsetof(struct kdbus_cmd_make, items)); + size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(ep_name) + 1); + +- make = alloca0(size); ++ make = alloca0_align(size, 8); + make->size = size; + make->flags = KDBUS_MAKE_ACCESS_WORLD; + +@@ -1472,7 +1473,7 @@ int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) { + size += ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access)); + } + +- update = alloca0(size); ++ update = alloca0_align(size, 8); + update->size = size; + + n = update->items; +@@ -1528,7 +1529,7 @@ int bus_kernel_make_starter( + ALIGN8(offsetof(struct kdbus_item, str) + strlen(name) + 1) + + policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access)); + +- hello = alloca0(size); ++ hello = alloca0_align(size, 8); + + n = hello->items; + strcpy(n->str, name); +@@ -1588,9 +1589,10 @@ int bus_kernel_create_domain(const char *name, char **s) { + if (fd < 0) + return -errno; + +- make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) + +- offsetof(struct kdbus_item, str) + +- strlen(name) + 1)); ++ make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd_make, items) + ++ offsetof(struct kdbus_item, str) + ++ strlen(name) + 1), ++ 8); + + n = make->items; + strcpy(n->str, name); +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index 1fa3ad2611..400ba307bc 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -128,7 +128,7 @@ static void message_free(sd_bus_message *m) { + message_reset_parts(m); + + if (m->release_kdbus) { +- uint64_t off; ++ uint64_t off _alignas_(8); + + off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer; + ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off); diff --git a/0356-login-add-public-sd_session_get_desktop-API.patch b/0356-login-add-public-sd_session_get_desktop-API.patch new file mode 100644 index 0000000..523c93d --- /dev/null +++ b/0356-login-add-public-sd_session_get_desktop-API.patch @@ -0,0 +1,146 @@ +From c72d5456e2d6a6c8cefbfc16a542ae03a769397f Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sat, 20 Sep 2014 18:42:29 +0200 +Subject: [PATCH] login: add public sd_session_get_desktop() API + +The desktop brand is stored as DESKTOP variable for sessions. It can be +set arbitrarily by the session owner and identifies the desktop +environment that is running on that session. +--- + man/pam_systemd.xml | 4 +++- + man/sd_session_is_active.xml | 23 +++++++++++++++++++++++ + src/libsystemd/libsystemd.sym.m4 | 7 ++++++- + src/libsystemd/sd-login/sd-login.c | 19 +++++++++++++++++++ + src/systemd/sd-login.h | 3 +++ + 5 files changed, 54 insertions(+), 2 deletions(-) + +diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml +index 52dfe9df43..4df26a3f2b 100644 +--- a/man/pam_systemd.xml ++++ b/man/pam_systemd.xml +@@ -268,7 +268,9 @@ + as defined by the Desktop + Entry +- Specification. ++ Specification. See ++ sd_session_get_desktop3 ++ for more details. + + + +diff --git a/man/sd_session_is_active.xml b/man/sd_session_is_active.xml +index 5006be4df5..e9840669c2 100644 +--- a/man/sd_session_is_active.xml ++++ b/man/sd_session_is_active.xml +@@ -51,6 +51,7 @@ + sd_session_get_service + sd_session_get_type + sd_session_get_class ++ sd_session_get_desktop + sd_session_get_display + sd_session_get_tty + sd_session_get_vt +@@ -110,6 +111,12 @@ + + + ++ int sd_session_get_desktop ++ const char *session ++ char **desktop ++ ++ ++ + int sd_session_get_display + const char *session + char **display +@@ -218,6 +225,22 @@ + free3 + call after use. + ++ sd_session_get_desktop() may ++ be used to determine the brand of the desktop running on ++ the session identified by the specified session identifier. ++ This field can be set freely by desktop environments and ++ does not follow any special formatting. However, desktops ++ are strongly recommended to use the same identifiers and ++ capitalization as for ++ $XDG_CURRENT_DESKTOP, as defined by ++ the Desktop ++ Entry ++ Specification. The returned string needs to be ++ freed with the libc ++ free3 ++ call after use. ++ + sd_session_get_display() + may be used to determine the X11 display of the + session identified by the specified session +diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 +index d1450fbb26..87da7ac021 100644 +--- a/src/libsystemd/libsystemd.sym.m4 ++++ b/src/libsystemd/libsystemd.sym.m4 +@@ -153,6 +153,11 @@ global: + sd_machine_get_ifindices; + } LIBSYSTEMD_214; + ++LIBSYSTEMD_217 { ++global: ++ sd_session_get_desktop; ++} LIBSYSTEMD_216; ++ + m4_ifdef(`ENABLE_KDBUS', + LIBSYSTEMD_FUTURE { + global: +@@ -438,5 +443,5 @@ global: + /* sd-path */ + sd_path_home; + sd_path_search; +-} LIBSYSTEMD_216; ++} LIBSYSTEMD_217; + ) +diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c +index 95cb6ff581..c72d23ed53 100644 +--- a/src/libsystemd/sd-login/sd-login.c ++++ b/src/libsystemd/sd-login/sd-login.c +@@ -485,6 +485,25 @@ _public_ int sd_session_get_class(const char *session, char **class) { + return session_get_string(session, "CLASS", class); + } + ++_public_ int sd_session_get_desktop(const char *session, char **desktop) { ++ _cleanup_free_ char *escaped = NULL; ++ char *t; ++ int r; ++ ++ assert_return(desktop, -EINVAL); ++ ++ r = session_get_string(session, "DESKTOP", &escaped); ++ if (r < 0) ++ return r; ++ ++ t = cunescape(escaped); ++ if (!t) ++ return -ENOMEM; ++ ++ *desktop = t; ++ return 0; ++} ++ + _public_ int sd_session_get_display(const char *session, char **display) { + return session_get_string(session, "DISPLAY", display); + } +diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h +index 1eb3be30b5..93af19709b 100644 +--- a/src/systemd/sd-login.h ++++ b/src/systemd/sd-login.h +@@ -147,6 +147,9 @@ int sd_session_get_type(const char *session, char **type); + /* Determine the class of this session, i.e. one of "user", "greeter" or "lock-screen". */ + int sd_session_get_class(const char *session, char **clazz); + ++/* Determine the desktop brand of this session, i.e. something like "GNOME", "KDE" or "SYSTEMD-CONSOLE". */ ++int sd_session_get_desktop(const char *session, char **desktop); ++ + /* Determine the X11 display of this session. */ + int sd_session_get_display(const char *session, char **display); + diff --git a/0357-man-fix-typo-and-add-link.patch b/0357-man-fix-typo-and-add-link.patch new file mode 100644 index 0000000..2c9d7db --- /dev/null +++ b/0357-man-fix-typo-and-add-link.patch @@ -0,0 +1,32 @@ +From 9c77924c29874aa4684c2a9e1a7b9ee547d49d85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Sep 2014 09:13:38 -0400 +Subject: [PATCH] man: fix typo and add link + +--- + man/systemd.service.xml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index a82dfb2c86..b9a2f8d82f 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -310,7 +310,8 @@ + + BusPolicy= + +- If specfied, a custom kdbus ++ If specified, a custom ++ kdbus + endpoint will be created and installed as the + default bus node for the service. Such a custom + endpoint can hold an own set of policy rules +@@ -330,7 +331,7 @@ + of two parts; the bus name, and a verb to + specify to granted access, which is one of + , +- or ++ , or + . + implies + , and diff --git a/0358-exit-status.c-bring-EXIT_BUS_ENDPOINT-label-in-line-.patch b/0358-exit-status.c-bring-EXIT_BUS_ENDPOINT-label-in-line-.patch new file mode 100644 index 0000000..02ac072 --- /dev/null +++ b/0358-exit-status.c-bring-EXIT_BUS_ENDPOINT-label-in-line-.patch @@ -0,0 +1,23 @@ +From ffb6c43e7985e837ae50f8831b98c9941c406969 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Sep 2014 09:15:49 -0400 +Subject: [PATCH] exit-status.c: bring EXIT_BUS_ENDPOINT label in line with + others + +--- + 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 b036ded1f4..5c73b4d3c0 100644 +--- a/src/shared/exit-status.c ++++ b/src/shared/exit-status.c +@@ -150,7 +150,7 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { + return "MAKE_STARTER"; + + case EXIT_BUS_ENDPOINT: +- return "EXIT_BUS_ENDPOINT"; ++ return "BUS_ENDPOINT"; + } + } + diff --git a/0359-terminal-make-evdev-logind-matches-per-session.patch b/0359-terminal-make-evdev-logind-matches-per-session.patch new file mode 100644 index 0000000..e264c4a --- /dev/null +++ b/0359-terminal-make-evdev-logind-matches-per-session.patch @@ -0,0 +1,433 @@ +From 5d301b8aecc286d6ec7e92b0864d66360ea57205 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 22 Sep 2014 17:34:13 +0200 +Subject: [PATCH] terminal: make evdev logind-matches per session + +Instead of adding matches per device, we now add logind matches per +session. This reduces the number of matches considerably and saves +resources. +--- + src/libsystemd-terminal/idev-evdev.c | 170 ++++++++------------------------ + src/libsystemd-terminal/idev-internal.h | 4 + + src/libsystemd-terminal/idev.c | 114 +++++++++++++++++++++ + 3 files changed, 158 insertions(+), 130 deletions(-) + +diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c +index 719e18c316..63fa89e47d 100644 +--- a/src/libsystemd-terminal/idev-evdev.c ++++ b/src/libsystemd-terminal/idev-evdev.c +@@ -60,9 +60,6 @@ struct unmanaged_evdev { + struct managed_evdev { + idev_evdev evdev; + dev_t devnum; +- +- sd_bus_slot *slot_pause_device; +- sd_bus_slot *slot_resume_device; + sd_bus_slot *slot_take_device; + + bool requested : 1; /* TakeDevice() was sent */ +@@ -580,7 +577,7 @@ static int managed_evdev_take_device_fn(sd_bus *bus, + return 0; + } + +-static void managed_evdev_resume(idev_element *e) { ++static void managed_evdev_enable(idev_element *e) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + managed_evdev *em = managed_evdev_from_element(e); + idev_session *s = e->session; +@@ -628,7 +625,7 @@ error: + s->name, e->name, strerror(-r)); + } + +-static void managed_evdev_pause(idev_element *e) { ++static void managed_evdev_disable(idev_element *e) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + managed_evdev *em = managed_evdev_from_element(e); + idev_session *s = e->session; +@@ -686,24 +683,45 @@ static void managed_evdev_pause(idev_element *e) { + s->name, e->name, strerror(-r)); + } + +-static int managed_evdev_pause_device_fn(sd_bus *bus, +- sd_bus_message *signal, +- void *userdata, +- sd_bus_error *ret_error) { +- managed_evdev *em = userdata; +- idev_element *e = &em->evdev.element; ++static void managed_evdev_resume(idev_element *e, int fd) { ++ managed_evdev *em = managed_evdev_from_element(e); ++ idev_session *s = e->session; ++ int r; ++ ++ /* ++ * We get ResumeDevice signals whenever logind resumed a previously ++ * paused device. The arguments contain the major/minor number of the ++ * related device and a new file-descriptor for the freshly opened ++ * device-node. We take the file-descriptor and immediately resume the ++ * device. ++ */ ++ ++ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); ++ if (fd < 0) { ++ log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m", ++ s->name, e->name); ++ return; ++ } ++ ++ r = idev_evdev_resume(&em->evdev, fd); ++ if (r < 0) ++ log_debug("idev-evdev: %s/%s: cannot resume: %s", ++ s->name, e->name, strerror(-r)); ++ ++ return; ++} ++ ++static void managed_evdev_pause(idev_element *e, const char *mode) { ++ managed_evdev *em = managed_evdev_from_element(e); + idev_session *s = e->session; + idev_context *c = s->context; +- uint32_t major, minor; +- const char *mode; + int r; + + /* + * We get PauseDevice() signals from logind whenever a device we + * requested was, or is about to be, paused. Arguments are major/minor + * number of the device and the mode of the operation. +- * In case the event is not about our device, we ignore it. Otherwise, +- * we treat it as asynchronous access-revocation (as if we got HUP on ++ * We treat it as asynchronous access-revocation (as if we got HUP on + * the device fd). Note that we might have already treated the HUP + * event via EPOLLHUP, whichever comes first. + * +@@ -728,17 +746,6 @@ static int managed_evdev_pause_device_fn(sd_bus *bus, + * acknowledge the request. + */ + +- r = sd_bus_message_read(signal, "uus", &major, &minor, &mode); +- if (r < 0) { +- log_debug("idev-evdev: %s/%s: erroneous PauseDevice signal", +- s->name, e->name); +- return 0; +- } +- +- /* not our device? */ +- if (makedev(major, minor) != em->devnum) +- return 0; +- + idev_evdev_pause(&em->evdev, true); + + if (streq(mode, "pause")) { +@@ -763,7 +770,7 @@ static int managed_evdev_pause_device_fn(sd_bus *bus, + "org.freedesktop.login1.Session", + "PauseDeviceComplete"); + if (r >= 0) { +- r = sd_bus_message_append(m, "uu", major, minor); ++ r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum)); + if (r >= 0) + r = sd_bus_send(c->sysbus, m, NULL); + } +@@ -772,99 +779,6 @@ static int managed_evdev_pause_device_fn(sd_bus *bus, + log_debug("idev-evdev: %s/%s: cannot send PauseDeviceComplete: %s", + s->name, e->name, strerror(-r)); + } +- +- return 0; +-} +- +-static int managed_evdev_resume_device_fn(sd_bus *bus, +- sd_bus_message *signal, +- void *userdata, +- sd_bus_error *ret_error) { +- managed_evdev *em = userdata; +- idev_element *e = &em->evdev.element; +- idev_session *s = e->session; +- uint32_t major, minor; +- int r, fd; +- +- /* +- * We get ResumeDevice signals whenever logind resumed a previously +- * paused device. The arguments contain the major/minor number of the +- * related device and a new file-descriptor for the freshly opened +- * device-node. +- * If the signal is not about our device, we simply ignore it. +- * Otherwise, we take the file-descriptor and immediately resume the +- * device. +- */ +- +- r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd); +- if (r < 0) { +- log_debug("idev-evdev: %s/%s: erroneous ResumeDevice signal", +- s->name, e->name); +- return 0; +- } +- +- /* not our device? */ +- if (makedev(major, minor) != em->devnum) +- return 0; +- +- fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); +- if (fd < 0) { +- log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m", +- s->name, e->name); +- return 0; +- } +- +- r = idev_evdev_resume(&em->evdev, fd); +- if (r < 0) +- log_debug("idev-evdev: %s/%s: cannot resume: %s", +- s->name, e->name, strerror(-r)); +- +- return 0; +-} +- +-static int managed_evdev_setup_bus(managed_evdev *em) { +- idev_element *e = &em->evdev.element; +- idev_session *s = e->session; +- idev_context *c = s->context; +- _cleanup_free_ char *match = NULL; +- int r; +- +- match = strjoin("type='signal'," +- "sender='org.freedesktop.login1'," +- "interface='org.freedesktop.login1.Session'," +- "member='PauseDevice'," +- "path='", s->path, "'", +- NULL); +- if (!match) +- return -ENOMEM; +- +- r = sd_bus_add_match(c->sysbus, +- &em->slot_pause_device, +- match, +- managed_evdev_pause_device_fn, +- em); +- if (r < 0) +- return r; +- +- free(match); +- match = strjoin("type='signal'," +- "sender='org.freedesktop.login1'," +- "interface='org.freedesktop.login1.Session'," +- "member='ResumeDevice'," +- "path='", s->path, "'", +- NULL); +- if (!match) +- return -ENOMEM; +- +- r = sd_bus_add_match(c->sysbus, +- &em->slot_resume_device, +- match, +- managed_evdev_resume_device_fn, +- em); +- if (r < 0) +- return r; +- +- return 0; + } + + static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) { +@@ -893,10 +807,6 @@ static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_de + em->evdev = IDEV_EVDEV_INIT(&managed_evdev_vtable, s); + em->devnum = devnum; + +- r = managed_evdev_setup_bus(em); +- if (r < 0) +- return r; +- + r = idev_element_add(e, name); + if (r < 0) + return r; +@@ -910,18 +820,18 @@ static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_de + static void managed_evdev_free(idev_element *e) { + managed_evdev *em = managed_evdev_from_element(e); + +- em->slot_resume_device = sd_bus_slot_unref(em->slot_resume_device); +- em->slot_pause_device = sd_bus_slot_unref(em->slot_pause_device); + idev_evdev_destroy(&em->evdev); + free(em); + } + + static const idev_element_vtable managed_evdev_vtable = { + .free = managed_evdev_free, +- .enable = managed_evdev_resume, +- .disable = managed_evdev_pause, +- .open = managed_evdev_resume, +- .close = managed_evdev_pause, ++ .enable = managed_evdev_enable, ++ .disable = managed_evdev_disable, ++ .open = managed_evdev_enable, ++ .close = managed_evdev_disable, ++ .resume = managed_evdev_resume, ++ .pause = managed_evdev_pause, + }; + + /* +diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h +index c416f4fadd..a159aef211 100644 +--- a/src/libsystemd-terminal/idev-internal.h ++++ b/src/libsystemd-terminal/idev-internal.h +@@ -116,6 +116,8 @@ struct idev_element_vtable { + void (*disable) (idev_element *e); + void (*open) (idev_element *e); + void (*close) (idev_element *e); ++ void (*resume) (idev_element *e, int fd); ++ void (*pause) (idev_element *e, const char *mode); + void (*feedback) (idev_element *e, idev_data *data); + }; + +@@ -155,6 +157,8 @@ struct idev_session { + idev_context *context; + char *name; + char *path; ++ sd_bus_slot *slot_resume_device; ++ sd_bus_slot *slot_pause_device; + + Hashmap *element_map; + Hashmap *device_map; +diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c +index 8592930662..e979b608b6 100644 +--- a/src/libsystemd-terminal/idev.c ++++ b/src/libsystemd-terminal/idev.c +@@ -274,6 +274,22 @@ static void element_disable(idev_element *e) { + } + } + ++static void element_resume(idev_element *e, int fd) { ++ assert(e); ++ assert(fd >= 0); ++ ++ if (e->vtable->resume) ++ e->vtable->resume(e, fd); ++} ++ ++static void element_pause(idev_element *e, const char *mode) { ++ assert(e); ++ assert(mode); ++ ++ if (e->vtable->pause) ++ e->vtable->pause(e, mode); ++} ++ + /* + * Sessions + */ +@@ -417,6 +433,98 @@ idev_session *idev_find_session(idev_context *c, const char *name) { + return hashmap_get(c->session_map, name); + } + ++static int session_resume_device_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ idev_session *s = userdata; ++ idev_element *e; ++ uint32_t major, minor; ++ int r, fd; ++ ++ r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd); ++ if (r < 0) { ++ log_debug("idev: %s: erroneous ResumeDevice signal", s->name); ++ return 0; ++ } ++ ++ e = idev_find_evdev(s, makedev(major, minor)); ++ if (!e) ++ return 0; ++ ++ element_resume(e, fd); ++ return 0; ++} ++ ++static int session_pause_device_fn(sd_bus *bus, ++ sd_bus_message *signal, ++ void *userdata, ++ sd_bus_error *ret_error) { ++ idev_session *s = userdata; ++ idev_element *e; ++ uint32_t major, minor; ++ const char *mode; ++ int r; ++ ++ r = sd_bus_message_read(signal, "uus", &major, &minor, &mode); ++ if (r < 0) { ++ log_debug("idev: %s: erroneous PauseDevice signal", s->name); ++ return 0; ++ } ++ ++ e = idev_find_evdev(s, makedev(major, minor)); ++ if (!e) ++ return 0; ++ ++ element_pause(e, mode); ++ return 0; ++} ++ ++static int session_setup_bus(idev_session *s) { ++ _cleanup_free_ char *match = NULL; ++ int r; ++ ++ if (!s->managed) ++ return 0; ++ ++ match = strjoin("type='signal'," ++ "sender='org.freedesktop.login1'," ++ "interface='org.freedesktop.login1.Session'," ++ "member='ResumeDevice'," ++ "path='", s->path, "'", ++ NULL); ++ if (!match) ++ return -ENOMEM; ++ ++ r = sd_bus_add_match(s->context->sysbus, ++ &s->slot_resume_device, ++ match, ++ session_resume_device_fn, ++ s); ++ if (r < 0) ++ return r; ++ ++ free(match); ++ match = strjoin("type='signal'," ++ "sender='org.freedesktop.login1'," ++ "interface='org.freedesktop.login1.Session'," ++ "member='PauseDevice'," ++ "path='", s->path, "'", ++ NULL); ++ if (!match) ++ return -ENOMEM; ++ ++ r = sd_bus_add_match(s->context->sysbus, ++ &s->slot_pause_device, ++ match, ++ session_pause_device_fn, ++ s); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ + int idev_session_new(idev_session **out, + idev_context *c, + unsigned int flags, +@@ -462,6 +570,10 @@ int idev_session_new(idev_session **out, + if (!s->device_map) + return -ENOMEM; + ++ r = session_setup_bus(s); ++ if (r < 0) ++ return r; ++ + r = hashmap_put(c->session_map, s->name, s); + if (r < 0) + return r; +@@ -485,6 +597,8 @@ idev_session *idev_session_free(idev_session *s) { + if (s->name) + hashmap_remove_value(s->context->session_map, s->name, s); + ++ s->slot_pause_device = sd_bus_slot_unref(s->slot_pause_device); ++ s->slot_resume_device = sd_bus_slot_unref(s->slot_resume_device); + s->context = idev_context_unref(s->context); + hashmap_free(s->device_map); + hashmap_free(s->element_map); diff --git a/0360-terminal-allow-user-context-to-be-retrieved-stored.patch b/0360-terminal-allow-user-context-to-be-retrieved-stored.patch new file mode 100644 index 0000000..e5969b7 --- /dev/null +++ b/0360-terminal-allow-user-context-to-be-retrieved-stored.patch @@ -0,0 +1,146 @@ +From f2a15d86ccd0729e1442f40679cd393417e1e177 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 22 Sep 2014 17:37:21 +0200 +Subject: [PATCH] terminal: allow user-context to be retrieved/stored + +Add "userdata" storage to a bunch of external objects, namely displays and +sessions. Furthermore, add some property retrieval helpers. + +This is required if we want external API users to not duplicate our own +object hashtables, but retrieve context from the objects themselves. +--- + src/libsystemd-terminal/grdev-internal.h | 1 + + src/libsystemd-terminal/grdev.c | 18 ++++++++++++++++++ + src/libsystemd-terminal/grdev.h | 5 +++++ + src/libsystemd-terminal/sysview-internal.h | 1 + + src/libsystemd-terminal/sysview.c | 18 ++++++++++++++++++ + src/libsystemd-terminal/sysview.h | 4 ++++ + 6 files changed, 47 insertions(+) + +diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h +index f5915b16e8..ee182695ce 100644 +--- a/src/libsystemd-terminal/grdev-internal.h ++++ b/src/libsystemd-terminal/grdev-internal.h +@@ -94,6 +94,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_tile*, grdev_tile_free); + struct grdev_display { + grdev_session *session; + char *name; ++ void *userdata; + + size_t n_leafs; + grdev_tile *tile; +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index 43d0c7c9bf..e34112ee7c 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -282,6 +282,24 @@ grdev_display *grdev_display_free(grdev_display *display) { + return NULL; + } + ++void grdev_display_set_userdata(grdev_display *display, void *userdata) { ++ assert(display); ++ ++ display->userdata = userdata; ++} ++ ++void *grdev_display_get_userdata(grdev_display *display) { ++ assert_return(display, NULL); ++ ++ return display->userdata; ++} ++ ++const char *grdev_display_get_name(grdev_display *display) { ++ assert_return(display, NULL); ++ ++ return display->name; ++} ++ + bool grdev_display_is_enabled(grdev_display *display) { + return display && display->enabled; + } +diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h +index 9924a257b6..5f745aaad4 100644 +--- a/src/libsystemd-terminal/grdev.h ++++ b/src/libsystemd-terminal/grdev.h +@@ -108,6 +108,11 @@ struct grdev_display_target { + const grdev_fb *fb; + }; + ++void grdev_display_set_userdata(grdev_display *display, void *userdata); ++void *grdev_display_get_userdata(grdev_display *display); ++ ++const char *grdev_display_get_name(grdev_display *display); ++ + bool grdev_display_is_enabled(grdev_display *display); + void grdev_display_enable(grdev_display *display); + void grdev_display_disable(grdev_display *display); +diff --git a/src/libsystemd-terminal/sysview-internal.h b/src/libsystemd-terminal/sysview-internal.h +index 9299fabb82..d9f7fe3301 100644 +--- a/src/libsystemd-terminal/sysview-internal.h ++++ b/src/libsystemd-terminal/sysview-internal.h +@@ -64,6 +64,7 @@ struct sysview_session { + sysview_seat *seat; + char *name; + char *path; ++ void *userdata; + + sd_bus_slot *slot_take_control; + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 5b623c1e6c..208c6ce25c 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -104,6 +104,12 @@ sysview_device *sysview_device_free(sysview_device *device) { + return NULL; + } + ++const char *sysview_device_get_name(sysview_device *device) { ++ assert_return(device, NULL); ++ ++ return device->name; ++} ++ + unsigned int sysview_device_get_type(sysview_device *device) { + assert_return(device, (unsigned)-1); + +@@ -243,6 +249,18 @@ sysview_session *sysview_session_free(sysview_session *session) { + return NULL; + } + ++void sysview_session_set_userdata(sysview_session *session, void *userdata) { ++ assert(session); ++ ++ session->userdata = userdata; ++} ++ ++void *sysview_session_get_userdata(sysview_session *session) { ++ assert_return(session, NULL); ++ ++ return session->userdata; ++} ++ + const char *sysview_session_get_name(sysview_session *session) { + assert_return(session, NULL); + +diff --git a/src/libsystemd-terminal/sysview.h b/src/libsystemd-terminal/sysview.h +index 4d800f8d69..f691e492d5 100644 +--- a/src/libsystemd-terminal/sysview.h ++++ b/src/libsystemd-terminal/sysview.h +@@ -116,6 +116,7 @@ enum { + SYSVIEW_DEVICE_CNT + }; + ++const char *sysview_device_get_name(sysview_device *device); + unsigned int sysview_device_get_type(sysview_device *device); + struct udev_device *sysview_device_get_ud(sysview_device *device); + +@@ -123,6 +124,9 @@ struct udev_device *sysview_device_get_ud(sysview_device *device); + * Sessions + */ + ++void sysview_session_set_userdata(sysview_session *session, void *userdata); ++void *sysview_session_get_userdata(sysview_session *session); ++ + const char *sysview_session_get_name(sysview_session *session); + + int sysview_session_take_control(sysview_session *session); diff --git a/0361-terminal-handle-callback-errors-in-sysview-instead-o.patch b/0361-terminal-handle-callback-errors-in-sysview-instead-o.patch new file mode 100644 index 0000000..7b17d29 --- /dev/null +++ b/0361-terminal-handle-callback-errors-in-sysview-instead-o.patch @@ -0,0 +1,410 @@ +From ed3a9f6a30958ef90a24bc60aec86493974101d3 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 22 Sep 2014 17:55:31 +0200 +Subject: [PATCH] terminal: handle callback errors in sysview instead of + propagating them + +We cannot sanely propagate error codes if we call into user-callbacks +multiple times for multiple objects. There is no way to merge those errors +or somehow propagate them. + +However, we can just act similar to sd-event and print a log-message while +discarding the values. This way, we allow error-returns, but can properly +continue working on our objects. +--- + src/libsystemd-terminal/sysview.c | 175 +++++++++++++++++--------------------- + 1 file changed, 76 insertions(+), 99 deletions(-) + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 208c6ce25c..969514ad9d 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -272,7 +272,7 @@ static int session_take_control_fn(sd_bus *bus, + void *userdata, + sd_bus_error *ret_error) { + sysview_session *session = userdata; +- int error; ++ int r, error; + + session->slot_take_control = sd_bus_slot_unref(session->slot_take_control); + +@@ -287,7 +287,12 @@ static int session_take_control_fn(sd_bus *bus, + error = 0; + } + +- return context_raise_session_control(session->seat->context, session, error); ++ r = context_raise_session_control(session->seat->context, session, error); ++ if (r < 0) ++ log_debug("sysview: callback failed while signalling session control '%d' on session '%s': %s", ++ error, session->name, strerror(-r)); ++ ++ return 0; + } + + int sysview_session_take_control(sysview_session *session) { +@@ -548,10 +553,10 @@ static int context_raise_session_refresh(sysview_context *c, sysview_session *se + return context_raise(c, &event, 0); + } + +-static int context_add_device(sysview_context *c, sysview_device *device) { ++static void context_add_device(sysview_context *c, sysview_device *device) { + sysview_session *session; +- int r, error = 0; + Iterator i; ++ int r; + + assert(c); + assert(device); +@@ -564,20 +569,16 @@ static int context_add_device(sysview_context *c, sysview_device *device) { + continue; + + r = context_raise_session_attach(c, session, device); +- if (r != 0) +- error = r; ++ if (r < 0) ++ log_debug("sysview: callback failed while attaching device '%s' to session '%s': %s", ++ device->name, session->name, strerror(-r)); + } +- +- if (error < 0) +- log_debug("sysview: error while adding device '%s': %s", +- device->name, strerror(-r)); +- return error; + } + +-static int context_remove_device(sysview_context *c, sysview_device *device) { ++static void context_remove_device(sysview_context *c, sysview_device *device) { + sysview_session *session; +- int r, error = 0; + Iterator i; ++ int r; + + assert(c); + assert(device); +@@ -589,21 +590,18 @@ static int context_remove_device(sysview_context *c, sysview_device *device) { + continue; + + r = context_raise_session_detach(c, session, device); +- if (r != 0) +- error = r; ++ if (r < 0) ++ log_debug("sysview: callback failed while detaching device '%s' from session '%s': %s", ++ device->name, session->name, strerror(-r)); + } + +- if (error < 0) +- log_debug("sysview: error while removing device '%s': %s", +- device->name, strerror(-r)); + sysview_device_free(device); +- return error; + } + +-static int context_change_device(sysview_context *c, sysview_device *device, struct udev_device *ud) { ++static void context_change_device(sysview_context *c, sysview_device *device, struct udev_device *ud) { + sysview_session *session; +- int r, error = 0; + Iterator i; ++ int r; + + assert(c); + assert(device); +@@ -615,21 +613,17 @@ static int context_change_device(sysview_context *c, sysview_device *device, str + continue; + + r = context_raise_session_refresh(c, session, device, ud); +- if (r != 0) +- error = r; ++ if (r < 0) ++ log_debug("sysview: callback failed while changing device '%s' on session '%s': %s", ++ device->name, session->name, strerror(-r)); + } +- +- if (error < 0) +- log_debug("sysview: error while changing device '%s': %s", +- device->name, strerror(-r)); +- return error; + } + +-static int context_add_session(sysview_context *c, sysview_seat *seat, const char *id) { ++static void context_add_session(sysview_context *c, sysview_seat *seat, const char *id) { + sysview_session *session; + sysview_device *device; +- int r, error = 0; + Iterator i; ++ int r; + + assert(c); + assert(seat); +@@ -637,7 +631,7 @@ static int context_add_session(sysview_context *c, sysview_seat *seat, const cha + + session = sysview_find_session(c, id); + if (session) +- return 0; ++ return; + + log_debug("sysview: add session '%s' on seat '%s'", id, seat->name); + +@@ -654,35 +648,33 @@ static int context_add_session(sysview_context *c, sysview_seat *seat, const cha + if (seat->public) { + session->public = true; + r = context_raise_session_add(c, session); +- if (r != 0) { ++ if (r < 0) { ++ log_debug("sysview: callback failed while adding session '%s': %s", ++ session->name, strerror(-r)); + session->public = false; + goto error; + } + + HASHMAP_FOREACH(device, seat->device_map, i) { + r = context_raise_session_attach(c, session, device); +- if (r != 0) +- error = r; ++ if (r < 0) ++ log_debug("sysview: callback failed while attaching device '%s' to new session '%s': %s", ++ device->name, session->name, strerror(-r)); + } +- +- r = error; +- if (r != 0) +- goto error; + } + +- return 0; ++ return; + + error: + if (r < 0) + log_debug("sysview: error while adding session '%s': %s", + id, strerror(-r)); +- return r; + } + +-static int context_remove_session(sysview_context *c, sysview_session *session) { ++static void context_remove_session(sysview_context *c, sysview_session *session) { + sysview_device *device; +- int r, error = 0; + Iterator i; ++ int r; + + assert(c); + assert(session); +@@ -692,27 +684,25 @@ static int context_remove_session(sysview_context *c, sysview_session *session) + if (session->public) { + HASHMAP_FOREACH(device, session->seat->device_map, i) { + r = context_raise_session_detach(c, session, device); +- if (r != 0) +- error = r; ++ if (r < 0) ++ log_debug("sysview: callback failed while detaching device '%s' from old session '%s': %s", ++ device->name, session->name, strerror(-r)); + } + + session->public = false; + r = context_raise_session_remove(c, session); +- if (r != 0) +- error = r; ++ if (r < 0) ++ log_debug("sysview: callback failed while removing session '%s': %s", ++ session->name, strerror(-r)); + } + + if (!session->custom) + sysview_session_release_control(session); + +- if (error < 0) +- log_debug("sysview: error while removing session '%s': %s", +- session->name, strerror(-error)); + sysview_session_free(session); +- return error; + } + +-static int context_add_seat(sysview_context *c, const char *id) { ++static void context_add_seat(sysview_context *c, const char *id) { + sysview_seat *seat; + int r; + +@@ -721,7 +711,7 @@ static int context_add_seat(sysview_context *c, const char *id) { + + seat = sysview_find_seat(c, id); + if (seat) +- return 0; ++ return; + + log_debug("sysview: add seat '%s'", id); + +@@ -731,54 +721,45 @@ static int context_add_seat(sysview_context *c, const char *id) { + + seat->public = true; + r = context_raise_seat_add(c, seat); +- if (r != 0) { ++ if (r < 0) { ++ log_debug("sysview: callback failed while adding seat '%s': %s", ++ seat->name, strerror(-r)); + seat->public = false; +- goto error; + } + +- return 0; ++ return; + + error: + if (r < 0) + log_debug("sysview: error while adding seat '%s': %s", + id, strerror(-r)); +- return r; + } + +-static int context_remove_seat(sysview_context *c, sysview_seat *seat) { ++static void context_remove_seat(sysview_context *c, sysview_seat *seat) { + sysview_session *session; + sysview_device *device; +- int r, error = 0; ++ int r; + + assert(c); + assert(seat); + + log_debug("sysview: remove seat '%s'", seat->name); + +- while ((device = hashmap_first(seat->device_map))) { +- r = context_remove_device(c, device); +- if (r != 0) +- error = r; +- } ++ while ((device = hashmap_first(seat->device_map))) ++ context_remove_device(c, device); + +- while ((session = hashmap_first(seat->session_map))) { +- r = context_remove_session(c, session); +- if (r != 0) +- error = r; +- } ++ while ((session = hashmap_first(seat->session_map))) ++ context_remove_session(c, session); + + if (seat->public) { + seat->public = false; + r = context_raise_seat_remove(c, seat); +- if (r != 0) +- error = r; ++ if (r < 0) ++ log_debug("sysview: callback failed while removing seat '%s': %s", ++ seat->name, strerror(-r)); + } + +- if (error < 0) +- log_debug("sysview: error while removing seat '%s': %s", +- seat->name, strerror(-error)); + sysview_seat_free(seat); +- return error; + } + + int sysview_context_new(sysview_context **out, +@@ -923,12 +904,12 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { + if (!device) + return 0; + +- return context_remove_device(c, device); ++ context_remove_device(c, device); + } else if (streq_ptr(action, "change")) { + if (!device) + return 0; + +- return context_change_device(c, device, d); ++ context_change_device(c, device, d); + } else if (!action || streq_ptr(action, "add")) { + struct udev_device *p; + unsigned int type, t; +@@ -966,7 +947,7 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) { + return r; + } + +- return context_add_device(c, device); ++ context_add_device(c, device); + } + + return 0; +@@ -1093,7 +1074,8 @@ static int context_ld_seat_new(sysview_context *c, sd_bus_message *signal) { + return r; + } + +- return context_add_seat(c, id); ++ context_add_seat(c, id); ++ return 0; + } + + static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) { +@@ -1112,7 +1094,8 @@ static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) { + if (!seat) + return 0; + +- return context_remove_seat(c, seat); ++ context_remove_seat(c, seat); ++ return 0; + } + + static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) { +@@ -1159,14 +1142,13 @@ static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) { + } + + r = context_raise_session_filter(c, id, seatid, username, uid); +- if (r <= 0) { +- if (r < 0) +- log_debug("sysview: cannot filter new session '%s' on seat '%s': %s", +- id, seatid, strerror(-r)); +- return r; +- } ++ if (r < 0) ++ log_debug("sysview: callback failed while filtering session '%s': %s", ++ id, strerror(-r)); ++ else if (r > 0) ++ context_add_session(c, seat, id); + +- return context_add_session(c, seat, id); ++ return 0; + + error: + log_debug("sysview: failed retrieving information for new session '%s': %s", +@@ -1190,7 +1172,8 @@ static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal + if (!session) + return 0; + +- return context_remove_session(c, session); ++ context_remove_session(c, session); ++ return 0; + } + + static int context_ld_manager_signal_fn(sd_bus *bus, +@@ -1265,9 +1248,7 @@ static int context_ld_list_seats_fn(sd_bus *bus, + if (r < 0) + goto error; + +- r = context_add_seat(c, id); +- if (r != 0) +- return r; ++ context_add_seat(c, id); + + r = sd_bus_message_exit_container(reply); + if (r < 0) +@@ -1328,15 +1309,11 @@ static int context_ld_list_sessions_fn(sd_bus *bus, + seat = sysview_find_seat(c, seatid); + if (seat) { + r = context_raise_session_filter(c, id, seatid, username, uid); +- if (r < 0) { +- log_debug("sysview: cannot filter listed session '%s' on seat '%s': %s", +- id, seatid, strerror(-r)); +- return r; +- } else if (r > 0) { +- r = context_add_session(c, seat, id); +- if (r != 0) +- return r; +- } ++ if (r < 0) ++ log_debug("sysview: callback failed while filtering session '%s': %s", ++ id, strerror(-r)); ++ else if (r > 0) ++ context_add_session(c, seat, id); + } + + r = sd_bus_message_exit_container(reply); diff --git a/0362-terminal-signal-object-removal-during-sysview_contex.patch b/0362-terminal-signal-object-removal-during-sysview_contex.patch new file mode 100644 index 0000000..9a7626f --- /dev/null +++ b/0362-terminal-signal-object-removal-during-sysview_contex.patch @@ -0,0 +1,84 @@ +From c17091b79773e9c458f03a897b26c2257d7366a7 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 22 Sep 2014 18:05:19 +0200 +Subject: [PATCH] terminal: signal object removal during sysview_context_stop() + +Now that we no longer propagate callback return values, we can safely call +into user-callbacks during sysview_context_stop(). This way, users can +rely on all objects to be removed via callbacks (except if they failed +during object creation). This avoids duplicating any object hashtables on +the users' side and reduces memory consumption. +--- + src/libsystemd-terminal/evcat.c | 3 ++- + src/libsystemd-terminal/modeset.c | 3 ++- + src/libsystemd-terminal/sysview.c | 22 ++++++++-------------- + 3 files changed, 12 insertions(+), 16 deletions(-) + +diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c +index b3f08e60bf..62556f6a2b 100644 +--- a/src/libsystemd-terminal/evcat.c ++++ b/src/libsystemd-terminal/evcat.c +@@ -330,7 +330,8 @@ static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *e + case SYSVIEW_EVENT_SESSION_REMOVE: + idev_session_disable(e->idev_session); + e->idev_session = idev_session_free(e->idev_session); +- sd_event_exit(e->event, 0); ++ if (sd_event_get_exit_code(e->event, &r) == -ENODATA) ++ sd_event_exit(e->event, 0); + break; + case SYSVIEW_EVENT_SESSION_ATTACH: + d = ev->session_attach.device; +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +index 7a28e7ab97..f564fa0f65 100644 +--- a/src/libsystemd-terminal/modeset.c ++++ b/src/libsystemd-terminal/modeset.c +@@ -332,7 +332,8 @@ static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event + grdev_session_restore(m->grdev_session); + grdev_session_disable(m->grdev_session); + m->grdev_session = grdev_session_free(m->grdev_session); +- sd_event_exit(m->event, 0); ++ if (sd_event_get_exit_code(m->event, &r) == -ENODATA) ++ sd_event_exit(m->event, 0); + break; + case SYSVIEW_EVENT_SESSION_ATTACH: + d = ev->session_attach.device; +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 969514ad9d..cd776f62d8 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -1437,20 +1437,6 @@ void sysview_context_stop(sysview_context *c) { + + log_debug("sysview: stop"); + +- c->running = false; +- c->scanned = false; +- c->event_fn = NULL; +- c->userdata = NULL; +- c->scan_src = sd_event_source_unref(c->scan_src); +- context_ud_stop(c); +- context_ld_stop(c); +- +- /* +- * Event-callbacks are already cleared, hence we can safely ignore +- * return codes of the context_remove_*() helpers. They cannot be +- * originated from user-callbacks, so we already handled them. +- */ +- + while ((device = hashmap_first(c->device_map))) + context_remove_device(c, device); + +@@ -1459,6 +1445,14 @@ void sysview_context_stop(sysview_context *c) { + + while ((seat = hashmap_first(c->seat_map))) + context_remove_seat(c, seat); ++ ++ c->running = false; ++ c->scanned = false; ++ c->event_fn = NULL; ++ c->userdata = NULL; ++ c->scan_src = sd_event_source_unref(c->scan_src); ++ context_ud_stop(c); ++ context_ld_stop(c); + } + + static int context_scan_fn(sd_event_source *s, void *userdata) { diff --git a/0363-util-avoid-non-portable-__WORDSIZE.patch b/0363-util-avoid-non-portable-__WORDSIZE.patch new file mode 100644 index 0000000..7a1d77e --- /dev/null +++ b/0363-util-avoid-non-portable-__WORDSIZE.patch @@ -0,0 +1,27 @@ +From 8507eb20b64010b26f23822cbf442bb0bf96511c Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Fri, 19 Sep 2014 20:26:53 +0200 +Subject: [PATCH] util: avoid non-portable __WORDSIZE + +Lets not unnecessarily rely on __WORDSIZE, which is not clearly specified +by any spec. Use explicit size comparisons if we're not interested in the +WORDSIZE, anyway. + +(David: adjust commit message to explain why we do this) +--- + 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 a1d5657237..21a90a40e5 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -205,7 +205,7 @@ int safe_atod(const char *s, double *ret_d); + + int safe_atou8(const char *s, uint8_t *ret); + +-#if __WORDSIZE == 32 ++#if LONG_MAX == INT_MAX + static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); diff --git a/0364-sd-bus-sync-kdbus.h-API-ABI-break.patch b/0364-sd-bus-sync-kdbus.h-API-ABI-break.patch new file mode 100644 index 0000000..c352c94 --- /dev/null +++ b/0364-sd-bus-sync-kdbus.h-API-ABI-break.patch @@ -0,0 +1,197 @@ +From f8c2425287c8362ae3a3c9acfb9e23a16862b38a Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Mon, 22 Sep 2014 18:20:14 +0200 +Subject: [PATCH] sd-bus: sync kdbus.h (API+ABI break) + +The kdbus logic name registry logic was changed to transport the actual +name to acquire, release or report in a kdbus item. + +This brings the name API a little more in line with other calls, and allows +for later augmentation. + +Follow that change on the systemd side. +--- + src/bus-proxyd/bus-proxyd.c | 9 ++++++--- + src/libsystemd/sd-bus/bus-control.c | 30 ++++++++++++++++++++++-------- + src/libsystemd/sd-bus/kdbus.h | 23 ++++++++++------------- + 3 files changed, 38 insertions(+), 24 deletions(-) + +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +index d35d7f63b2..a5387bb234 100644 +--- a/src/bus-proxyd/bus-proxyd.c ++++ b/src/bus-proxyd/bus-proxyd.c +@@ -743,12 +743,15 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { + name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset); + + KDBUS_ITEM_FOREACH(name, name_list, names) { ++ const char *entry_name = NULL; ++ struct kdbus_item *item; + char *n; + +- if (name->size <= sizeof(*name)) +- continue; ++ KDBUS_ITEM_FOREACH(item, name, items) ++ if (item->type == KDBUS_ITEM_NAME) ++ entry_name = item->str; + +- if (!streq(name->name, arg0)) ++ if (!streq_ptr(entry_name, arg0)) + continue; + + if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) { +diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c +index 5ac48c081f..50b662f85d 100644 +--- a/src/libsystemd/sd-bus/bus-control.c ++++ b/src/libsystemd/sd-bus/bus-control.c +@@ -59,11 +59,14 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags + assert(name); + + l = strlen(name); +- size = offsetof(struct kdbus_cmd_name, name) + l + 1; ++ size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l + 1); + n = alloca0_align(size, 8); + n->size = size; + kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags); +- memcpy(n->name, name, l+1); ++ ++ n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l + 1; ++ n->items[0].type = KDBUS_ITEM_NAME; ++ memcpy(n->items[0].str, name, l+1); + + #ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(n, n->size); +@@ -144,16 +147,20 @@ _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) + + static int bus_release_name_kernel(sd_bus *bus, const char *name) { + struct kdbus_cmd_name *n; +- size_t l; ++ size_t size, l; + int r; + + assert(bus); + assert(name); + + l = strlen(name); +- n = alloca0_align(offsetof(struct kdbus_cmd_name, name) + l + 1, 8); +- n->size = offsetof(struct kdbus_cmd_name, name) + l + 1; +- memcpy(n->name, name, l+1); ++ size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l + 1); ++ n = alloca0_align(size, 8); ++ n->size = size; ++ ++ n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l + 1; ++ n->items[0].type = KDBUS_ITEM_NAME; ++ memcpy(n->items[0].str, name, l+1); + + #ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(n, n->size); +@@ -235,6 +242,9 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { + + KDBUS_ITEM_FOREACH(name, name_list, names) { + ++ struct kdbus_item *item; ++ const char *entry_name = NULL; ++ + if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) { + char *n; + +@@ -248,8 +258,12 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { + previous_id = name->owner_id; + } + +- if (name->size > sizeof(*name) && service_name_is_valid(name->name)) { +- r = strv_extend(x, name->name); ++ KDBUS_ITEM_FOREACH(item, name, items) ++ if (item->type == KDBUS_ITEM_NAME) ++ entry_name = item->str; ++ ++ if (entry_name && service_name_is_valid(entry_name)) { ++ r = strv_extend(x, entry_name); + if (r < 0) + return -ENOMEM; + } +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index 7379b3d442..0718b8497a 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -17,11 +17,8 @@ + #ifndef _KDBUS_UAPI_H_ + #define _KDBUS_UAPI_H_ + +-#ifndef __KERNEL__ +-#include +-#include ++#include + #include +-#endif + + #define KDBUS_IOCTL_MAGIC 0x95 + #define KDBUS_SRC_ID_KERNEL (0) +@@ -121,7 +118,7 @@ struct kdbus_timestamp { + /** + * struct kdbus_vec - I/O vector for kdbus payload items + * @size: The size of the vector +- * @address: Memory address for memory addresses ++ * @address: Memory address of data buffer + * @offset: Offset in the in-message payload memory, + * relative to the message head + * +@@ -160,7 +157,7 @@ struct kdbus_bloom_filter { + * struct kdbus_memfd - a kdbus memfd + * @size: The memfd's size + * @fd: The file descriptor number +- * @__pad: Padding to ensure proper alignement and size ++ * @__pad: Padding to ensure proper alignment and size + * + * Attached to: + * KDBUS_ITEM_PAYLOAD_MEMFD +@@ -477,7 +474,7 @@ enum kdbus_policy_type { + + /** + * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello +- * @KDBUS_HELLO_ACCEPT_FD: The connection allows the receiving of ++ * @KDBUS_HELLO_ACCEPT_FD: The connection allows the reception of + * any passed file descriptors + * @KDBUS_HELLO_ACTIVATOR: Special-purpose connection which registers + * a well-know name for a process to be started +@@ -533,8 +530,7 @@ enum kdbus_attach_flags { + /** + * struct kdbus_cmd_hello - struct to say hello to kdbus + * @size: The total size of the structure +- * @conn_flags: Connection flags (KDBUS_HELLO_*). The kernel will +- * return its capabilities in that field. ++ * @conn_flags: Connection flags (KDBUS_HELLO_*). + * @attach_flags: Mask of metadata to attach to each message sent + * (KDBUS_ATTACH_*) + * @bus_flags: The flags field copied verbatim from the original +@@ -608,9 +604,10 @@ enum kdbus_name_flags { + * struct kdbus_cmd_name - struct to describe a well-known name + * @size: The total size of the struct + * @flags: Flags for a name entry (KDBUS_NAME_*) +- * @owner_id: The current owner of the name. ++ * @owner_id: The current owner of the name + * @conn_flags: The flags of the owning connection (KDBUS_HELLO_*) +- * @name: The well-known name ++ * @items: Item list, containing the well-known name as ++ * KDBUS_ITEM_NAME + * + * This structure is used with the KDBUS_CMD_NAME_ACQUIRE ioctl. + */ +@@ -619,7 +616,7 @@ struct kdbus_cmd_name { + __u64 flags; + __u64 owner_id; + __u64 conn_flags; +- char name[0]; ++ struct kdbus_item items[0]; + } __attribute__((aligned(8))); + + /** +@@ -808,7 +805,7 @@ enum kdbus_ioctl_type { + KDBUS_CMD_NAME_RELEASE = _IOW(KDBUS_IOCTL_MAGIC, 0x51, + struct kdbus_cmd_name), + KDBUS_CMD_NAME_LIST = _IOWR(KDBUS_IOCTL_MAGIC, 0x52, +- struct kdbus_cmd_name_list), ++ struct kdbus_cmd_name_list), + + KDBUS_CMD_CONN_INFO = _IOWR(KDBUS_IOCTL_MAGIC, 0x60, + struct kdbus_cmd_conn_info), diff --git a/0365-logind-add-support-for-Triton2-Power-Button.patch b/0365-logind-add-support-for-Triton2-Power-Button.patch new file mode 100644 index 0000000..bb50cdd --- /dev/null +++ b/0365-logind-add-support-for-Triton2-Power-Button.patch @@ -0,0 +1,21 @@ +From 58d4aabedd415a735efeb8c2608ee73618c07f78 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 22 Sep 2014 22:14:39 -0400 +Subject: [PATCH] logind: add support for Triton2 Power Button + +https://bugs.freedesktop.org/show_bug.cgi?id=84201 +--- + src/login/70-power-switch.rules | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/login/70-power-switch.rules b/src/login/70-power-switch.rules +index 36fb827315..a6997f7788 100644 +--- a/src/login/70-power-switch.rules ++++ b/src/login/70-power-switch.rules +@@ -9,5 +9,6 @@ ACTION=="remove", GOTO="power_switch_end" + + SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="acpi", TAG+="power-switch" + SUBSYSTEM=="input", KERNEL=="event*", KERNELS=="thinkpad_acpi", TAG+="power-switch" ++SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="twl4030_pwrbutton", TAG+="power-switch" + + LABEL="power_switch_end" diff --git a/0366-terminal-fix-spelling-mistake.patch b/0366-terminal-fix-spelling-mistake.patch new file mode 100644 index 0000000..4fcbc33 --- /dev/null +++ b/0366-terminal-fix-spelling-mistake.patch @@ -0,0 +1,131 @@ +From 0508a4dfb8300000fcfc5fa5147582e5feebf1a8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 23 Sep 2014 09:22:33 -0400 +Subject: [PATCH] terminal: fix spelling mistake + +--- + src/libsystemd-terminal/grdev-internal.h | 4 ++-- + src/libsystemd-terminal/grdev.c | 28 ++++++++++++++-------------- + 2 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h +index ee182695ce..f455dd4172 100644 +--- a/src/libsystemd-terminal/grdev-internal.h ++++ b/src/libsystemd-terminal/grdev-internal.h +@@ -60,7 +60,7 @@ enum { + }; + + struct grdev_tile { +- LIST_FIELDS(grdev_tile, childs_by_node); ++ LIST_FIELDS(grdev_tile, children_by_node); + grdev_tile *parent; + grdev_display *display; + +@@ -79,7 +79,7 @@ struct grdev_tile { + } leaf; + + struct { +- size_t n_childs; ++ size_t n_children; + LIST_HEAD(grdev_tile, child_list); + } node; + }; +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index e34112ee7c..c5ea524c69 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -54,10 +54,10 @@ static inline grdev_tile *tile_leftmost(grdev_tile *tile) { + } + + #define TILE_FOREACH(_root, _i) \ +- for (_i = tile_leftmost(_root); _i; _i = tile_leftmost(_i->childs_by_node_next) ? : _i->parent) ++ for (_i = tile_leftmost(_root); _i; _i = tile_leftmost(_i->children_by_node_next) ? : _i->parent) + + #define TILE_FOREACH_SAFE(_root, _i, _next) \ +- for (_i = tile_leftmost(_root); _i && ((_next = tile_leftmost(_i->childs_by_node_next) ? : _i->parent), true); _i = _next) ++ for (_i = tile_leftmost(_root); _i && ((_next = tile_leftmost(_i->children_by_node_next) ? : _i->parent), true); _i = _next) + + static void tile_link(grdev_tile *tile, grdev_tile *parent) { + grdev_display *display; +@@ -73,8 +73,8 @@ static void tile_link(grdev_tile *tile, grdev_tile *parent) { + + assert(!display || !display->enabled); + +- ++parent->node.n_childs; +- LIST_PREPEND(childs_by_node, parent->node.child_list, tile); ++ ++parent->node.n_children; ++ LIST_PREPEND(children_by_node, parent->node.child_list, tile); + tile->parent = parent; + + if (display) { +@@ -105,10 +105,10 @@ static void tile_unlink(grdev_tile *tile) { + + assert(parent->type == GRDEV_TILE_NODE); + assert(parent->display == display); +- assert(parent->node.n_childs > 0); ++ assert(parent->node.n_children > 0); + +- --parent->node.n_childs; +- LIST_REMOVE(childs_by_node, parent->node.child_list, tile); ++ --parent->node.n_children; ++ LIST_REMOVE(children_by_node, parent->node.child_list, tile); + tile->parent = NULL; + + if (display) { +@@ -127,14 +127,14 @@ static void tile_unlink(grdev_tile *tile) { + * we must take care to not leave them around. Therefore, whenever we + * unlink any part of a tree, we also destroy the parent, in case it's + * now stale. +- * Parents are stale if they have no childs and either have no display ++ * Parents are stale if they have no children and either have no display + * or if they are intermediate nodes (i.e, they have a parent). + * This means, you can easily create trees, but you can never partially + * move or destruct them so far. They're always reduced to minimal form + * if you cut them. This might change later, but so far we didn't need + * partial destruction or the ability to move whole trees. */ + +- if (parent->node.n_childs < 1 && (parent->parent || !parent->display)) ++ if (parent->node.n_children < 1 && (parent->parent || !parent->display)) + grdev_tile_free(parent); + } + +@@ -207,7 +207,7 @@ grdev_tile *grdev_tile_free(grdev_tile *tile) { + case GRDEV_TILE_NODE: + assert(!tile->parent); + assert(!tile->display); +- assert(tile->node.n_childs == 0); ++ assert(tile->node.n_children == 0); + + break; + } +@@ -472,10 +472,10 @@ static void display_cache_targets(grdev_display *display) { + + assert(display); + +- /* depth-first with childs before parent */ ++ /* depth-first with children before parent */ + for (tile = tile_leftmost(display->tile); + tile; +- tile = tile_leftmost(tile->childs_by_node_next) ? : tile->parent) { ++ tile = tile_leftmost(tile->children_by_node_next) ? : tile->parent) { + if (tile->type == GRDEV_TILE_LEAF) { + grdev_pipe *p; + +@@ -504,7 +504,7 @@ static void display_cache_targets(grdev_display *display) { + } else { + grdev_tile *child, *l; + +- /* We're now at a node with all it's childs already ++ /* We're now at a node with all its children already + * computed (depth-first, child before parent). We + * first need to know the size of our tile, then we + * recurse into all leafs and update their cache. */ +@@ -512,7 +512,7 @@ static void display_cache_targets(grdev_display *display) { + tile->cache_w = 0; + tile->cache_h = 0; + +- LIST_FOREACH(childs_by_node, child, tile->node.child_list) { ++ LIST_FOREACH(children_by_node, child, tile->node.child_list) { + if (child->x + child->cache_w > tile->cache_w) + tile->cache_w = child->x + child->cache_w; + if (child->y + child->cache_h > tile->cache_h) diff --git a/0367-Fix-warning-about-unused-variable-with-SELINUX.patch b/0367-Fix-warning-about-unused-variable-with-SELINUX.patch new file mode 100644 index 0000000..6661e92 --- /dev/null +++ b/0367-Fix-warning-about-unused-variable-with-SELINUX.patch @@ -0,0 +1,28 @@ +From 493d521d9ffe706741665a88ea14929913ea2eaf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 23 Sep 2014 09:22:40 -0400 +Subject: [PATCH] Fix warning about unused variable with !SELINUX + +src/shared/label.c:255:15: warning: unused variable 'l' [-Wunused-variable] + char *l = NULL; + ^ +--- + src/shared/label.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/shared/label.c b/src/shared/label.c +index 02b41f02d8..b6af38d82d 100644 +--- a/src/shared/label.c ++++ b/src/shared/label.c +@@ -252,9 +252,10 @@ fail: + + int label_get_our_label(char **label) { + int r = -EOPNOTSUPP; +- char *l = NULL; + + #ifdef HAVE_SELINUX ++ char *l = NULL; ++ + r = getcon(&l); + if (r < 0) + return r; diff --git a/0368-localed-rename-write_data_x11-to-x11_write_data.patch b/0368-localed-rename-write_data_x11-to-x11_write_data.patch new file mode 100644 index 0000000..66dd14d --- /dev/null +++ b/0368-localed-rename-write_data_x11-to-x11_write_data.patch @@ -0,0 +1,42 @@ +From e78af5ffe53a0d24854d721d1166a60f8ed0dfb6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 4 Sep 2014 12:30:46 -0400 +Subject: [PATCH] localed: rename write_data_x11 to x11_write_data + +Other functions in this file follow this pattern, +we have vconsole_write_data and locale_write_data. +--- + src/locale/localed.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/locale/localed.c b/src/locale/localed.c +index 2252080f2e..1d5be715ba 100644 +--- a/src/locale/localed.c ++++ b/src/locale/localed.c +@@ -430,7 +430,7 @@ static int vconsole_write_data(Context *c) { + return write_env_file_label("/etc/vconsole.conf", l); + } + +-static int write_data_x11(Context *c) { ++static int x11_write_data(Context *c) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *temp_path = NULL; + int r; +@@ -605,7 +605,7 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { + if (modified) { + int r; + +- r = write_data_x11(c); ++ r = x11_write_data(c); + if (r < 0) { + log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); + return r; +@@ -1050,7 +1050,7 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat + free_and_strdup(&c->x11_options, options) < 0) + return -ENOMEM; + +- r = write_data_x11(c); ++ r = x11_write_data(c); + if (r < 0) { + log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %s", strerror(-r)); diff --git a/0369-sd-bus-sync-kdbus.h-API-break.patch b/0369-sd-bus-sync-kdbus.h-API-break.patch new file mode 100644 index 0000000..08c1078 --- /dev/null +++ b/0369-sd-bus-sync-kdbus.h-API-break.patch @@ -0,0 +1,79 @@ +From 619d7a039f9f64ffa593634c2715838ffbc17be4 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 23 Sep 2014 16:13:54 +0200 +Subject: [PATCH] sd-bus: sync kdbus.h (API break) + +Just a rename of two struct members to make the header file c++ compatible. +--- + src/libsystemd/sd-bus/bus-control.c | 4 ++-- + src/libsystemd/sd-bus/bus-kernel.c | 8 ++++---- + src/libsystemd/sd-bus/kdbus.h | 6 +++--- + 3 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c +index 50b662f85d..b22f4c4ff6 100644 +--- a/src/libsystemd/sd-bus/bus-control.c ++++ b/src/libsystemd/sd-bus/bus-control.c +@@ -851,8 +851,8 @@ static int add_name_change_match(sd_bus *bus, + offsetof(struct kdbus_notify_name_change, name) + + l; + +- item->name_change.old.id = old_owner_id; +- item->name_change.new.id = new_owner_id; ++ item->name_change.old_id.id = old_owner_id; ++ item->name_change.new_id.id = new_owner_id; + + if (name) + memcpy(item->name_change.name, name, l); +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index c30491e687..236e8787b7 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -950,19 +950,19 @@ static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_ + assert(k); + assert(d); + +- if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) ++ if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) + old_owner[0] = 0; + else +- sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old.id); ++ sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old_id.id); + +- if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) { ++ if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) { + + if (isempty(old_owner)) + return 0; + + new_owner[0] = 0; + } else +- sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new.id); ++ sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new_id.id); + + return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner); + } +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index 0718b8497a..b167c4d00e 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -46,7 +46,7 @@ struct kdbus_notify_id_change { + /** + * struct kdbus_notify_name_change - name registry change message + * @old: ID and flags of former owner of a name +- * @new: ID and flags of new owner of a name ++ * @now: ID and flags of new owner of a name + * @name: Well-known name + * + * Sent from kernel to userspace when the owner or activator of +@@ -58,8 +58,8 @@ struct kdbus_notify_id_change { + * KDBUS_ITEM_NAME_CHANGE + */ + struct kdbus_notify_name_change { +- struct kdbus_notify_id_change old; +- struct kdbus_notify_id_change new; ++ struct kdbus_notify_id_change old_id; ++ struct kdbus_notify_id_change new_id; + char name[0]; + }; + diff --git a/0370-sd-bus-sync-kdbus.h.patch b/0370-sd-bus-sync-kdbus.h.patch new file mode 100644 index 0000000..e527c75 --- /dev/null +++ b/0370-sd-bus-sync-kdbus.h.patch @@ -0,0 +1,24 @@ +From 590889ac53c8557493f491b4259669e54074615d Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 23 Sep 2014 17:37:44 +0200 +Subject: [PATCH] sd-bus: sync kdbus.h + +--- + src/libsystemd/sd-bus/kdbus.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index b167c4d00e..77a153be37 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -45,8 +45,8 @@ struct kdbus_notify_id_change { + + /** + * struct kdbus_notify_name_change - name registry change message +- * @old: ID and flags of former owner of a name +- * @now: ID and flags of new owner of a name ++ * @old_id: ID and flags of former owner of a name ++ * @new_id: ID and flags of new owner of a name + * @name: Well-known name + * + * Sent from kernel to userspace when the owner or activator of diff --git a/0371-Silence-some-unchecked-return-value-warnings.patch b/0371-Silence-some-unchecked-return-value-warnings.patch new file mode 100644 index 0000000..18fa597 --- /dev/null +++ b/0371-Silence-some-unchecked-return-value-warnings.patch @@ -0,0 +1,93 @@ +From ce540a24d53e1751a5b69224d5a7f5a59f2de7ad Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 23 Sep 2014 13:33:53 +0200 +Subject: [PATCH] Silence some "unchecked return-value" warnings + +This adds some log-messages to ioctl() calls where we don't really care +for the return value. It isn't strictly necessary to look for those, but +lets be sure and print warnings. This silences gcc and coverity, and also +makes sure we get reports in case something goes wrong and we didn't +expect it to fail that way. +--- + src/libsystemd-terminal/grdev-drm.c | 23 ++++++++++++++++++----- + src/login/logind-session.c | 6 +++++- + 2 files changed, 23 insertions(+), 6 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 2e55ad326b..5c65c096de 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -1474,14 +1474,19 @@ static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_ + + grdrm_fb *grdrm_fb_free(grdrm_fb *fb) { + unsigned int i; ++ int r; + + if (!fb) + return NULL; + + assert(fb->card); + +- if (fb->id > 0 && fb->card->fd >= 0) +- ioctl(fb->card->fd, DRM_IOCTL_MODE_RMFB, fb->id); ++ if (fb->id > 0 && fb->card->fd >= 0) { ++ r = ioctl(fb->card->fd, DRM_IOCTL_MODE_RMFB, fb->id); ++ if (r < 0) ++ log_debug("grdrm: %s: cannot delete framebuffer %" PRIu32 ": %m", ++ fb->card->base.name, fb->id); ++ } + + for (i = 0; i < ELEMENTSOF(fb->handles); ++i) { + struct drm_mode_destroy_dumb destroy_dumb = { }; +@@ -1491,7 +1496,10 @@ grdrm_fb *grdrm_fb_free(grdrm_fb *fb) { + + if (fb->handles[i] > 0 && fb->card->fd >= 0) { + destroy_dumb.handle = fb->handles[i]; +- ioctl(fb->card->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); ++ r = ioctl(fb->card->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); ++ if (r < 0) ++ log_debug("grdrm: %s: cannot destroy dumb-buffer %" PRIu32 ": %m", ++ fb->card->base.name, fb->handles[i]); + } + } + +@@ -2549,8 +2557,13 @@ static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct u + basecard->session->name, basecard->name, cu->devnode); + } else { + /* We might get DRM-Master implicitly on open(); drop it immediately +- * so we acquire it only once we're actually enabled. */ +- ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); ++ * so we acquire it only once we're actually enabled. We don't ++ * really care whether this call fails or not, but lets log any ++ * weird errors, anyway. */ ++ r = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); ++ if (r < 0 && errno != EACCES && errno != EINVAL) ++ log_debug("grdrm: %s/%s: cannot drop DRM-Master: %m", ++ basecard->session->name, basecard->name); + + r = grdrm_card_open(&cu->card, fd); + if (r < 0) +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 477ac9ab1b..65bbb77750 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -1054,6 +1054,8 @@ void session_restore_vt(Session *s) { + } + + void session_leave_vt(Session *s) { ++ int r; ++ + assert(s); + + /* This is called whenever we get a VT-switch signal from the kernel. +@@ -1071,7 +1073,9 @@ void session_leave_vt(Session *s) { + return; + + session_device_pause_all(s); +- ioctl(s->vtfd, VT_RELDISP, 1); ++ r = ioctl(s->vtfd, VT_RELDISP, 1); ++ if (r < 0) ++ log_debug("Cannot release VT of session %s: %m", s->id); + } + + bool session_is_controller(Session *s, const char *sender) { diff --git a/0372-terminal-fix-tile-offset-calculation.patch b/0372-terminal-fix-tile-offset-calculation.patch new file mode 100644 index 0000000..6797046 --- /dev/null +++ b/0372-terminal-fix-tile-offset-calculation.patch @@ -0,0 +1,28 @@ +From b4170aed36e667e52ce4a353bda1964e3872ab34 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 23 Sep 2014 13:38:09 +0200 +Subject: [PATCH] terminal: fix tile-offset calculation + +Binary operators with two pointers as arguments always operate on +object-size, not bytes. That is, "int *a, *b", (a - b) calculates the +number of integers between b and a, not the number of bytes. + +Fix our cache-offset calculation to not use sizeof() with full-ptr +arithmetic. +--- + src/libsystemd-terminal/grdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index c5ea524c69..80a71beeb9 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -345,7 +345,7 @@ const grdev_display_target *grdev_display_next_target(grdev_display *display, co + assert(cache->pipe->tile->display == display); + assert(display->pipes >= cache); + +- idx = (cache - display->pipes) / sizeof(*cache) + 1; ++ idx = cache - display->pipes + 1; + } else { + idx = 0; + } diff --git a/0373-terminal-verify-grdev-tiles-are-correctly-linked.patch b/0373-terminal-verify-grdev-tiles-are-correctly-linked.patch new file mode 100644 index 0000000..688616e --- /dev/null +++ b/0373-terminal-verify-grdev-tiles-are-correctly-linked.patch @@ -0,0 +1,26 @@ +From c5e6bfc6bc46dd8bc187e035929d6a49cd23ec09 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 23 Sep 2014 13:40:18 +0200 +Subject: [PATCH] terminal: verify grdev tiles are correctly linked + +We used to set "pipe->tile = tile" inside of the leaf allocation. We no +longer do that. Verify that "out" is non-NULL, otherwise we'd leak memory. + +This is currently always given, but make sure to add an assert(), so +coverity does not complain. +--- + src/libsystemd-terminal/grdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index 80a71beeb9..fa1fc378c8 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -158,6 +158,7 @@ int grdev_tile_new_leaf(grdev_tile **out, grdev_pipe *pipe) { + _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL; + int r; + ++ assert_return(out, -EINVAL); + assert_return(pipe, -EINVAL); + assert_return(!pipe->tile, -EINVAL); + diff --git a/0374-terminal-verify-kernel-returned-DRM-events-are-not-t.patch b/0374-terminal-verify-kernel-returned-DRM-events-are-not-t.patch new file mode 100644 index 0000000..0b2910f --- /dev/null +++ b/0374-terminal-verify-kernel-returned-DRM-events-are-not-t.patch @@ -0,0 +1,26 @@ +From a908d213557cfbe874b7bd1ae3a1b0d3c05c29e9 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 23 Sep 2014 13:51:42 +0200 +Subject: [PATCH] terminal: verify kernel-returned DRM events are not truncated + +Make sure the kernel always returns events properly. This is guaranteed +right now, otherwise, we do something really wrong. But lets be sure and +verify the received values properly. This also silences some coverity +warnings. +--- + src/libsystemd-terminal/grdev-drm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 5c65c096de..5393ebf988 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -2223,7 +2223,7 @@ static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void * + for (i = 0; i < l; i += event->length) { + event = (void*)&buf[i]; + +- if (i + event->length > l) { ++ if (i + (ssize_t)sizeof(*event) > l || i + (ssize_t)event->length > l) { + log_debug("grdrm: %s/%s: truncated event", card->base.session->name, card->base.name); + break; + } diff --git a/0375-terminal-provide-display-dimensions-to-API-users.patch b/0375-terminal-provide-display-dimensions-to-API-users.patch new file mode 100644 index 0000000..9c2fcb4 --- /dev/null +++ b/0375-terminal-provide-display-dimensions-to-API-users.patch @@ -0,0 +1,57 @@ +From 158c1e3e0c1e9dd8ebf1b93061e1c81805eac339 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Tue, 23 Sep 2014 13:52:50 +0200 +Subject: [PATCH] terminal: provide display dimensions to API users + +Allow users to query the display dimensions of a grdev_display. This is +required to properly resize the objects to be rendered. +--- + src/libsystemd-terminal/grdev.c | 14 ++++++++++++++ + src/libsystemd-terminal/grdev.h | 2 ++ + 2 files changed, 16 insertions(+) + +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index fa1fc378c8..aaac06ec34 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -301,6 +301,18 @@ const char *grdev_display_get_name(grdev_display *display) { + return display->name; + } + ++uint32_t grdev_display_get_width(grdev_display *display) { ++ assert_return(display, 0); ++ ++ return display->width; ++} ++ ++uint32_t grdev_display_get_height(grdev_display *display) { ++ assert_return(display, 0); ++ ++ return display->height; ++} ++ + bool grdev_display_is_enabled(grdev_display *display) { + return display && display->enabled; + } +@@ -572,6 +584,8 @@ static bool display_cache(grdev_display *display) { + } + + display_cache_targets(display); ++ display->width = display->tile->cache_w; ++ display->height = display->tile->cache_h; + + r = 0; + +diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h +index 5f745aaad4..6ca8a767c4 100644 +--- a/src/libsystemd-terminal/grdev.h ++++ b/src/libsystemd-terminal/grdev.h +@@ -112,6 +112,8 @@ void grdev_display_set_userdata(grdev_display *display, void *userdata); + void *grdev_display_get_userdata(grdev_display *display); + + const char *grdev_display_get_name(grdev_display *display); ++uint32_t grdev_display_get_width(grdev_display *display); ++uint32_t grdev_display_get_height(grdev_display *display); + + bool grdev_display_is_enabled(grdev_display *display); + void grdev_display_enable(grdev_display *display); diff --git a/0376-bus-remove-unused-check.patch b/0376-bus-remove-unused-check.patch new file mode 100644 index 0000000..bba3147 --- /dev/null +++ b/0376-bus-remove-unused-check.patch @@ -0,0 +1,26 @@ +From 04c553e322680b6fcdf5b271e84b0b4b0ad8d5f9 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 23 Sep 2014 21:34:21 +0200 +Subject: [PATCH] bus: remove unused check + +strerror_r does not return null here and even if it did we would have +problems already at the preceding strlen call. + +Found by coverity. Fixes: CID#1237770 +--- + src/libsystemd/sd-bus/bus-error.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c +index c2e41fb016..abdfd73204 100644 +--- a/src/libsystemd/sd-bus/bus-error.c ++++ b/src/libsystemd/sd-bus/bus-error.c +@@ -312,7 +312,7 @@ static void bus_error_strerror(sd_bus_error *e, int error) { + continue; + } + +- if (!x || errno) { ++ if (errno) { + free(m); + return; + } diff --git a/0377-bus-policy-split-API-for-bus-proxyd.patch b/0377-bus-policy-split-API-for-bus-proxyd.patch new file mode 100644 index 0000000..85eb54f --- /dev/null +++ b/0377-bus-policy-split-API-for-bus-proxyd.patch @@ -0,0 +1,500 @@ +From 078ef7b85ad77ba999588f72b31a50ced5907692 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Wed, 24 Sep 2014 17:02:08 +0200 +Subject: [PATCH] bus-policy: split API for bus-proxyd + +Instead of operating on an sd_bus_message object, expose an API that has 4 +functions: + + policy_check_own() + policy_check_hello() + policy_check_recv() + policy_check_send() + +This also allows dropping extra code to parse message contents - the bus +proxy already has dedicated code paths for that, and we can hook into +those later. + +Tests amended accordingly. +--- + src/bus-proxyd/bus-policy.c | 200 ++++++++++++++++++++++++--------------- + src/bus-proxyd/bus-policy.h | 17 +++- + src/bus-proxyd/test-bus-policy.c | 92 ++++++------------ + test/bus-policy/methods.conf | 2 + + 4 files changed, 171 insertions(+), 140 deletions(-) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 151d679f6b..165e763f57 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -592,93 +592,73 @@ static int file_load(Policy *p, const char *path) { + } + } + +-static bool is_matching_name_request(sd_bus_message *m, const char *name, bool prefix) { +- +- char *n = NULL; +- int r; +- +- if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) +- return false; +- +- r = sd_bus_message_read(m, "s", &n); +- if (r < 0) +- return false; +- +- r = sd_bus_message_rewind(m, true); +- if (r < 0) +- return false; +- +- if (prefix) +- return startswith(name, n); +- else +- return streq_ptr(name, n); +-} +- +-static bool is_matching_call(PolicyItem *i, sd_bus_message *m, const char *name) { +- +- if (i->message_type && (i->message_type != m->header->type)) +- return false; +- +- if (i->path && (!m->path || !streq(i->path, m->path))) +- return false; +- +- if (i->member && (!m->member || !streq(i->member, m->member))) +- return false; +- +- if (i->interface && (!m->interface || !streq(i->interface, m->interface))) +- return false; +- +- if (i->name && (!name || !streq(i->name, name))) +- return false; +- +- return true; +-} +- + enum { + ALLOW, + DUNNO, + DENY, + }; + ++struct policy_check_filter { ++ int class; ++ const struct ucred *ucred; ++ int message_type; ++ const char *interface; ++ const char *path; ++ const char *member; ++ char **names_strv; ++ Hashmap *names_hash; ++}; ++ + static int is_permissive(PolicyItem *i) { + + return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY; + } + +-static int check_policy_item(PolicyItem *i, sd_bus_message *m, const struct ucred *ucred) { ++static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) { + + switch (i->class) { + case POLICY_ITEM_SEND: +- if ((m->bus->is_kernel && is_matching_call(i, m, m->destination)) || +- (!m->bus->is_kernel && is_matching_call(i, m, m->sender))) +- return is_permissive(i); +- break; +- + case POLICY_ITEM_RECV: +- if ((m->bus->is_kernel && is_matching_call(i, m, m->sender)) || +- (!m->bus->is_kernel && is_matching_call(i, m, m->destination))) +- return is_permissive(i); +- break; ++ ++ if (i->name) { ++ if (filter->names_hash && !hashmap_contains(filter->names_hash, i->name)) ++ break; ++ ++ if (filter->names_strv && !strv_contains(filter->names_strv, i->name)) ++ break; ++ } ++ ++ if (i->message_type && (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: +- if (is_matching_name_request(m, i->name, false)) ++ if (streq(i->name, filter->member)) + return is_permissive(i); + break; + + case POLICY_ITEM_OWN_PREFIX: +- if (is_matching_name_request(m, i->name, true)) ++ if (startswith(i->name, filter->member)) + return is_permissive(i); + break; + + case POLICY_ITEM_USER: +- if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && +- (streq_ptr(i->name, "*") || (i->uid_valid && i->uid == ucred->uid))) ++ if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->ucred->uid))) + return is_permissive(i); + break; + + case POLICY_ITEM_GROUP: +- if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && +- (streq_ptr(i->name, "*") || (i->gid_valid && i->gid == ucred->gid))) ++ if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->ucred->gid))) + return is_permissive(i); + break; + +@@ -690,7 +670,7 @@ static int check_policy_item(PolicyItem *i, sd_bus_message *m, const struct ucre + return DUNNO; + } + +-static int check_policy_items(PolicyItem *items, sd_bus_message *m, const struct ucred *ucred) { ++static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) { + + PolicyItem *i; + int r, ret = DUNNO; +@@ -698,7 +678,10 @@ static int check_policy_items(PolicyItem *items, sd_bus_message *m, const struct + /* 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) { +- r = check_policy_item(i, m, ucred); ++ if (i->class != filter->class) ++ continue; ++ ++ r = check_policy_item(i, filter); + if (r != DUNNO) + ret = r; + } +@@ -706,7 +689,7 @@ static int check_policy_items(PolicyItem *items, sd_bus_message *m, const struct + return ret; + } + +-bool policy_check(Policy *p, sd_bus_message *m, const struct ucred *ucred) { ++static int policy_check(Policy *p, const struct policy_check_filter *filter) { + + PolicyItem *items; + int r; +@@ -720,31 +703,100 @@ bool policy_check(Policy *p, sd_bus_message *m, const struct ucred *ucred) { + * 4. If the message isn't caught be the defaults either, reject it. + */ + +- r = check_policy_items(p->mandatory_items, m, ucred); ++ r = check_policy_items(p->mandatory_items, filter); + if (r != DUNNO) +- return r == ALLOW; ++ return r; + +- if (ucred->pid > 0) { +- items = hashmap_get(p->user_items, UINT32_TO_PTR(ucred->uid)); ++ if (filter->ucred) { ++ items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->ucred->uid)); + if (items) { +- r = check_policy_items(items, m, ucred); ++ r = check_policy_items(items, filter); + if (r != DUNNO) +- return r == ALLOW; ++ return r; + } + +- items = hashmap_get(p->group_items, UINT32_TO_PTR(ucred->gid)); ++ items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->ucred->gid)); + if (items) { +- r = check_policy_items(items, m, ucred); ++ r = check_policy_items(items, filter); + if (r != DUNNO) +- return r == ALLOW; ++ return r; + } + } + +- r = check_policy_items(p->default_items, m, ucred); +- if (r != DUNNO) +- return r == ALLOW; ++ return check_policy_items(p->default_items, filter); ++} ++ ++bool policy_check_own(Policy *p, const struct ucred *ucred, const char *name) { ++ ++ struct policy_check_filter filter = { ++ .class = POLICY_ITEM_OWN, ++ .ucred = ucred, ++ .member = name, ++ }; ++ ++ return policy_check(p, &filter) == ALLOW; ++} ++ ++bool policy_check_hello(Policy *p, const struct ucred *ucred) { ++ ++ struct policy_check_filter filter = { ++ .class = POLICY_ITEM_USER, ++ .ucred = ucred, ++ }; ++ int user, group; ++ ++ user = policy_check(p, &filter); ++ if (user == DENY) ++ return false; ++ ++ filter.class = POLICY_ITEM_GROUP; ++ group = policy_check(p, &filter); ++ if (user == DUNNO && group == DUNNO) ++ return false; ++ ++ return !(user == DENY || group == DENY); ++} ++ ++bool policy_check_recv(Policy *p, ++ const struct ucred *ucred, ++ Hashmap *names, ++ int message_type, ++ const char *path, ++ const char *interface, ++ const char *member) { ++ ++ struct policy_check_filter filter = { ++ .class = POLICY_ITEM_RECV, ++ .ucred = ucred, ++ .names_hash = names, ++ .message_type = message_type, ++ .interface = interface, ++ .path = path, ++ .member = member, ++ }; ++ ++ return policy_check(p, &filter) == ALLOW; ++} + +- return false; ++bool policy_check_send(Policy *p, ++ const struct ucred *ucred, ++ char **names, ++ int message_type, ++ const char *path, ++ const char *interface, ++ const char *member) { ++ ++ struct policy_check_filter filter = { ++ .class = POLICY_ITEM_SEND, ++ .ucred = ucred, ++ .names_strv = names, ++ .message_type = message_type, ++ .interface = interface, ++ .path = path, ++ .member = member, ++ }; ++ ++ return policy_check(p, &filter) == ALLOW; + } + + int policy_load(Policy *p, char **files) { +diff --git a/src/bus-proxyd/bus-policy.h b/src/bus-proxyd/bus-policy.h +index 2222716e7a..5b4d9d0c10 100644 +--- a/src/bus-proxyd/bus-policy.h ++++ b/src/bus-proxyd/bus-policy.h +@@ -76,7 +76,22 @@ typedef struct Policy { + int policy_load(Policy *p, char **files); + void policy_free(Policy *p); + +-bool policy_check(Policy *p, sd_bus_message *m, const struct ucred *c); ++bool policy_check_own(Policy *p, const struct ucred *ucred, const char *name); ++bool policy_check_hello(Policy *p, const struct ucred *ucred); ++bool policy_check_recv(Policy *p, ++ const struct ucred *ucred, ++ Hashmap *names, ++ int message_type, ++ const char *path, ++ const char *interface, ++ const char *member); ++bool policy_check_send(Policy *p, ++ const struct ucred *ucred, ++ char **names, ++ int message_type, ++ const char *path, ++ const char *interface, ++ const char *member); + + void policy_dump(Policy *p); + +diff --git a/src/bus-proxyd/test-bus-policy.c b/src/bus-proxyd/test-bus-policy.c +index ed17bfe96e..37e66274f0 100644 +--- a/src/bus-proxyd/test-bus-policy.c ++++ b/src/bus-proxyd/test-bus-policy.c +@@ -44,122 +44,84 @@ + + #include + +-static int make_name_request(sd_bus *bus, +- const char *name, +- sd_bus_message **ret) { +- +- int r; +- sd_bus_message *m = NULL; +- +- r = sd_bus_message_new_method_call(bus, &m, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "RequestName"); +- if (r < 0) +- return r; +- +- r = sd_bus_message_append_basic(m, 's', name); +- if (r < 0) +- return r; +- +- m->sealed = 1; +- sd_bus_message_rewind(m, true); +- +- *ret = m; +- return 0; +-} +- + int main(int argc, char *argv[]) { + + Policy p = {}; +- sd_bus_message *m; + struct ucred ucred = {}; +- _cleanup_bus_close_unref_ sd_bus *bus = NULL;; +- +- assert_se(sd_bus_default_system(&bus) >= 0); +- +- /* Fake pid for policy checks */ +- ucred.pid = 1; ++ char **names_strv; ++ Hashmap *names_hash; + + /* Ownership tests */ + assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/ownerships.conf")) == 0); + +- assert_se(make_name_request(bus, "org.test.test1", &m) == 0); + ucred.uid = 0; +- assert_se(policy_check(&p, m, &ucred) == true); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test1") == true); + ucred.uid = 1; +- assert_se(policy_check(&p, m, &ucred) == true); +- assert_se(sd_bus_message_unref(m) == 0); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test1") == true); + +- assert_se(make_name_request(bus, "org.test.test2", &m) == 0); + ucred.uid = 0; +- assert_se(policy_check(&p, m, &ucred) == true); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test2") == true); + ucred.uid = 1; +- assert_se(policy_check(&p, m, &ucred) == false); +- assert_se(sd_bus_message_unref(m) == 0); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test2") == false); + +- assert_se(make_name_request(bus, "org.test.test3", &m) == 0); + ucred.uid = 0; +- assert_se(policy_check(&p, m, &ucred) == false); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test3") == false); + ucred.uid = 1; +- assert_se(policy_check(&p, m, &ucred) == false); +- assert_se(sd_bus_message_unref(m) == 0); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test3") == false); + +- assert_se(make_name_request(bus, "org.test.test4", &m) == 0); + ucred.uid = 0; +- assert_se(policy_check(&p, m, &ucred) == false); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test4") == false); + ucred.uid = 1; +- assert_se(policy_check(&p, m, &ucred) == true); +- assert_se(sd_bus_message_unref(m) == 0); ++ assert_se(policy_check_own(&p, &ucred, "org.test.test4") == true); + + policy_free(&p); + +- /* Signal test */ ++ /* Signaltest */ + assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/signals.conf")) == 0); ++ names_strv = STRV_MAKE("bli.bla.blubb"); + +- assert_se(sd_bus_message_new_signal(bus, &m, "/an/object/path", "bli.bla.blubb", "Name") == 0); + ucred.uid = 0; +- assert_se(policy_check(&p, m, &ucred) == true); ++ assert_se(policy_check_send(&p, &ucred, names_strv, SD_BUS_MESSAGE_SIGNAL, NULL, "/an/object/path", NULL) == true); + + ucred.uid = 1; +- assert_se(policy_check(&p, m, &ucred) == false); +- assert_se(sd_bus_message_unref(m) == 0); ++ assert_se(policy_check_send(&p, &ucred, names_strv, SD_BUS_MESSAGE_SIGNAL, NULL, "/an/object/path", NULL) == false); + + policy_free(&p); + + /* Method calls */ + assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/methods.conf")) == 0); ++ names_strv = STRV_MAKE("org.test.test1"); ++ policy_dump(&p); + + ucred.uid = 0; +- assert_se(sd_bus_message_new_method_call(bus, &m, "org.foo.bar", "/an/object/path", "bli.bla.blubb", "Member") == 0); +- assert_se(policy_check(&p, m, &ucred) == false); +- +- assert_se(sd_bus_message_new_method_call(bus, &m, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == 0); +- assert_se(policy_check(&p, m, &ucred) == false); + +- bus->is_kernel = 1; +- assert_se(sd_bus_message_new_method_call(bus, &m, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == 0); +- assert_se(policy_check(&p, m, &ucred) == true); ++ assert_se(policy_check_send(&p, &ucred, names_strv, SD_BUS_MESSAGE_METHOD_CALL, "/an/object/path", "bli.bla.blubb", "Member") == false); ++ assert_se(policy_check_send(&p, &ucred, names_strv, SD_BUS_MESSAGE_METHOD_CALL, "/an/object/path", "bli.bla.blubb", "Member") == false); ++ assert_se(policy_check_send(&p, &ucred, names_strv, SD_BUS_MESSAGE_METHOD_CALL, "/an/object/path", "org.test.int1", "Member") == true); ++ assert_se(policy_check_send(&p, &ucred, names_strv, SD_BUS_MESSAGE_METHOD_CALL, "/an/object/path", "org.test.int2", "Member") == true); + +- assert_se(sd_bus_message_new_method_call(bus, &m, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == 0); +- assert_se(policy_check(&p, m, &ucred) == true); ++ names_hash = hashmap_new(&string_hash_ops); ++ assert(names_hash != NULL); ++ assert_se(hashmap_put(names_hash, "org.test.test3", NULL) >= 0); ++ assert_se(policy_check_recv(&p, &ucred, names_hash, SD_BUS_MESSAGE_METHOD_CALL, "/an/object/path", "org.test.int3", "Member111") == true); + + policy_free(&p); + + /* User and groups */ + assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/hello.conf")) == 0); +- assert_se(sd_bus_message_new_method_call(bus, &m, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "Hello") == 0); + policy_dump(&p); + + ucred.uid = 0; +- assert_se(policy_check(&p, m, &ucred) == true); ++ assert_se(policy_check_hello(&p, &ucred) == true); + + ucred.uid = 1; +- assert_se(policy_check(&p, m, &ucred) == false); ++ assert_se(policy_check_hello(&p, &ucred) == false); + + ucred.uid = 0; + ucred.gid = 1; +- assert_se(policy_check(&p, m, &ucred) == false); ++ assert_se(policy_check_hello(&p, &ucred) == false); + + policy_free(&p); + +- + return EXIT_SUCCESS; + } +diff --git a/test/bus-policy/methods.conf b/test/bus-policy/methods.conf +index d6c28c71bc..4d4675ea10 100644 +--- a/test/bus-policy/methods.conf ++++ b/test/bus-policy/methods.conf +@@ -10,6 +10,8 @@ + + + ++ ++ + + + diff --git a/0378-fileio-make-parse_env_file-return-number-of-parsed-i.patch b/0378-fileio-make-parse_env_file-return-number-of-parsed-i.patch new file mode 100644 index 0000000..10329a2 --- /dev/null +++ b/0378-fileio-make-parse_env_file-return-number-of-parsed-i.patch @@ -0,0 +1,156 @@ +From a5f6c30da3ac58081108221bf8a0f6f1d84b33a9 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 22 Sep 2014 09:38:38 +0200 +Subject: [PATCH] fileio: make parse_env_file() return number of parsed items + +This commit introduces possibility to call parse_env_file_internal() and hand +over extra argument where we will accumulate how many items were successfully +parsed and pushed by callback. We make use of this in parse_env_file() and +return number of parsed items on success instead of always returning zero. + +As a side-effect this commit should fix bug that locale settings in +/etc/locale.conf are not overriden by options passed via kernel command line. +--- + src/shared/fileio.c | 40 +++++++++++++++++++++++++++------------- + 1 file changed, 27 insertions(+), 13 deletions(-) + +diff --git a/src/shared/fileio.c b/src/shared/fileio.c +index 18960abf02..38028b972e 100644 +--- a/src/shared/fileio.c ++++ b/src/shared/fileio.c +@@ -296,8 +296,9 @@ static int parse_env_file_internal( + const char *fname, + const char *newline, + int (*push) (const char *filename, unsigned line, +- const char *key, char *value, void *userdata), +- void *userdata) { ++ const char *key, char *value, void *userdata, int *n_pushed), ++ void *userdata, ++ int *n_pushed) { + + _cleanup_free_ char *contents = NULL, *key = NULL; + size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; +@@ -386,7 +387,7 @@ static int parse_env_file_internal( + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + +- r = push(fname, line, key, value, userdata); ++ r = push(fname, line, key, value, userdata, n_pushed); + if (r < 0) + goto fail; + +@@ -431,7 +432,7 @@ static int parse_env_file_internal( + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + +- r = push(fname, line, key, value, userdata); ++ r = push(fname, line, key, value, userdata, n_pushed); + if (r < 0) + goto fail; + +@@ -566,7 +567,7 @@ static int parse_env_file_internal( + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + +- r = push(fname, line, key, value, userdata); ++ r = push(fname, line, key, value, userdata, n_pushed); + if (r < 0) + goto fail; + } +@@ -581,7 +582,8 @@ fail: + static int parse_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, +- void *userdata) { ++ void *userdata, ++ int *n_pushed) { + + const char *k; + va_list aq, *ap = userdata; +@@ -613,6 +615,10 @@ static int parse_env_file_push( + va_end(aq); + free(*v); + *v = value; ++ ++ if (n_pushed) ++ (*n_pushed)++; ++ + return 1; + } + } +@@ -628,22 +634,23 @@ int parse_env_file( + const char *newline, ...) { + + va_list ap; +- int r; ++ int r, n_pushed = 0; + + if (!newline) + newline = NEWLINE; + + va_start(ap, newline); +- r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap); ++ r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed); + va_end(ap); + +- return r; ++ return r < 0 ? r : n_pushed; + } + + static int load_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, +- void *userdata) { ++ void *userdata, ++ int *n_pushed) { + char ***m = userdata; + char *p; + int r; +@@ -670,6 +677,9 @@ static int load_env_file_push( + if (r < 0) + return r; + ++ if (n_pushed) ++ (*n_pushed)++; ++ + free(value); + return 0; + } +@@ -681,7 +691,7 @@ int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) { + if (!newline) + newline = NEWLINE; + +- r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m); ++ r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL); + if (r < 0) { + strv_free(m); + return r; +@@ -694,7 +704,8 @@ int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) { + static int load_env_file_push_pairs( + const char *filename, unsigned line, + const char *key, char *value, +- void *userdata) { ++ void *userdata, ++ int *n_pushed) { + char ***m = userdata; + int r; + +@@ -726,6 +737,9 @@ static int load_env_file_push_pairs( + return r; + } + ++ if (n_pushed) ++ (*n_pushed)++; ++ + return 0; + } + +@@ -736,7 +750,7 @@ int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ** + if (!newline) + newline = NEWLINE; + +- r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m); ++ r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL); + if (r < 0) { + strv_free(m); + return r; diff --git a/0379-localectl-print-warning-when-there-are-options-given.patch b/0379-localectl-print-warning-when-there-are-options-given.patch new file mode 100644 index 0000000..f029118 --- /dev/null +++ b/0379-localectl-print-warning-when-there-are-options-given.patch @@ -0,0 +1,238 @@ +From a34286684ebb78dd3db0d7f34feb2c121c9d00cc Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 24 Sep 2014 13:17:43 +0200 +Subject: [PATCH] localectl: print warning when there are options given on + kernel cmdline + +--- + src/core/locale-setup.c | 47 +++++---------------------------------------- + src/locale/localectl.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ + src/shared/locale-util.c | 20 +++++++++++++++++++ + src/shared/locale-util.h | 25 ++++++++++++++++++++++++ + 4 files changed, 100 insertions(+), 42 deletions(-) + +diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c +index 7a4103504f..5177dbfd08 100644 +--- a/src/core/locale-setup.c ++++ b/src/core/locale-setup.c +@@ -30,48 +30,11 @@ + #include "fileio.h" + #include "strv.h" + #include "env-util.h" +- +-enum { +- /* We don't list LC_ALL here on purpose. People should be +- * using LANG instead. */ +- +- VARIABLE_LANG, +- VARIABLE_LANGUAGE, +- VARIABLE_LC_CTYPE, +- VARIABLE_LC_NUMERIC, +- VARIABLE_LC_TIME, +- VARIABLE_LC_COLLATE, +- VARIABLE_LC_MONETARY, +- VARIABLE_LC_MESSAGES, +- VARIABLE_LC_PAPER, +- VARIABLE_LC_NAME, +- VARIABLE_LC_ADDRESS, +- VARIABLE_LC_TELEPHONE, +- VARIABLE_LC_MEASUREMENT, +- VARIABLE_LC_IDENTIFICATION, +- _VARIABLE_MAX +-}; +- +-static const char * const variable_names[_VARIABLE_MAX] = { +- [VARIABLE_LANG] = "LANG", +- [VARIABLE_LANGUAGE] = "LANGUAGE", +- [VARIABLE_LC_CTYPE] = "LC_CTYPE", +- [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", +- [VARIABLE_LC_TIME] = "LC_TIME", +- [VARIABLE_LC_COLLATE] = "LC_COLLATE", +- [VARIABLE_LC_MONETARY] = "LC_MONETARY", +- [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", +- [VARIABLE_LC_PAPER] = "LC_PAPER", +- [VARIABLE_LC_NAME] = "LC_NAME", +- [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", +- [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", +- [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", +- [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" +-}; ++#include "locale-util.h" + + int locale_setup(char ***environment) { + char **add; +- char *variables[_VARIABLE_MAX] = {}; ++ char *variables[_VARIABLE_LC_MAX] = {}; + int r = 0, i; + + if (detect_container(NULL) <= 0) { +@@ -121,13 +84,13 @@ int locale_setup(char ***environment) { + } + + add = NULL; +- for (i = 0; i < _VARIABLE_MAX; i++) { ++ for (i = 0; i < _VARIABLE_LC_MAX; i++) { + char *s; + + if (!variables[i]) + continue; + +- s = strjoin(variable_names[i], "=", variables[i], NULL); ++ s = strjoin(locale_variable_to_string(i), "=", variables[i], NULL); + if (!s) { + r = -ENOMEM; + goto finish; +@@ -157,7 +120,7 @@ int locale_setup(char ***environment) { + finish: + strv_free(add); + +- for (i = 0; i < _VARIABLE_MAX; i++) ++ for (i = 0; i < _VARIABLE_LC_MAX; i++) + free(variables[i]); + + return r; +diff --git a/src/locale/localectl.c b/src/locale/localectl.c +index bf8b7b2bef..5917364d7c 100644 +--- a/src/locale/localectl.c ++++ b/src/locale/localectl.c +@@ -43,6 +43,8 @@ + #include "path-util.h" + #include "utf8.h" + #include "def.h" ++#include "virt.h" ++#include "fileio.h" + #include "locale-util.h" + + static bool arg_no_pager = false; +@@ -81,6 +83,53 @@ typedef struct StatusInfo { + const char *x11_options; + } StatusInfo; + ++static void print_overriden_variables(void) { ++ int r; ++ char *variables[_VARIABLE_LC_MAX] = {}; ++ LocaleVariable j; ++ bool print_warning = true; ++ ++ if (detect_container(NULL) > 0 || arg_host) ++ return; ++ ++ r = parse_env_file("/proc/cmdline", WHITESPACE, ++ "locale.LANG", &variables[VARIABLE_LANG], ++ "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], ++ "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], ++ "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], ++ "locale.LC_TIME", &variables[VARIABLE_LC_TIME], ++ "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], ++ "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], ++ "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], ++ "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], ++ "locale.LC_NAME", &variables[VARIABLE_LC_NAME], ++ "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], ++ "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], ++ "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], ++ "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], ++ NULL); ++ ++ if (r < 0 && r != -ENOENT) { ++ log_warning("Failed to read /proc/cmdline: %s", strerror(-r)); ++ goto finish; ++ } ++ ++ for (j = VARIABLE_LANG; j < _VARIABLE_LC_MAX; j++) ++ if (variables[j]) { ++ if (print_warning) { ++ printf("Warning: Settings on Kernel Command Line override system locale settings in /etc/locale.conf\n"); ++ printf(" Command Line: %s=%s\n", locale_variable_to_string(j), variables[j]); ++ ++ print_warning = false; ++ continue; ++ } ++ printf(" %s=%s\n", locale_variable_to_string(j), variables[j]); ++ } ++ finish: ++ for (j = VARIABLE_LANG; j < _VARIABLE_LC_MAX; j++) ++ free(variables[j]); ++} ++ + static void print_status_info(StatusInfo *i) { + assert(i); + +@@ -134,6 +183,7 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { + goto fail; + } + ++ print_overriden_variables(); + print_status_info(&info); + + fail: +diff --git a/src/shared/locale-util.c b/src/shared/locale-util.c +index 68851ae13d..d5eaff3d9e 100644 +--- a/src/shared/locale-util.c ++++ b/src/shared/locale-util.c +@@ -25,6 +25,7 @@ + #include "util.h" + #include "utf8.h" + #include "strv.h" ++#include "util.h" + + #include "locale-util.h" + +@@ -203,3 +204,22 @@ bool locale_is_valid(const char *name) { + + return true; + } ++ ++static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { ++ [VARIABLE_LANG] = "LANG", ++ [VARIABLE_LANGUAGE] = "LANGUAGE", ++ [VARIABLE_LC_CTYPE] = "LC_CTYPE", ++ [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", ++ [VARIABLE_LC_TIME] = "LC_TIME", ++ [VARIABLE_LC_COLLATE] = "LC_COLLATE", ++ [VARIABLE_LC_MONETARY] = "LC_MONETARY", ++ [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", ++ [VARIABLE_LC_PAPER] = "LC_PAPER", ++ [VARIABLE_LC_NAME] = "LC_NAME", ++ [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", ++ [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", ++ [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", ++ [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" ++}; ++ ++DEFINE_STRING_TABLE_LOOKUP(locale_variable, LocaleVariable); +diff --git a/src/shared/locale-util.h b/src/shared/locale-util.h +index 7be9af2b4e..d7a3e4fae6 100644 +--- a/src/shared/locale-util.h ++++ b/src/shared/locale-util.h +@@ -21,5 +21,30 @@ + along with systemd; If not, see . + ***/ + ++typedef enum LocaleVariable { ++ /* We don't list LC_ALL here on purpose. People should be ++ * using LANG instead. */ ++ ++ VARIABLE_LANG, ++ VARIABLE_LANGUAGE, ++ VARIABLE_LC_CTYPE, ++ VARIABLE_LC_NUMERIC, ++ VARIABLE_LC_TIME, ++ VARIABLE_LC_COLLATE, ++ VARIABLE_LC_MONETARY, ++ VARIABLE_LC_MESSAGES, ++ VARIABLE_LC_PAPER, ++ VARIABLE_LC_NAME, ++ VARIABLE_LC_ADDRESS, ++ VARIABLE_LC_TELEPHONE, ++ VARIABLE_LC_MEASUREMENT, ++ VARIABLE_LC_IDENTIFICATION, ++ _VARIABLE_LC_MAX, ++ _VARIABLE_LC_INVALID = -1 ++} LocaleVariable; ++ + int get_locales(char ***l); + bool locale_is_valid(const char *name); ++ ++const char* locale_variable_to_string(LocaleVariable i) _const_; ++LocaleVariable locale_variable_from_string(const char *s) _pure_; diff --git a/0380-bus-proxyd-add-some-asserts.patch b/0380-bus-proxyd-add-some-asserts.patch new file mode 100644 index 0000000..a296ac0 --- /dev/null +++ b/0380-bus-proxyd-add-some-asserts.patch @@ -0,0 +1,124 @@ +From 94a2c2f64a1379ca5c9ce4dbbee45ce17250ab51 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 25 Sep 2014 15:49:43 +0200 +Subject: [PATCH] bus-proxyd: add some asserts + +Both as documentation, and to make Coverity happy. + +Fixes CID #1241495 and #1241496. +--- + src/bus-proxyd/bus-policy.c | 19 +++++++++++++++++++ + src/bus-proxyd/bus-proxyd.c | 8 ++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 165e763f57..0de7680d4b 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -611,11 +611,16 @@ struct policy_check_filter { + + 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: +@@ -643,21 +648,29 @@ static int check_policy_item(PolicyItem *i, const struct policy_check_filter *fi + return is_permissive(i); + + case POLICY_ITEM_OWN: ++ assert(filter->member); ++ + if (streq(i->name, filter->member)) + return is_permissive(i); + break; + + case POLICY_ITEM_OWN_PREFIX: ++ assert(filter->member); ++ + if (startswith(i->name, filter->member)) + return is_permissive(i); + break; + + case POLICY_ITEM_USER: ++ assert(filter->ucred); ++ + if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->ucred->uid))) + return is_permissive(i); + break; + + case POLICY_ITEM_GROUP: ++ assert(filter->ucred); ++ + if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->ucred->gid))) + return is_permissive(i); + break; +@@ -675,6 +688,9 @@ static int check_policy_items(PolicyItem *items, const struct policy_check_filte + PolicyItem *i; + int r, ret = DUNNO; + ++ assert(items); ++ 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) { +@@ -694,6 +710,9 @@ static int policy_check(Policy *p, const struct policy_check_filter *filter) { + PolicyItem *items; + int r; + ++ assert(p); ++ assert(filter); ++ + /* + * The policy check is implemented by the following logic: + * +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +index a5387bb234..6a0fc7edfb 100644 +--- a/src/bus-proxyd/bus-proxyd.c ++++ b/src/bus-proxyd/bus-proxyd.c +@@ -373,6 +373,8 @@ static int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + ++ assert(call); ++ + if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + return 0; + +@@ -387,6 +389,8 @@ static int synthetic_reply_method_errno(sd_bus_message *call, int error, const s + + _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; + +@@ -402,6 +406,8 @@ static 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; + +@@ -426,6 +432,8 @@ static int synthetic_reply_return_strv(sd_bus_message *call, char **l) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + ++ assert(call); ++ + r = sd_bus_message_new_method_return(call, &m); + if (r < 0) + return synthetic_reply_method_errno(call, r, NULL); diff --git a/0381-shared-path-util-try-to-make-PATH_FORECH_PREFIX-look.patch b/0381-shared-path-util-try-to-make-PATH_FORECH_PREFIX-look.patch new file mode 100644 index 0000000..206f0f7 --- /dev/null +++ b/0381-shared-path-util-try-to-make-PATH_FORECH_PREFIX-look.patch @@ -0,0 +1,32 @@ +From 4a690c47260ca507bbcf92e2a68f66d3ec9a23fb Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 25 Sep 2014 16:12:41 +0200 +Subject: [PATCH] shared: path-util - try to make PATH_FORECH_PREFIX look less + wrong + +We replace the idiom "X && !(*foo = 0)" with "X && ((*foo = 0), true)". + +This is not a functional change, but should hopefully make it less +likely that people and static analyzers believe there is a typo here +(i.e., to make it clear that the intention was not "X && *foo != 0"). + +Thanks to David Herrmann for the suggestion. +--- + src/shared/path-util.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index d85291bb44..8d171a57ec 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -65,8 +65,8 @@ int fsck_exists(const char *fstype); + * the tree, to root. Also returns "" (and not "/"!) for the root + * directory. Excludes the specified directory itself */ + #define PATH_FOREACH_PREFIX(prefix, path) \ +- for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && !(*_slash = 0); _slash = strrchr((prefix), '/')) ++ for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) + + /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ + #define PATH_FOREACH_PREFIX_MORE(prefix, path) \ +- for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && !(*_slash = 0); _slash = strrchr((prefix), '/')) ++ for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) diff --git a/0382-bus-proxy-drop-one-wrong-assert.patch b/0382-bus-proxy-drop-one-wrong-assert.patch new file mode 100644 index 0000000..879e38e --- /dev/null +++ b/0382-bus-proxy-drop-one-wrong-assert.patch @@ -0,0 +1,21 @@ +From 4a3bb599609d687e0a501a748bfac491f5fb9f6c Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 25 Sep 2014 16:21:36 +0200 +Subject: [PATCH] bus-proxy: drop one wrong assert() + +--- + src/bus-proxyd/bus-policy.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c +index 0de7680d4b..2ff5d646f1 100644 +--- a/src/bus-proxyd/bus-policy.c ++++ b/src/bus-proxyd/bus-policy.c +@@ -688,7 +688,6 @@ static int check_policy_items(PolicyItem *items, const struct policy_check_filte + PolicyItem *i; + int r, ret = DUNNO; + +- assert(items); + assert(filter); + + /* Check all policies in a set - a broader one might be followed by a more specific one, diff --git a/0383-readahead-wipe-out-readahead.patch b/0383-readahead-wipe-out-readahead.patch new file mode 100644 index 0000000..cc3a03b --- /dev/null +++ b/0383-readahead-wipe-out-readahead.patch @@ -0,0 +1,3368 @@ +From d6bc8348d5be8576a475ac8ced2b0146e60fb71f Mon Sep 17 00:00:00 2001 +From: Daniel Buch +Date: Tue, 26 Aug 2014 21:17:22 +0200 +Subject: [PATCH] readahead: wipe out readahead + +--- + 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 | 22 +- + 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-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-udev-hwdb-update.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, 24 insertions(+), 2676 deletions(-) + delete mode 100644 man/sd-readahead.xml + delete mode 100644 man/sd_readahead.xml + delete mode 100644 man/systemd-readahead-replay.service.xml + delete mode 120000 src/readahead/Makefile + delete mode 100644 src/readahead/readahead-analyze.c + delete mode 100644 src/readahead/readahead-collect.c + delete mode 100644 src/readahead/readahead-common.c + delete mode 100644 src/readahead/readahead-common.h + delete mode 100644 src/readahead/readahead-replay.c + delete mode 100644 src/readahead/readahead.c + delete mode 100644 src/readahead/sd-readahead.c + delete mode 100644 src/readahead/test-ssd.c + delete mode 100644 src/systemd/sd-readahead.h + delete mode 100644 units/systemd-readahead-collect.service.in + delete mode 100644 units/systemd-readahead-done.service.in + delete mode 100644 units/systemd-readahead-done.timer + delete mode 100644 units/systemd-readahead-drop.service + delete mode 100644 units/systemd-readahead-replay.service.in + +diff --git a/Makefile-man.am b/Makefile-man.am +index 5c27937152..1be6d3aafa 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -1141,34 +1141,6 @@ 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 \ +@@ -1549,7 +1521,6 @@ 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 \ +@@ -1591,7 +1562,6 @@ EXTRA_DIST += \ + man/sd_login_monitor_new.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 \ +@@ -1647,7 +1617,6 @@ 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 6b2ca29ce8..53128518b4 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2346,8 +2346,7 @@ systemctl_LDADD = \ + + # ------------------------------------------------------------------------------ + systemd_notify_SOURCES = \ +- src/notify/notify.c \ +- src/readahead/sd-readahead.c ++ src/notify/notify.c + + systemd_notify_LDADD = \ + libsystemd-internal.la \ +@@ -4333,57 +4332,6 @@ EXTRA_DIST += \ + 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 = \ + src/bootchart/bootchart.c \ +diff --git a/configure.ac b/configure.ac +index 38a165c101..84644e163f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -842,14 +842,6 @@ 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])) + if test "x$enable_bootchart" != "xno"; then +@@ -1341,7 +1333,6 @@ 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 d78a1151c5..5f331e740a 100644 +--- a/man/sd-daemon.xml ++++ b/man/sd-daemon.xml +@@ -140,7 +140,6 @@ + systemd.service5, + systemd.socket5, + fprintf3, +- sd-readahead3, + pkg-config1 + + +diff --git a/man/sd-login.xml b/man/sd-login.xml +index d8d45048ed..f21170db16 100644 +--- a/man/sd-login.xml ++++ b/man/sd-login.xml +@@ -131,7 +131,6 @@ + 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 +deleted file mode 100644 +index bcc46b24d8..0000000000 +--- a/man/sd-readahead.xml ++++ /dev/null +@@ -1,117 +0,0 @@ +- +- +- +- +- +- +- +- +- 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 +deleted file mode 100644 +index 98272997cb..0000000000 +--- a/man/sd_readahead.xml ++++ /dev/null +@@ -1,178 +0,0 @@ +- +- +- +- +- +- +- +- +- 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 69baae0dce..684f490099 100644 +--- a/man/systemd-notify.xml ++++ b/man/systemd-notify.xml +@@ -141,17 +141,6 @@ + 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 +deleted file mode 100644 +index 669fe78942..0000000000 +--- a/man/systemd-readahead-replay.service.xml ++++ /dev/null +@@ -1,203 +0,0 @@ +- +- +- +- +- +- +- +- +- 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 b552029b82..51254ec533 100644 +--- a/po/POTFILES.skip ++++ b/po/POTFILES.skip +@@ -17,6 +17,5 @@ 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 06f03bd1e7..58b1c7b4e5 100644 +--- a/shell-completion/zsh/_systemd ++++ b/shell-completion/zsh/_systemd +@@ -63,8 +63,7 @@ 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]' \ +- '--readahead=[Controls disk read-ahead operations]:arguments:(cancel done noreply)' ++ '--booted[Returns 0 if the system was booted up with systemd]' + ;; + systemd-tty-ask-password-agent) + _arguments \ +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index 3233e15f4e..137b7876d6 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -131,7 +131,7 @@ static int create_disk( + "Conflicts=umount.target\n" + "BindsTo=dev-mapper-%i.device\n" + "IgnoreOnIsolate=true\n" +- "After=systemd-readahead-collect.service systemd-readahead-replay.service cryptsetup-pre.target\n", ++ "After=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 25d868aa87..539e2e64b5 100644 +--- a/src/gpt-auto-generator/gpt-auto-generator.c ++++ b/src/gpt-auto-generator/gpt-auto-generator.c +@@ -144,7 +144,6 @@ 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 33933e4bf6..a0f757a252 100644 +--- a/src/notify/notify.c ++++ b/src/notify/notify.c +@@ -31,7 +31,6 @@ + #include "strv.h" + #include "util.h" + #include "log.h" +-#include "sd-readahead.h" + #include "build.h" + #include "env-util.h" + +@@ -39,7 +38,6 @@ 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" +@@ -49,8 +47,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 Returns 0 if the system was booted up with systemd, non-zero otherwise\n" +- " --readahead=ACTION Controls read-ahead operations\n", ++ " --booted Returns 0 if the system was booted up with systemd, non-zero otherwise\n", + program_invocation_short_name); + } + +@@ -62,7 +59,6 @@ static int parse_argv(int argc, char *argv[]) { + ARG_PID, + ARG_STATUS, + ARG_BOOTED, +- ARG_READAHEAD + }; + + static const struct option options[] = { +@@ -72,7 +68,6 @@ 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 }, + {} + }; + +@@ -118,10 +113,6 @@ static int parse_argv(int argc, char *argv[]) { + arg_booted = true; + break; + +- case ARG_READAHEAD: +- arg_readahead = optarg; +- break; +- + case '?': + return -EINVAL; + +@@ -134,8 +125,7 @@ static int parse_argv(int argc, char *argv[]) { + !arg_ready && + !arg_status && + !arg_pid && +- !arg_booted && +- !arg_readahead) { ++ !arg_booted) { + help(); + return -EINVAL; + } +@@ -160,14 +150,6 @@ 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 +deleted file mode 120000 +index d0b0e8e008..0000000000 +--- a/src/readahead/Makefile ++++ /dev/null +@@ -1 +0,0 @@ +-../Makefile +\ No newline at end of file +diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c +deleted file mode 100644 +index 76db3cb7e4..0000000000 +--- a/src/readahead/readahead-analyze.c ++++ /dev/null +@@ -1,146 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index 822a803a41..0000000000 +--- a/src/readahead/readahead-collect.c ++++ /dev/null +@@ -1,650 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index 3ca48a7257..0000000000 +--- a/src/readahead/readahead-common.c ++++ /dev/null +@@ -1,398 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index b34f3aadd7..0000000000 +--- a/src/readahead/readahead-common.h ++++ /dev/null +@@ -1,61 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index f81e0fe55d..0000000000 +--- a/src/readahead/readahead-replay.c ++++ /dev/null +@@ -1,281 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index 35176e9379..0000000000 +--- a/src/readahead/readahead.c ++++ /dev/null +@@ -1,163 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index 675d82cdd1..0000000000 +--- a/src/readahead/sd-readahead.c ++++ /dev/null +@@ -1,89 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index 808faf359c..0000000000 +--- a/src/readahead/test-ssd.c ++++ /dev/null +@@ -1,41 +0,0 @@ +-/*-*- 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 +deleted file mode 100644 +index bb30f9a45e..0000000000 +--- a/src/systemd/sd-readahead.h ++++ /dev/null +@@ -1,73 +0,0 @@ +-/*-*- 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 e4a9e17cb7..ada9dbbf4f 100644 +--- a/system-preset/90-systemd.preset ++++ b/system-preset/90-systemd.preset +@@ -10,7 +10,6 @@ + + enable remote-fs.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 ab1d97da54..a1276e5b61 100644 +--- a/units/.gitignore ++++ b/units/.gitignore +@@ -47,9 +47,6 @@ + /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 43c145b726..f9691e2f2d 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-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service ++After=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 49a50a7feb..7d59a40195 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-readahead-collect.service systemd-readahead-replay.service systemd-quotacheck.service ++After=systemd-quotacheck.service + Before=local-fs.target shutdown.target + ConditionPathExists=@QUOTAON@ + +diff --git a/units/system-update.target b/units/system-update.target +index d0f847f957..48d46fcbda 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 systemd-readahead-collect.service systemd-readahead-replay.service ++Conflicts=shutdown.target + After=sysinit.target + Before=shutdown.target + AllowIsolate=yes +diff --git a/units/systemd-backlight@.service.in b/units/systemd-backlight@.service.in +index e945d8733f..ecf3de48d7 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-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service ++After=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 02dfe774df..34a5d5237b 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=systemd-readahead-collect.service systemd-readahead-replay.service proc-sys-fs-binfmt_misc.automount ++After=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 6cdde5b82d..7a448ac936 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-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service systemd-sysusers.service ++After=systemd-remount-fs.service systemd-sysusers.service + Before=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 26cce5131e..6d7657853e 100644 +--- a/units/systemd-fsck-root.service.in ++++ b/units/systemd-fsck-root.service.in +@@ -9,7 +9,6 @@ + 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 d2cda6a466..857e625679 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=systemd-readahead-collect.service systemd-readahead-replay.service %i.device systemd-fsck-root.service local-fs-pre.target ++After=%i.device systemd-fsck-root.service local-fs-pre.target + Before=shutdown.target + + [Service] +diff --git a/units/systemd-journal-catalog-update.service.in b/units/systemd-journal-catalog-update.service.in +index 0cb7076f12..bfa5e6b435 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=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target ++After=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 32deb52e26..040a0febe8 100644 +--- a/units/systemd-modules-load.service.in ++++ b/units/systemd-modules-load.service.in +@@ -10,7 +10,6 @@ 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 f726ea1bcd..5cb9bc3bc9 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-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service ++After=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 1879b2f24c..b55844b36f 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-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service ++After=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 +deleted file mode 100644 +index d4b8e67932..0000000000 +--- a/units/systemd-readahead-collect.service.in ++++ /dev/null +@@ -1,28 +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=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 +deleted file mode 100644 +index e0d9579449..0000000000 +--- a/units/systemd-readahead-done.service.in ++++ /dev/null +@@ -1,22 +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=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 +deleted file mode 100644 +index c58e09616e..0000000000 +--- a/units/systemd-readahead-done.timer ++++ /dev/null +@@ -1,22 +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=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 +deleted file mode 100644 +index d9d12bc533..0000000000 +--- a/units/systemd-readahead-drop.service ++++ /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=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 +deleted file mode 100644 +index c64a533e4e..0000000000 +--- a/units/systemd-readahead-replay.service.in ++++ /dev/null +@@ -1,26 +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=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 70e1a8680a..8d9daacaa5 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-readahead-collect.service systemd-readahead-replay.service systemd-fsck-root.service ++After=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 9d264a2bca..0e9851bf2e 100644 +--- a/units/systemd-rfkill@.service.in ++++ b/units/systemd-rfkill@.service.in +@@ -11,7 +11,7 @@ Documentation=man:systemd-rfkill@.service(8) + DefaultDependencies=no + RequiresMountsFor=/var/lib/systemd/rfkill + Conflicts=shutdown.target +-After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service ++After=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 ade9dc3007..fa72085f9e 100644 +--- a/units/systemd-sysctl.service.in ++++ b/units/systemd-sysctl.service.in +@@ -10,7 +10,6 @@ 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 69fea11fb1..ffd6d7747b 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-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service ++After=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 31b2378410..133c8c94c4 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=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target time-sync.target ++After=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 06346d3b7c..f3833fdfd5 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-readahead-collect.service systemd-readahead-replay.service systemd-sysusers.service ++After=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 72ab083d54..e895cda0e6 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=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target systemd-sysusers.service ++After=local-fs.target systemd-sysusers.service + Before=sysinit.target shutdown.target + RefuseManualStop=yes + +diff --git a/units/systemd-udev-hwdb-update.service.in b/units/systemd-udev-hwdb-update.service.in +index 153d93c7e5..cdbcd837cd 100644 +--- a/units/systemd-udev-hwdb-update.service.in ++++ b/units/systemd-udev-hwdb-update.service.in +@@ -10,7 +10,7 @@ Description=Rebuild Hardware Database + Documentation=man:udev(7) man:systemd-udevd.service(8) + DefaultDependencies=no + Conflicts=shutdown.target +-After=systemd-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service ++After=systemd-remount-fs.service + Before=sysinit.target shutdown.target systemd-update-done.service + ConditionNeedsUpdate=/etc + +diff --git a/units/systemd-update-done.service.in b/units/systemd-update-done.service.in +index 7031bff614..ec7d906392 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=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target ++After=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 da7dda76ba..163eccd91f 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-readahead-collect.service systemd-readahead-replay.service systemd-remount-fs.service systemd-tmpfiles-setup.service auditd.service ++After=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 18faa63f28..6160361871 100644 +--- a/units/systemd-vconsole-setup.service.in ++++ b/units/systemd-vconsole-setup.service.in +@@ -10,7 +10,6 @@ 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/0384-delta-warn-if-diff-failed.patch b/0384-delta-warn-if-diff-failed.patch new file mode 100644 index 0000000..c357428 --- /dev/null +++ b/0384-delta-warn-if-diff-failed.patch @@ -0,0 +1,34 @@ +From 3d1b90bd7fb562fdb3d15e0d7750ae0c36bc15b6 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 25 Sep 2014 18:16:04 +0200 +Subject: [PATCH] delta: warn if diff failed + +Found by Coverity. Fixes CID #1237541. +--- + src/delta/delta.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/delta/delta.c b/src/delta/delta.c +index 91f8592b40..2fdbeeae81 100644 +--- a/src/delta/delta.c ++++ b/src/delta/delta.c +@@ -159,7 +159,7 @@ static int notify_override_unchanged(const char *f) { + + static int found_override(const char *top, const char *bottom) { + _cleanup_free_ char *dest = NULL; +- int k; ++ int k, r; + pid_t pid; + + assert(top); +@@ -194,7 +194,9 @@ static int found_override(const char *top, const char *bottom) { + _exit(1); + } + +- wait_for_terminate(pid, NULL); ++ r = wait_for_terminate(pid, NULL); ++ if (r < 0) ++ log_warning("Failed to wait for diff: %s", strerror(-r)); + + putchar('\n'); + diff --git a/0385-nspawn-check-some-more-return-values.patch b/0385-nspawn-check-some-more-return-values.patch new file mode 100644 index 0000000..6d9a497 --- /dev/null +++ b/0385-nspawn-check-some-more-return-values.patch @@ -0,0 +1,219 @@ +From 79d80fc1466512d0ca211f4bfcd9de5f2f816a5a Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 25 Sep 2014 18:49:56 +0200 +Subject: [PATCH] nspawn: check some more return values + +Most of these failures would anyway get caught later on, but now the error messages are a bit more +specific. +--- + src/nspawn/nspawn.c | 120 +++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 96 insertions(+), 24 deletions(-) + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index c22d0cb598..4c1cfabca4 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -675,7 +675,18 @@ static int mount_all(const char *dest) { + if (mount_table[k].what && t > 0) + continue; + +- mkdir_p(where, 0755); ++ t = mkdir_p(where, 0755); ++ if (t < 0) { ++ if (mount_table[k].fatal) { ++ log_error("Failed to create directory %s: %s", where, strerror(-t)); ++ ++ if (r == 0) ++ r = t; ++ } else ++ log_warning("Failed to create directory %s: %s", where, strerror(-t)); ++ ++ continue; ++ } + + #ifdef HAVE_SELINUX + if (arg_selinux_apifs_context && +@@ -694,13 +705,15 @@ static int mount_all(const char *dest) { + where, + mount_table[k].type, + mount_table[k].flags, +- o) < 0 && +- mount_table[k].fatal) { ++ o) < 0) { + +- log_error("mount(%s) failed: %m", where); ++ if (mount_table[k].fatal) { ++ log_error("mount(%s) failed: %m", where); + +- if (r == 0) +- r = -errno; ++ if (r == 0) ++ r = -errno; ++ } else ++ log_warning("mount(%s) failed: %m", where); + } + } + +@@ -743,15 +756,35 @@ static int mount_binds(const char *dest, char **l, bool ro) { + + /* Create the mount point, but be conservative -- refuse to create block + * and char devices. */ +- if (S_ISDIR(source_st.st_mode)) +- mkdir_label(where, 0755); +- else if (S_ISFIFO(source_st.st_mode)) +- mkfifo(where, 0644); +- else if (S_ISSOCK(source_st.st_mode)) +- mknod(where, 0644 | S_IFSOCK, 0); +- else if (S_ISREG(source_st.st_mode)) +- touch(where); +- else { ++ if (S_ISDIR(source_st.st_mode)) { ++ r = mkdir_label(where, 0755); ++ if (r < 0) { ++ log_error("Failed to create mount point %s: %s", where, strerror(-r)); ++ ++ return r; ++ } ++ } else if (S_ISFIFO(source_st.st_mode)) { ++ r = mkfifo(where, 0644); ++ if (r < 0 && errno != EEXIST) { ++ log_error("Failed to create mount point %s: %m", where); ++ ++ return -errno; ++ } ++ } else if (S_ISSOCK(source_st.st_mode)) { ++ r = mknod(where, 0644 | S_IFSOCK, 0); ++ if (r < 0 && errno != EEXIST) { ++ log_error("Failed to create mount point %s: %m", where); ++ ++ return -errno; ++ } ++ } else if (S_ISREG(source_st.st_mode)) { ++ r = touch(where); ++ if (r < 0) { ++ log_error("Failed to create mount point %s: %s", where, strerror(-r)); ++ ++ return r; ++ } ++ } else { + log_error("Refusing to create mountpoint for file: %s", *x); + return -ENOTSUP; + } +@@ -778,12 +811,18 @@ static int mount_tmpfs(const char *dest) { + + STRV_FOREACH_PAIR(i, o, arg_tmpfs) { + _cleanup_free_ char *where = NULL; ++ int r; + + where = strappend(dest, *i); + if (!where) + return log_oom(); + +- mkdir_label(where, 0755); ++ r = mkdir_label(where, 0755); ++ if (r < 0) { ++ log_error("creating mount point for tmpfs %s failed: %s", where, strerror(-r)); ++ ++ return r; ++ } + + if (mount("tmpfs", where, "tmpfs", MS_NODEV|MS_STRICTATIME, *o) < 0) { + log_error("tmpfs mount to %s failed: %m", where); +@@ -844,8 +883,19 @@ static int setup_timezone(const char *dest) { + if (!what) + return log_oom(); + +- mkdir_parents(where, 0755); +- unlink(where); ++ r = mkdir_parents(where, 0755); ++ if (r < 0) { ++ log_error("Failed to create directory for timezone info %s in container: %s", where, strerror(-r)); ++ ++ return 0; ++ } ++ ++ r = unlink(where); ++ if (r < 0 && errno != ENOENT) { ++ log_error("Failed to remove existing timezone info %s in container: %m", where); ++ ++ return 0; ++ } + + if (symlink(what, where) < 0) { + log_error("Failed to correct timezone of container: %m"); +@@ -857,6 +907,7 @@ static int setup_timezone(const char *dest) { + + static int setup_resolv_conf(const char *dest) { + _cleanup_free_ char *where = NULL; ++ int r; + + assert(dest); + +@@ -870,8 +921,19 @@ static int setup_resolv_conf(const char *dest) { + + /* We don't really care for the results of this really. If it + * fails, it fails, but meh... */ +- mkdir_parents(where, 0755); +- copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644); ++ r = mkdir_parents(where, 0755); ++ if (r < 0) { ++ log_warning("Failed to create parent directory for resolv.conf %s: %s", where, strerror(-r)); ++ ++ return 0; ++ } ++ ++ r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644); ++ if (r < 0) { ++ log_warning("Failed to copy /etc/resolv.conf to %s: %s", where, strerror(-r)); ++ ++ return 0; ++ } + + return 0; + } +@@ -895,7 +957,11 @@ static int setup_volatile_state(const char *directory) { + } + + p = strappenda(directory, "/var"); +- mkdir(p, 0755); ++ r = mkdir(p, 0755); ++ if (r < 0 && errno != EEXIST) { ++ log_error("Failed to create %s: %m", directory); ++ return -errno; ++ } + + if (mount("tmpfs", p, "tmpfs", MS_STRICTATIME, "mode=755") < 0) { + log_error("Failed to mount tmpfs to /var: %m"); +@@ -935,7 +1001,13 @@ static int setup_volatile(const char *directory) { + f = strappenda(directory, "/usr"); + t = strappenda(template, "/usr"); + +- mkdir(t, 0755); ++ r = mkdir(t, 0755); ++ if (r < 0 && errno != EEXIST) { ++ log_error("Failed to create %s: %m", t); ++ r = -errno; ++ goto fail; ++ } ++ + if (mount(f, t, "bind", MS_BIND|MS_REC, NULL) < 0) { + log_error("Failed to create /usr bind mount: %m"); + r = -errno; +@@ -1294,7 +1366,7 @@ static int setup_journal(const char *directory) { + + r = mkdir_p(q, 0755); + if (r < 0) +- log_warning("failed to create directory %s: %m", q); ++ log_warning("Failed to create directory %s: %m", q); + return 0; + } + +@@ -1329,7 +1401,7 @@ static int setup_journal(const char *directory) { + + r = mkdir_p(q, 0755); + if (r < 0) +- log_warning("failed to create directory %s: %m", q); ++ log_warning("Failed to create directory %s: %m", q); + return 0; + } + diff --git a/0386-journal-remote-initialize-writer-hashmap-before-use.patch b/0386-journal-remote-initialize-writer-hashmap-before-use.patch new file mode 100644 index 0000000..c50cba0 --- /dev/null +++ b/0386-journal-remote-initialize-writer-hashmap-before-use.patch @@ -0,0 +1,39 @@ +From 22259a00fdb54dee818eeb1019421e2c516a330d Mon Sep 17 00:00:00 2001 +From: Jonathan Liu +Date: Wed, 24 Sep 2014 23:59:06 +1000 +Subject: [PATCH] journal-remote: initialize writer hashmap before use + +https://bugs.freedesktop.org/show_bug.cgi?id=83682 + +[zj: move the initalization even earlier, before any sockets are + looked at.] +--- + src/journal-remote/journal-remote.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index f06c2cb249..ad87783510 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -819,6 +819,10 @@ static int remoteserver_init(RemoteServer *s, + assert(server == NULL); + server = s; + ++ r = init_writer_hashmap(s); ++ if (r < 0) ++ return r; ++ + n = sd_listen_fds(true); + if (n < 0) { + log_error("Failed to read listening file descriptors from environment: %s", +@@ -942,10 +946,6 @@ static int remoteserver_init(RemoteServer *s, + return -EINVAL; + } + +- r = init_writer_hashmap(s); +- if (r < 0) +- return r; +- + if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) { + /* In this case we know what the writer will be + called, so we can create it and verify that we can diff --git a/0387-journal-remote-fix-counting-of-events-written.patch b/0387-journal-remote-fix-counting-of-events-written.patch new file mode 100644 index 0000000..840cc42 --- /dev/null +++ b/0387-journal-remote-fix-counting-of-events-written.patch @@ -0,0 +1,130 @@ +From dd87b1840c966fd25b81a7aa1071e8488c624db8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:26:40 -0400 +Subject: [PATCH] journal-remote: fix counting of events written + +After recent changes the number was always reported as 0, because +the accounting was done server_destroy(), called after the message was +already printed. But even before this change, the counts were wrong +because seqnum start at 0 only for newly created journal files, so when +appending to existing files, the calculated count was wrong anyway. + +Also do some variable renaming for consistency and disable some low-level +debug messages. +--- + src/journal-remote/journal-remote-parse.c | 6 ++--- + src/journal-remote/journal-remote-write.c | 44 +++++++++++++++++-------------- + 2 files changed, 27 insertions(+), 23 deletions(-) + +diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c +index e7eb1516fb..224e8f140b 100644 +--- a/src/journal-remote/journal-remote-parse.c ++++ b/src/journal-remote/journal-remote-parse.c +@@ -367,7 +367,7 @@ int process_data(RemoteSource *source) { + assert(source->data_size == 0); + + r = get_data_size(source); +- log_debug("get_data_size() -> %d", r); ++ // log_debug("get_data_size() -> %d", r); + if (r < 0) + return r; + if (r == 0) { +@@ -386,7 +386,7 @@ int process_data(RemoteSource *source) { + assert(source->data_size > 0); + + r = get_data_data(source, &data); +- log_debug("get_data_data() -> %d", r); ++ // log_debug("get_data_data() -> %d", r); + if (r < 0) + return r; + if (r == 0) { +@@ -409,7 +409,7 @@ int process_data(RemoteSource *source) { + + case STATE_DATA_FINISH: + r = get_data_newline(source); +- log_debug("get_data_newline() -> %d", r); ++ // log_debug("get_data_newline() -> %d", r); + if (r < 0) + return r; + if (r == 0) { +diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c +index 8ede950bea..0139f851a5 100644 +--- a/src/journal-remote/journal-remote-write.c ++++ b/src/journal-remote/journal-remote-write.c +@@ -99,11 +99,8 @@ Writer* writer_free(Writer *w) { + journal_file_close(w->journal); + } + +- if (w->server) { +- w->server->event_count += w->seqnum; +- if (w->hashmap_key) +- hashmap_remove(w->server->writers, w->hashmap_key); +- } ++ if (w->server && w->hashmap_key) ++ hashmap_remove(w->server->writers, w->hashmap_key); + + free(w->hashmap_key); + +@@ -129,40 +126,47 @@ Writer* writer_ref(Writer *w) { + return w; + } + +- +-int writer_write(Writer *s, ++int writer_write(Writer *w, + struct iovec_wrapper *iovw, + dual_timestamp *ts, + bool compress, + bool seal) { + int r; + +- assert(s); ++ assert(w); + assert(iovw); + assert(iovw->count > 0); + +- if (journal_file_rotate_suggested(s->journal, 0)) { ++ if (journal_file_rotate_suggested(w->journal, 0)) { + log_info("%s: Journal header limits reached or header out-of-date, rotating", +- s->journal->path); +- r = do_rotate(&s->journal, compress, seal); ++ w->journal->path); ++ r = do_rotate(&w->journal, compress, seal); + if (r < 0) + return r; + } + +- r = journal_file_append_entry(s->journal, ts, iovw->iovec, iovw->count, +- &s->seqnum, NULL, NULL); +- if (r >= 0) ++ r = journal_file_append_entry(w->journal, ts, iovw->iovec, iovw->count, ++ &w->seqnum, NULL, NULL); ++ if (r >= 0) { ++ if (w->server) ++ w->server->event_count += 1; + return 1; ++ } + +- log_debug("%s: Write failed, rotating: %s", s->journal->path, strerror(-r)); +- r = do_rotate(&s->journal, compress, seal); ++ log_debug("%s: Write failed, rotating: %s", w->journal->path, strerror(-r)); ++ r = do_rotate(&w->journal, compress, seal); + if (r < 0) + return r; + else +- log_info("%s: Successfully rotated journal", s->journal->path); ++ log_info("%s: Successfully rotated journal", w->journal->path); + + log_debug("Retrying write."); +- r = journal_file_append_entry(s->journal, ts, iovw->iovec, iovw->count, +- &s->seqnum, NULL, NULL); +- return r < 0 ? r : 1; ++ r = journal_file_append_entry(w->journal, ts, iovw->iovec, iovw->count, ++ &w->seqnum, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ if (w->server) ++ w->server->event_count += 1; ++ return 1; + } diff --git a/0388-journal-build-fix-when-LZ4-is-enabled-but-XZ-is-not.patch b/0388-journal-build-fix-when-LZ4-is-enabled-but-XZ-is-not.patch new file mode 100644 index 0000000..02abc48 --- /dev/null +++ b/0388-journal-build-fix-when-LZ4-is-enabled-but-XZ-is-not.patch @@ -0,0 +1,22 @@ +From 10893a5cfa7d792ba171282c2ec46b85ed6aae0c Mon Sep 17 00:00:00 2001 +From: Gustavo Sverzut Barbieri +Date: Thu, 25 Sep 2014 18:08:02 -0300 +Subject: [PATCH] journal: build fix when LZ4 is enabled but XZ is not + +--- + src/journal/journal-file.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index da2ef3b795..6b4bf0d5ae 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -78,7 +78,7 @@ typedef struct JournalFile { + + Hashmap *chain_cache; + +-#ifdef HAVE_XZ ++#if defined(HAVE_XZ) || defined(HAVE_LZ4) + void *compress_buffer; + size_t compress_buffer_size; + #endif diff --git a/0389-man-sd_event_new-tweaks.patch b/0389-man-sd_event_new-tweaks.patch new file mode 100644 index 0000000..a65d527 --- /dev/null +++ b/0389-man-sd_event_new-tweaks.patch @@ -0,0 +1,71 @@ +From bfe6c07e1b6bd8bf63d662c60fb333a003bb97a1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:27:17 -0400 +Subject: [PATCH] man/sd_event_new: tweaks + +--- + man/sd_event_new.xml | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/man/sd_event_new.xml b/man/sd_event_new.xml +index bd495b63bf..3062f43e69 100644 +--- a/man/sd_event_new.xml ++++ b/man/sd_event_new.xml +@@ -86,7 +86,7 @@ along with systemd; If not, see . + event parameter. After use, drop + the returned reference with + sd_event_unref(). When the last reference is +- dropped, the event loop is freed. ++ dropped, the object is freed. + + sd_event_default() acquires a reference + to the default event loop object of the calling thread, possibly +@@ -100,23 +100,23 @@ along with systemd; If not, see . + recommended to use this call instead of + sd_event_new() in order to share event loop + objects between various components that are dispatched in the same +- thread. All threads either have exactly zero or one default event loop +- associated, but never more. ++ thread. All threads have exactly either zero or one default event loop ++ objects associated, but never more. + + sd_event_ref() increases the reference +- counter of the specified event loop object by one. ++ count of the specified event loop object by one. + + sd_event_unref() decreases the +- reference counter of the specified event loop object by one. If +- the counter hits zero, the event loop object is freed. Note that it ++ reference count of the specified event loop object by one. If ++ the count hits zero, the object is freed. Note that it + is freed regardless of whether it is the default event loop object for a + thread or not. This means that allocating an event loop with + sd_event_default(), then releasing it, and + then acquiring a new one with + sd_event_default() will result in two +- distinct objects. Note that, in order to free an event loop object, ++ distinct objects. Note that in order to free an event loop object, + all remaining event sources of the event loop also need to be +- freed as they each keep a reference to it. ++ freed as each keeps a reference to it. + + + +@@ -128,7 +128,7 @@ along with systemd; If not, see . + code. sd_event_ref() always returns a pointer + to the event loop object passed + in. sd_event_unref() always returns +- NULL. ++ NULL. + + + +@@ -140,7 +140,7 @@ along with systemd; If not, see . + + -ENOMEM + +- Not enough memory to allocate object ++ Not enough memory to allocate the object. + + + diff --git a/0390-build-sys-add-sd_session_get_desktop-to-Makefile-man.patch b/0390-build-sys-add-sd_session_get_desktop-to-Makefile-man.patch new file mode 100644 index 0000000..07f8926 --- /dev/null +++ b/0390-build-sys-add-sd_session_get_desktop-to-Makefile-man.patch @@ -0,0 +1,40 @@ +From 3a17521f5906b8028d6f01da99f0d84e442b02bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:27:21 -0400 +Subject: [PATCH] build-sys: add sd_session_get_desktop to Makefile-man.am + +Fixup for c72d5456e2d. +--- + Makefile-man.am | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/Makefile-man.am b/Makefile-man.am +index 1be6d3aafa..199c731e7e 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -1289,6 +1289,7 @@ MANPAGES_ALIAS += \ + man/sd_seat_can_tty.3 \ + man/sd_seat_get_sessions.3 \ + man/sd_session_get_class.3 \ ++ man/sd_session_get_desktop.3 \ + man/sd_session_get_display.3 \ + man/sd_session_get_remote_host.3 \ + man/sd_session_get_remote_user.3 \ +@@ -1330,6 +1331,7 @@ man/sd_seat_can_multi_session.3: man/sd_seat_get_active.3 + man/sd_seat_can_tty.3: man/sd_seat_get_active.3 + man/sd_seat_get_sessions.3: man/sd_seat_get_active.3 + man/sd_session_get_class.3: man/sd_session_is_active.3 ++man/sd_session_get_desktop.3: man/sd_session_is_active.3 + man/sd_session_get_display.3: man/sd_session_is_active.3 + man/sd_session_get_remote_host.3: man/sd_session_is_active.3 + man/sd_session_get_remote_user.3: man/sd_session_is_active.3 +@@ -1421,6 +1423,9 @@ man/sd_seat_get_sessions.html: man/sd_seat_get_active.html + man/sd_session_get_class.html: man/sd_session_is_active.html + $(html-alias) + ++man/sd_session_get_desktop.html: man/sd_session_is_active.html ++ $(html-alias) ++ + man/sd_session_get_display.html: man/sd_session_is_active.html + $(html-alias) + diff --git a/0391-man-add-sd_event_add_signal-3.patch b/0391-man-add-sd_event_add_signal-3.patch new file mode 100644 index 0000000..b9e4214 --- /dev/null +++ b/0391-man-add-sd_event_add_signal-3.patch @@ -0,0 +1,316 @@ +From 3144ebcad37422dd85220915d37e7e9eea36564a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:27:27 -0400 +Subject: [PATCH] man: add sd_event_add_signal(3) + +--- + Makefile-man.am | 7 ++ + man/sd_event_add_signal.xml | 196 ++++++++++++++++++++++++++++++++++++++++++++ + man/sd_event_add_time.xml | 24 ++++-- + 3 files changed, 221 insertions(+), 6 deletions(-) + create mode 100644 man/sd_event_add_signal.xml + +diff --git a/Makefile-man.am b/Makefile-man.am +index 199c731e7e..85a3612f39 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -741,6 +741,7 @@ MANPAGES += \ + man/sd_bus_open_user.3 \ + man/sd_bus_path_encode.3 \ + man/sd_bus_request_name.3 \ ++ man/sd_event_add_signal.3 \ + man/sd_event_add_time.3 \ + man/sd_event_new.3 \ + man/systemd-bus-proxyd.8 \ +@@ -802,6 +803,7 @@ MANPAGES_ALIAS += \ + man/sd_bus_unref.3 \ + man/sd_event_default.3 \ + man/sd_event_ref.3 \ ++ man/sd_event_source_get_signal.3 \ + man/sd_event_source_get_time.3 \ + man/sd_event_source_get_time_accuracy.3 \ + man/sd_event_source_get_time_clock.3 \ +@@ -865,6 +867,7 @@ man/sd_bus_release_name.3: man/sd_bus_request_name.3 + man/sd_bus_unref.3: man/sd_bus_new.3 + man/sd_event_default.3: man/sd_event_new.3 + man/sd_event_ref.3: man/sd_event_new.3 ++man/sd_event_source_get_signal.3: man/sd_event_add_signal.3 + man/sd_event_source_get_time.3: man/sd_event_add_time.3 + man/sd_event_source_get_time_accuracy.3: man/sd_event_add_time.3 + man/sd_event_source_get_time_clock.3: man/sd_event_add_time.3 +@@ -1040,6 +1043,9 @@ man/sd_event_default.html: man/sd_event_new.html + man/sd_event_ref.html: man/sd_event_new.html + $(html-alias) + ++man/sd_event_source_get_signal.html: man/sd_event_add_signal.html ++ $(html-alias) ++ + man/sd_event_source_get_time.html: man/sd_event_add_time.html + $(html-alias) + +@@ -1542,6 +1548,7 @@ EXTRA_DIST += \ + man/sd_bus_open_user.xml \ + man/sd_bus_path_encode.xml \ + man/sd_bus_request_name.xml \ ++ man/sd_event_add_signal.xml \ + man/sd_event_add_time.xml \ + man/sd_event_new.xml \ + man/sd_get_seats.xml \ +diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml +new file mode 100644 +index 0000000000..2344fb3c02 +--- /dev/null ++++ b/man/sd_event_add_signal.xml +@@ -0,0 +1,196 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd_event_add_signal ++ systemd ++ ++ ++ ++ More text ++ Zbigniew ++ Jędrzejewski-Szmek ++ zbyszek@in.waw.pl ++ ++ ++ ++ ++ ++ sd_event_add_signal ++ 3 ++ ++ ++ ++ sd_event_add_signal ++ sd_event_source_get_signal ++ ++ Add a signal event source to an event loop ++ ++ ++ ++ ++ #include <systemd/sd-bus.h> ++ ++ ++ int sd_event_add_signal ++ sd_event *event ++ sd_event_source **source ++ int signal ++ sd_event_signal_handler_t handler ++ void *userdata ++ ++ ++ ++ typedef int (*sd_event_signal_handler_t) ++ sd_event_source *s ++ const struct signalfd_siginfo *si ++ void *userdata ++ ++ ++ ++ int sd_event_source_get_signal ++ sd_event_source *source ++ ++ ++ ++ ++ ++ ++ Description ++ ++ sd_event_add_signal() adds a new signal ++ event source to an event loop object. The event loop is specified ++ in event, the event source is returned in ++ the source parameter. The ++ signal parameter specifies the signal to be handled ++ (see ++ signal7). ++ The handler must reference a function to ++ call when the signal is delivered or be NULL. ++ The handler function will be passed the ++ userdata pointer, which may be chosen ++ 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 ++ for futher information. ++ ++ Only a single handler may be installed for a specific ++ signal. The signal will be unblocked, and must be ++ blocked when the function is called. If the handler is not ++ specified (handler is ++ NULL), a default handler which causes the ++ program to exit will be used. By default, the handler is enabled ++ permanently (SD_EVENT_ON), but this may be ++ changed with ++ sd_event_source_set_enabled3. ++ If the handler function returns a negative error code, it will be ++ disabled after the invocation, even if ++ SD_EVENT_ON mode is set. ++ ++ ++ sd_event_source_get_signal() retrieves ++ the configured signal number of a signal event source created ++ previously with sd_event_add_signal(). It ++ takes the event source object as the source ++ parameter. ++ ++ ++ ++ ++ Return Value ++ ++ On success, these functions return 0 or a positive ++ integer. On failure, they return a negative errno-style error ++ code. ++ ++ ++ ++ Errors ++ ++ Returned errors may indicate the following problems: ++ ++ ++ ++ -ENOMEM ++ ++ Not enough memory to allocate an object. ++ ++ ++ ++ -EINVAL ++ ++ An invalid argument has been passed. ++ ++ ++ ++ ++ -EBUSY ++ ++ An handler is already installed for this ++ signal or the signal was not blocked previously. ++ ++ ++ ++ ++ -ESTALE ++ ++ The event loop is already terminated. ++ ++ ++ ++ ++ -ECHILD ++ ++ The event loop has been created in a different process. ++ ++ ++ ++ ++ ++ ++ ++ Notes ++ ++ sd_event_add_signal() and the other functions ++ described here are available as a shared library, which can be ++ compiled and linked to with the ++ libsystemd pkg-config1 ++ file. ++ ++ ++ ++ See Also ++ ++ ++ systemd1, ++ sd-event3, ++ sd_event_new3, ++ sd_event_add_time3, ++ sd_event_source_set_enabled3 ++ ++ ++ ++ +diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml +index a3304f7985..d3775e5d5f 100644 +--- a/man/sd_event_add_time.xml ++++ b/man/sd_event_add_time.xml +@@ -69,6 +69,13 @@ along with systemd; If not, see . + + + ++ typedef int (*sd_event_time_handler_t) ++ sd_event_source *s ++ uint64_t usec ++ void *userdata ++ ++ ++ + int sd_event_source_get_time + sd_event_source *source + usec_t *usec +@@ -132,11 +139,15 @@ along with systemd; If not, see . + actually have been called at a slightly later time, subject to the + specified accuracy value, the kernel timer slack (see + prctl2) +- and additional scheduling latencies. By default, the timer will +- elapse once (SD_EVENT_ONESHOT), but this may be changed with +- sd_event_source_set_enabled3. If +- the handler function returns a negative error code, it will be +- disabled after the invocation, even if SD_EVENT_ON mode is set. ++ and additional scheduling latencies. ++ ++ By default, the timer will elapse once ++ (SD_EVENT_ONESHOT), but this may be changed ++ with ++ sd_event_source_set_enabled3. ++ If the handler function returns a negative error code, it will be ++ disabled after the invocation, even if ++ SD_EVENT_ON mode is set. + + + sd_event_source_get_time() retrieves +@@ -187,7 +198,7 @@ along with systemd; If not, see . + + -ENOMEM + +- Not enough memory to allocate object. ++ Not enough memory to allocate an object. + + + +@@ -237,6 +248,7 @@ along with systemd; If not, see . + systemd1, + sd-event3, + sd_event_new3, ++ sd_event_add_signal3, + clock_gettime2, + sd_event_source_set_enabled3 + diff --git a/0392-man-add-sd_event_add_child-3.patch b/0392-man-add-sd_event_add_child-3.patch new file mode 100644 index 0000000..c0963ed --- /dev/null +++ b/0392-man-add-sd_event_add_child-3.patch @@ -0,0 +1,294 @@ +From edf2573743b25273bee020230a60f1a054b8ec60 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:27:33 -0400 +Subject: [PATCH] man: add sd_event_add_child(3) + +--- + Makefile-man.am | 7 ++ + man/sd_event_add_child.xml | 205 ++++++++++++++++++++++++++++++++++++++++++++ + man/sd_event_add_signal.xml | 1 + + man/sd_event_add_time.xml | 1 + + 4 files changed, 214 insertions(+) + create mode 100644 man/sd_event_add_child.xml + +diff --git a/Makefile-man.am b/Makefile-man.am +index 85a3612f39..53e2f2cf17 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -741,6 +741,7 @@ MANPAGES += \ + man/sd_bus_open_user.3 \ + man/sd_bus_path_encode.3 \ + man/sd_bus_request_name.3 \ ++ man/sd_event_add_child.3 \ + man/sd_event_add_signal.3 \ + man/sd_event_add_time.3 \ + man/sd_event_new.3 \ +@@ -803,6 +804,7 @@ MANPAGES_ALIAS += \ + man/sd_bus_unref.3 \ + man/sd_event_default.3 \ + man/sd_event_ref.3 \ ++ man/sd_event_source_get_child_pid.3 \ + man/sd_event_source_get_signal.3 \ + man/sd_event_source_get_time.3 \ + man/sd_event_source_get_time_accuracy.3 \ +@@ -867,6 +869,7 @@ man/sd_bus_release_name.3: man/sd_bus_request_name.3 + man/sd_bus_unref.3: man/sd_bus_new.3 + man/sd_event_default.3: man/sd_event_new.3 + man/sd_event_ref.3: man/sd_event_new.3 ++man/sd_event_source_get_child_pid.3: man/sd_event_add_child.3 + man/sd_event_source_get_signal.3: man/sd_event_add_signal.3 + man/sd_event_source_get_time.3: man/sd_event_add_time.3 + man/sd_event_source_get_time_accuracy.3: man/sd_event_add_time.3 +@@ -1043,6 +1046,9 @@ man/sd_event_default.html: man/sd_event_new.html + man/sd_event_ref.html: man/sd_event_new.html + $(html-alias) + ++man/sd_event_source_get_child_pid.html: man/sd_event_add_child.html ++ $(html-alias) ++ + man/sd_event_source_get_signal.html: man/sd_event_add_signal.html + $(html-alias) + +@@ -1548,6 +1554,7 @@ EXTRA_DIST += \ + man/sd_bus_open_user.xml \ + man/sd_bus_path_encode.xml \ + man/sd_bus_request_name.xml \ ++ man/sd_event_add_child.xml \ + man/sd_event_add_signal.xml \ + man/sd_event_add_time.xml \ + man/sd_event_new.xml \ +diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml +new file mode 100644 +index 0000000000..a3b4d85ac8 +--- /dev/null ++++ b/man/sd_event_add_child.xml +@@ -0,0 +1,205 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd_event_add_child ++ systemd ++ ++ ++ ++ More text ++ Zbigniew ++ Jędrzejewski-Szmek ++ zbyszek@in.waw.pl ++ ++ ++ ++ ++ ++ sd_event_add_child ++ 3 ++ ++ ++ ++ sd_event_add_child ++ sd_event_source_get_child_pid ++ ++ Add a child state change event source to an event loop ++ ++ ++ ++ ++ #include <systemd/sd-bus.h> ++ ++ ++ int sd_event_add_child ++ sd_event *event ++ sd_event_source **source ++ pid_t pid ++ int options ++ sd_event_child_handler_t handler ++ void *userdata ++ ++ ++ ++ typedef int (*sd_event_child_handler_t) ++ sd_event_source *s ++ const siginfo_t *si ++ void *userdata ++ ++ ++ ++ int sd_event_source_get_child_pid ++ sd_event_source *source ++ pid_t *pid ++ ++ ++ ++ ++ ++ ++ Description ++ ++ sd_event_add_child() adds a new child ++ state change event source to an event loop object. The event loop ++ is specified in event, the event source is ++ returned in the source parameter. The ++ pid parameter specifies the process to ++ watch. The handler must reference a ++ function to call when the process changes state. The handler ++ function will be passed the userdata ++ pointer, which may be chosen freely by the caller. The handler ++ also receives a pointer to a const ++ siginfo_t structure containing the information about ++ the event. The options parameter determines ++ which state changes will be watched for. It must contain an OR-ed ++ mask of WEXITED (watch for the child ++ terminating), WSTOPPED (watch for the child ++ being stopped by a signal), and WCONTINUED ++ (watch for the child being resumed by a signal). See ++ waitid2 ++ for futher information. ++ ++ Only a single handler may be installed for a specific ++ child. The handler is enabled ++ for a single event (SD_EVENT_ONESHOT), ++ but this may be ++ changed with ++ sd_event_source_set_enabled3. ++ If the handler function returns a negative error code, it will be ++ disabled after the invocation, even if ++ SD_EVENT_ON mode is set. ++ ++ ++ sd_event_source_get_child_pid() ++ retrieves the configured pid of a child ++ state change event source created previously with ++ sd_event_add_child(). It takes the event ++ source object as the source parameter and a ++ pointer to pid_t to return the result in. ++ ++ ++ ++ ++ Return Value ++ ++ On success, these functions return 0 or a positive ++ integer. On failure, they return a negative errno-style error ++ code. ++ ++ ++ ++ Errors ++ ++ Returned errors may indicate the following problems: ++ ++ ++ ++ -ENOMEM ++ ++ Not enough memory to allocate an object. ++ ++ ++ ++ -EINVAL ++ ++ An invalid argument has been passed. This includes ++ specyfing an empty mask in options or a mask ++ which constains values different than a combination of ++ WEXITED, WSTOPPED, and ++ WCONTINUED. ++ ++ ++ ++ ++ ++ -EBUSY ++ ++ An handler is already installed for this ++ child. ++ ++ ++ ++ ++ -ESTALE ++ ++ The event loop is already terminated. ++ ++ ++ ++ ++ -ECHILD ++ ++ The event loop has been created in a different process. ++ ++ ++ ++ ++ ++ ++ ++ Notes ++ ++ sd_event_add_child() and the other functions ++ described here are available as a shared library, which can be ++ compiled and linked to with the ++ libsystemd pkg-config1 ++ file. ++ ++ ++ ++ See Also ++ ++ ++ systemd1, ++ sd-event3, ++ sd_event_new3, ++ sd_event_add_time3, ++ sd_event_add_signal3, ++ sd_event_source_set_enabled3 ++ ++ ++ ++ +diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml +index 2344fb3c02..2b656b67a2 100644 +--- a/man/sd_event_add_signal.xml ++++ b/man/sd_event_add_signal.xml +@@ -189,6 +189,7 @@ along with systemd; If not, see . + sd-event3, + sd_event_new3, + sd_event_add_time3, ++ sd_event_add_child3, + sd_event_source_set_enabled3 + + +diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml +index d3775e5d5f..e64ed8e207 100644 +--- a/man/sd_event_add_time.xml ++++ b/man/sd_event_add_time.xml +@@ -249,6 +249,7 @@ along with systemd; If not, see . + sd-event3, + sd_event_new3, + sd_event_add_signal3, ++ sd_event_add_child3, + clock_gettime2, + sd_event_source_set_enabled3 + diff --git a/0393-man-document-sd_event_add_-defer-post-exit.patch b/0393-man-document-sd_event_add_-defer-post-exit.patch new file mode 100644 index 0000000..723def8 --- /dev/null +++ b/0393-man-document-sd_event_add_-defer-post-exit.patch @@ -0,0 +1,298 @@ +From 4dfefc1914bad6a025e2d6738999e45b74715002 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:27:40 -0400 +Subject: [PATCH] man: document sd_event_add_{defer,post,exit} + +--- + Makefile-man.am | 12 +++ + man/sd_event_add_child.xml | 1 + + man/sd_event_add_defer.xml | 191 ++++++++++++++++++++++++++++++++++++++++++++ + man/sd_event_add_signal.xml | 1 + + man/sd_event_add_time.xml | 1 + + 5 files changed, 206 insertions(+) + create mode 100644 man/sd_event_add_defer.xml + +diff --git a/Makefile-man.am b/Makefile-man.am +index 53e2f2cf17..bd5306e676 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -742,6 +742,7 @@ MANPAGES += \ + man/sd_bus_path_encode.3 \ + man/sd_bus_request_name.3 \ + man/sd_event_add_child.3 \ ++ man/sd_event_add_defer.3 \ + man/sd_event_add_signal.3 \ + man/sd_event_add_time.3 \ + man/sd_event_new.3 \ +@@ -802,6 +803,8 @@ MANPAGES_ALIAS += \ + man/sd_bus_ref.3 \ + man/sd_bus_release_name.3 \ + man/sd_bus_unref.3 \ ++ man/sd_event_add_exit.3 \ ++ man/sd_event_add_post.3 \ + man/sd_event_default.3 \ + man/sd_event_ref.3 \ + man/sd_event_source_get_child_pid.3 \ +@@ -867,6 +870,8 @@ man/sd_bus_path_decode.3: man/sd_bus_path_encode.3 + man/sd_bus_ref.3: man/sd_bus_new.3 + man/sd_bus_release_name.3: man/sd_bus_request_name.3 + man/sd_bus_unref.3: man/sd_bus_new.3 ++man/sd_event_add_exit.3: man/sd_event_add_defer.3 ++man/sd_event_add_post.3: man/sd_event_add_defer.3 + man/sd_event_default.3: man/sd_event_new.3 + man/sd_event_ref.3: man/sd_event_new.3 + man/sd_event_source_get_child_pid.3: man/sd_event_add_child.3 +@@ -1040,6 +1045,12 @@ man/sd_bus_release_name.html: man/sd_bus_request_name.html + man/sd_bus_unref.html: man/sd_bus_new.html + $(html-alias) + ++man/sd_event_add_exit.html: man/sd_event_add_defer.html ++ $(html-alias) ++ ++man/sd_event_add_post.html: man/sd_event_add_defer.html ++ $(html-alias) ++ + man/sd_event_default.html: man/sd_event_new.html + $(html-alias) + +@@ -1555,6 +1566,7 @@ EXTRA_DIST += \ + man/sd_bus_path_encode.xml \ + man/sd_bus_request_name.xml \ + man/sd_event_add_child.xml \ ++ man/sd_event_add_defer.xml \ + man/sd_event_add_signal.xml \ + man/sd_event_add_time.xml \ + man/sd_event_new.xml \ +diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml +index a3b4d85ac8..f282a5094a 100644 +--- a/man/sd_event_add_child.xml ++++ b/man/sd_event_add_child.xml +@@ -198,6 +198,7 @@ along with systemd; If not, see . + sd_event_new3, + sd_event_add_time3, + sd_event_add_signal3, ++ sd_event_add_defer3, + sd_event_source_set_enabled3 + + +diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml +new file mode 100644 +index 0000000000..6c937098b2 +--- /dev/null ++++ b/man/sd_event_add_defer.xml +@@ -0,0 +1,191 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd_event_add_defer ++ systemd ++ ++ ++ ++ More text ++ Zbigniew ++ Jędrzejewski-Szmek ++ zbyszek@in.waw.pl ++ ++ ++ ++ ++ ++ sd_event_add_defer ++ 3 ++ ++ ++ ++ sd_event_add_defer ++ sd_event_add_post ++ sd_event_add_exit ++ ++ Add static event sources to an event loop ++ ++ ++ ++ ++ #include <systemd/sd-bus.h> ++ ++ ++ int sd_event_add_defer ++ sd_event *event ++ sd_event_source **source ++ sd_event_handler_t handler ++ void *userdata ++ ++ ++ ++ int sd_event_add_post ++ sd_event *event ++ sd_event_source **source ++ sd_event_handler_t handler ++ void *userdata ++ ++ ++ ++ int sd_event_add_exit ++ sd_event *event ++ sd_event_source **source ++ sd_event_handler_t handler ++ void *userdata ++ ++ ++ ++ typedef int (*sd_event_handler_t) ++ sd_event_source *s ++ void *userdata ++ ++ ++ ++ ++ ++ ++ Description ++ ++ Those three functions add new event sources to an event loop ++ object. The event loop is specified in ++ event, the event source is returned in the ++ source parameter. The event sources are ++ enabled statically and will "fire" when the event loop is run and ++ the conditions described below are met. The handler function will ++ be passed the userdata pointer, which may ++ be chosen freely by the caller. ++ ++ sd_event_add_defer() adds a new event ++ source that will "fire" the next time the event loop is run. By ++ default, the handler will be called once ++ (SD_EVENT_ONESHOT). ++ ++ sd_event_add_defer() adds a new event ++ source that will "fire" if any event handlers are invoked whenever ++ the event loop is run. By default, the source is enabled ++ permanently (SD_EVENT_ON). ++ ++ sd_event_add_exit() adds a new event ++ source that will "fire" when the event loop is terminated ++ with sd_event_exit(). ++ ++ The ++ sd_event_source_set_enabled3 ++ function may be used to enable the event source permanently ++ (SD_EVENT_ON) or to make it fire just once ++ (SD_EVENT_ONESHOT). If the handler function ++ returns a negative error code, it will be disabled after the ++ invocation, even if SD_EVENT_ON mode is ++ set. ++ ++ ++ ++ Return Value ++ ++ On success, this functions return 0 or a positive ++ integer. On failure, they return a negative errno-style error ++ code. ++ ++ ++ ++ Errors ++ ++ Returned errors may indicate the following problems: ++ ++ ++ ++ -ENOMEM ++ ++ Not enough memory to allocate an object. ++ ++ ++ ++ -EINVAL ++ ++ An invalid argument has been passed. ++ ++ ++ ++ -ESTALE ++ ++ The event loop is already terminated. ++ ++ ++ ++ -ECHILD ++ ++ The event loop has been created in a different process. ++ ++ ++ ++ ++ ++ ++ Notes ++ ++ Functions described here are available as a shared library, ++ which can be compiled and linked to with the ++ libsystemd pkg-config1 ++ file. ++ ++ ++ ++ See Also ++ ++ ++ systemd1, ++ sd-event3, ++ sd_event_new3, ++ sd_event_add_time3, ++ sd_event_add_signal3, ++ sd_event_add_child3, ++ sd_event_source_set_enabled3 ++ ++ ++ ++ +diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml +index 2b656b67a2..1517c1021c 100644 +--- a/man/sd_event_add_signal.xml ++++ b/man/sd_event_add_signal.xml +@@ -190,6 +190,7 @@ along with systemd; If not, see . + sd_event_new3, + sd_event_add_time3, + sd_event_add_child3, ++ sd_event_add_defer3, + sd_event_source_set_enabled3 + + +diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml +index e64ed8e207..f16b84f605 100644 +--- a/man/sd_event_add_time.xml ++++ b/man/sd_event_add_time.xml +@@ -250,6 +250,7 @@ along with systemd; If not, see . + sd_event_new3, + sd_event_add_signal3, + sd_event_add_child3, ++ sd_event_add_defer3, + clock_gettime2, + sd_event_source_set_enabled3 + diff --git a/0394-man-use-constant-markup-for-errno-value.patch b/0394-man-use-constant-markup-for-errno-value.patch new file mode 100644 index 0000000..1ea6b3f --- /dev/null +++ b/0394-man-use-constant-markup-for-errno-value.patch @@ -0,0 +1,514 @@ +From 8474b70c3a3842cdf3d51f331dd117ab6421f6d0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:27:46 -0400 +Subject: [PATCH] man: use markup for errno value + +We were inconsistent, but marking them up as constants makes more +sense then as variables. +--- + man/sd_bus_creds_get_pid.xml | 10 +++++----- + man/sd_bus_creds_new_from_pid.xml | 6 +++--- + man/sd_bus_error.xml | 4 ++-- + man/sd_bus_message_append_basic.xml | 10 +++++----- + man/sd_bus_message_get_cookie.xml | 4 ++-- + man/sd_bus_message_get_monotonic_usec.xml | 4 ++-- + man/sd_bus_negotiate_fds.xml | 2 +- + man/sd_bus_new.xml | 2 +- + man/sd_bus_open_user.xml | 4 ++-- + man/sd_bus_request_name.xml | 14 +++++++------- + man/sd_event_add_child.xml | 10 +++++----- + man/sd_event_add_defer.xml | 8 ++++---- + man/sd_event_add_signal.xml | 10 +++++----- + man/sd_event_add_time.xml | 10 +++++----- + man/sd_event_new.xml | 4 ++-- + 15 files changed, 51 insertions(+), 51 deletions(-) + +diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml +index 40ed81ecb0..6358762470 100644 +--- a/man/sd_bus_creds_get_pid.xml ++++ b/man/sd_bus_creds_get_pid.xml +@@ -381,7 +381,7 @@ along with systemd; If not, see . + + + +- -ENODATA ++ -ENODATA + + Given field is not available in + c. +@@ -389,7 +389,7 @@ along with systemd; If not, see . + + + +- -ENOENT ++ -ENOENT + + Given field is not specified for the sender. + This will be returned by sd_bus_get_unit, +@@ -403,7 +403,7 @@ along with systemd; If not, see . + + + +- -ENXIO ++ -ENXIO + + An error occurred in parsing cgroup paths. + libsystemd might be out of sync with +@@ -411,14 +411,14 @@ along with systemd; If not, see . + + + +- -EINVAL ++ -EINVAL + + Specified pointer parameter is NULL. + + + + +- -ENOMEM ++ -ENOMEM + + Memory allocation failed. + +diff --git a/man/sd_bus_creds_new_from_pid.xml b/man/sd_bus_creds_new_from_pid.xml +index bc94c44095..f3ea1defe1 100644 +--- a/man/sd_bus_creds_new_from_pid.xml ++++ b/man/sd_bus_creds_new_from_pid.xml +@@ -205,14 +205,14 @@ along with systemd; If not, see . + + + +- -ESRCH ++ -ESRCH + + Specified pid could not + be found. + + + +- -EINVAL ++ -EINVAL + + Specified parameter is invalid + (NULL in case of output +@@ -220,7 +220,7 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Memory allocation failed. + +diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml +index 7144f4ba32..aba80832d2 100644 +--- a/man/sd_bus_error.xml ++++ b/man/sd_bus_error.xml +@@ -376,7 +376,7 @@ along with systemd; If not, see . + + + +- -EINVAL ++ -EINVAL + + Error was already set in + sd_bus_error structure when one the +@@ -384,7 +384,7 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Memory allocation failed. + +diff --git a/man/sd_bus_message_append_basic.xml b/man/sd_bus_message_append_basic.xml +index 7c5f1e9ddc..2594134d87 100644 +--- a/man/sd_bus_message_append_basic.xml ++++ b/man/sd_bus_message_append_basic.xml +@@ -219,35 +219,35 @@ along with systemd; If not, see . + + + +- -EINVAL ++ -EINVAL + + Specified parameter is invalid. + + + + +- -EPERM ++ -EPERM + + Message has been sealed. + + + + +- -ESTALE ++ -ESTALE + + Message is in invalid state. + + + + +- -ENXIO ++ -ENXIO + + Message cannot be appended to. + + + + +- -ENOMEM ++ -ENOMEM + + Memory allocation failed. + +diff --git a/man/sd_bus_message_get_cookie.xml b/man/sd_bus_message_get_cookie.xml +index 641ecec659..3e3f9bd7be 100644 +--- a/man/sd_bus_message_get_cookie.xml ++++ b/man/sd_bus_message_get_cookie.xml +@@ -107,14 +107,14 @@ + + + +- -EINVAL ++ -EINVAL + + A specified parameter + is invalid. + + + +- -ENODATA ++ -ENODATA + + No cookie has been + assigned to this message. This either +diff --git a/man/sd_bus_message_get_monotonic_usec.xml b/man/sd_bus_message_get_monotonic_usec.xml +index 311ba55619..290faf2a5b 100644 +--- a/man/sd_bus_message_get_monotonic_usec.xml ++++ b/man/sd_bus_message_get_monotonic_usec.xml +@@ -139,14 +139,14 @@ + + + +- -EINVAL ++ -EINVAL + + A specified parameter + is invalid. + + + +- -ENODATA ++ -ENODATA + + No timestamp or + sequence number information is +diff --git a/man/sd_bus_negotiate_fds.xml b/man/sd_bus_negotiate_fds.xml +index c91318cd9d..fb313e34fb 100644 +--- a/man/sd_bus_negotiate_fds.xml ++++ b/man/sd_bus_negotiate_fds.xml +@@ -143,7 +143,7 @@ along with systemd; If not, see . + + + +- -EPERM ++ -EPERM + + The bus connection has already been started. + +diff --git a/man/sd_bus_new.xml b/man/sd_bus_new.xml +index 1f8d787eea..8c56dc0d20 100644 +--- a/man/sd_bus_new.xml ++++ b/man/sd_bus_new.xml +@@ -112,7 +112,7 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Memory allocation failed. + +diff --git a/man/sd_bus_open_user.xml b/man/sd_bus_open_user.xml +index 6cb4a314a5..47f8361486 100644 +--- a/man/sd_bus_open_user.xml ++++ b/man/sd_bus_open_user.xml +@@ -171,7 +171,7 @@ along with systemd; If not, see . + + + +- -EINVAL ++ -EINVAL + + Specified parameter is invalid + (NULL in case of output +@@ -179,7 +179,7 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Memory allocation failed. + +diff --git a/man/sd_bus_request_name.xml b/man/sd_bus_request_name.xml +index c23bbb37bc..ca082183cc 100644 +--- a/man/sd_bus_request_name.xml ++++ b/man/sd_bus_request_name.xml +@@ -143,7 +143,7 @@ + + + +- -EALREADY ++ -EALREADY + + The caller already is + the owner of the specified +@@ -151,7 +151,7 @@ + + + +- -EEXIST ++ -EEXIST + + The name has already + been acquired by a different peer, and +@@ -163,7 +163,7 @@ + + + +- -ESRCH ++ -ESRCH + + It was attempted to + release a name that is currently not +@@ -172,7 +172,7 @@ + + + +- -EADDRINUSE ++ -EADDRINUSE + + It was attempted to + release a name that is owned by a +@@ -181,21 +181,21 @@ + + + +- -EINVAL ++ -EINVAL + + A specified parameter + is invalid. + + + +- -ENOTCONN ++ -ENOTCONN + + The bus connection has + been disconnected. + + + +- -ECHILD ++ -ECHILD + + The bus connection has + been created in a different process +diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml +index f282a5094a..012fdb6a1a 100644 +--- a/man/sd_event_add_child.xml ++++ b/man/sd_event_add_child.xml +@@ -137,13 +137,13 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Not enough memory to allocate an object. + + + +- -EINVAL ++ -EINVAL + + An invalid argument has been passed. This includes + specyfing an empty mask in options or a mask +@@ -155,7 +155,7 @@ along with systemd; If not, see . + + + +- -EBUSY ++ -EBUSY + + An handler is already installed for this + child. +@@ -163,14 +163,14 @@ along with systemd; If not, see . + + + +- -ESTALE ++ -ESTALE + + The event loop is already terminated. + + + + +- -ECHILD ++ -ECHILD + + The event loop has been created in a different process. + +diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml +index 6c937098b2..442600a93e 100644 +--- a/man/sd_event_add_defer.xml ++++ b/man/sd_event_add_defer.xml +@@ -138,25 +138,25 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Not enough memory to allocate an object. + + + +- -EINVAL ++ -EINVAL + + An invalid argument has been passed. + + + +- -ESTALE ++ -ESTALE + + The event loop is already terminated. + + + +- -ECHILD ++ -ECHILD + + The event loop has been created in a different process. + +diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml +index 1517c1021c..6584268818 100644 +--- a/man/sd_event_add_signal.xml ++++ b/man/sd_event_add_signal.xml +@@ -134,20 +134,20 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Not enough memory to allocate an object. + + + +- -EINVAL ++ -EINVAL + + An invalid argument has been passed. + + + + +- -EBUSY ++ -EBUSY + + An handler is already installed for this + signal or the signal was not blocked previously. +@@ -155,14 +155,14 @@ along with systemd; If not, see . + + + +- -ESTALE ++ -ESTALE + + The event loop is already terminated. + + + + +- -ECHILD ++ -ECHILD + + The event loop has been created in a different process. + +diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml +index f16b84f605..77b8828bb3 100644 +--- a/man/sd_event_add_time.xml ++++ b/man/sd_event_add_time.xml +@@ -196,34 +196,34 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Not enough memory to allocate an object. + + + +- -EINVAL ++ -EINVAL + + An invalid argument has been passed. + + + + +- -ESTALE ++ -ESTALE + + The event loop is already terminated. + + + + +- -ECHILD ++ -ECHILD + + The event loop has been created in a different process. + + + + +- -ENOTSUP ++ -ENOTSUP + + The selected clock is not supported by the event loop implementation. + +diff --git a/man/sd_event_new.xml b/man/sd_event_new.xml +index 3062f43e69..d392ed30b0 100644 +--- a/man/sd_event_new.xml ++++ b/man/sd_event_new.xml +@@ -138,13 +138,13 @@ along with systemd; If not, see . + + + +- -ENOMEM ++ -ENOMEM + + Not enough memory to allocate the object. + + + +- -EMFILE ++ -EMFILE + + The maximum number of event loops has been allocated. + diff --git a/0395-only-build-and-install-systemd-bus-proxyd-if-enable-.patch b/0395-only-build-and-install-systemd-bus-proxyd-if-enable-.patch new file mode 100644 index 0000000..990b540 --- /dev/null +++ b/0395-only-build-and-install-systemd-bus-proxyd-if-enable-.patch @@ -0,0 +1,40 @@ +From ef99aec4d25087dec995b3f00b6957dcee6b13e9 Mon Sep 17 00:00:00 2001 +From: Gustavo Sverzut Barbieri +Date: Thu, 25 Sep 2014 18:13:19 -0300 +Subject: [PATCH] only build and install systemd-bus-proxyd if --enable-kdbus + +--- + Makefile.am | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 53128518b4..065d688ebb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -387,7 +387,6 @@ rootlibexec_PROGRAMS = \ + systemd-ac-power \ + systemd-sysctl \ + systemd-sleep \ +- systemd-bus-proxyd \ + systemd-socket-proxyd \ + systemd-update-done + +@@ -2428,6 +2427,10 @@ systemd_run_LDADD = \ + libsystemd-shared.la + + # ------------------------------------------------------------------------------ ++if ENABLE_KDBUS ++rootlibexec_PROGRAMS += \ ++ systemd-bus-proxyd ++ + systemd_bus_proxyd_SOURCES = \ + src/bus-proxyd/bus-proxyd.c \ + src/bus-proxyd/bus-policy.c \ +@@ -2449,7 +2452,6 @@ bus-proxyd-uninstall-hook: + INSTALL_EXEC_HOOKS += bus-proxyd-install-hook + UNINSTALL_EXEC_HOOKS += bus-proxyd-uninstall-hook + +-if ENABLE_KDBUS + nodist_systemunit_DATA += \ + units/systemd-bus-proxyd@.service + diff --git a/0396-build-sys-do-not-distribute-make-man-rules.py.patch b/0396-build-sys-do-not-distribute-make-man-rules.py.patch new file mode 100644 index 0000000..fcada1f --- /dev/null +++ b/0396-build-sys-do-not-distribute-make-man-rules.py.patch @@ -0,0 +1,23 @@ +From 0b094b10b4268383c836fa4f285e02ba25ed3ad0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 17:39:56 -0400 +Subject: [PATCH] build-sys: do not distribute make-man-rules.py + +It was added to EXTRA_DIST in 3c3e5f4276a893791110b03984735654372aa33a, +but this script only makes sense for developers. +--- + Makefile.am | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 065d688ebb..bf860cdc00 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -720,7 +720,6 @@ EXTRA_DIST += \ + $(man_MANS) \ + tools/make-man-index.py \ + tools/make-directive-index.py \ +- tools/make-man-rules.py \ + tools/xml_helper.py + + # ------------------------------------------------------------------------------ diff --git a/0397-do-not-install-factory-etc-pam.d-if-disable-pam.patch b/0397-do-not-install-factory-etc-pam.d-if-disable-pam.patch new file mode 100644 index 0000000..a54ca93 --- /dev/null +++ b/0397-do-not-install-factory-etc-pam.d-if-disable-pam.patch @@ -0,0 +1,25 @@ +From 2f88c8583aea6626c5f0a84cfc6de4b0a17f2d1c Mon Sep 17 00:00:00 2001 +From: Gustavo Sverzut Barbieri +Date: Thu, 25 Sep 2014 18:12:03 -0300 +Subject: [PATCH] do not install factory/etc/pam.d if --disable-pam + +--- + Makefile.am | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index bf860cdc00..1bdc91c239 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2048,9 +2048,11 @@ 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/0398-Revert-only-build-and-install-systemd-bus-proxyd-if-.patch b/0398-Revert-only-build-and-install-systemd-bus-proxyd-if-.patch new file mode 100644 index 0000000..2145f7f --- /dev/null +++ b/0398-Revert-only-build-and-install-systemd-bus-proxyd-if-.patch @@ -0,0 +1,44 @@ +From 440c61c500ead1bdc6f987b8ba7c5e7f7a9c9f59 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 25 Sep 2014 19:02:42 -0400 +Subject: [PATCH] Revert "only build and install systemd-bus-proxyd if + --enable-kdbus" + +This reverts commit ef99aec4d25087dec995b3f00b6957dcee6b13e9. + +systemd-stdio-bridge is used on non-kdbus systems. +--- + Makefile.am | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 1bdc91c239..0f54c5c014 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -387,6 +387,7 @@ rootlibexec_PROGRAMS = \ + systemd-ac-power \ + systemd-sysctl \ + systemd-sleep \ ++ systemd-bus-proxyd \ + systemd-socket-proxyd \ + systemd-update-done + +@@ -2428,10 +2429,6 @@ systemd_run_LDADD = \ + libsystemd-shared.la + + # ------------------------------------------------------------------------------ +-if ENABLE_KDBUS +-rootlibexec_PROGRAMS += \ +- systemd-bus-proxyd +- + systemd_bus_proxyd_SOURCES = \ + src/bus-proxyd/bus-proxyd.c \ + src/bus-proxyd/bus-policy.c \ +@@ -2453,6 +2450,7 @@ bus-proxyd-uninstall-hook: + INSTALL_EXEC_HOOKS += bus-proxyd-install-hook + UNINSTALL_EXEC_HOOKS += bus-proxyd-uninstall-hook + ++if ENABLE_KDBUS + nodist_systemunit_DATA += \ + units/systemd-bus-proxyd@.service + diff --git a/0399-make-utmp-wtmp-support-configurable.patch b/0399-make-utmp-wtmp-support-configurable.patch new file mode 100644 index 0000000..40662fd --- /dev/null +++ b/0399-make-utmp-wtmp-support-configurable.patch @@ -0,0 +1,303 @@ +From 37161c5148396448921841ae1026b281c7949652 Mon Sep 17 00:00:00 2001 +From: Emil Renner Berthing +Date: Wed, 24 Sep 2014 17:25:00 +0200 +Subject: [PATCH] make utmp/wtmp support configurable + +This adds --disable-utmp option to configure. If it is used, all +utmp-related functionality, including querying runlevel support, +is removed. +--- + Makefile-man.am | 29 +++++++++++++++++------------ + Makefile.am | 26 +++++++++++++++++++++----- + configure.ac | 11 +++++++++++ + man/runlevel.xml | 3 ++- + man/systemd-update-utmp.service.xml | 2 +- + src/core/build.h | 7 +++++++ + src/shared/utmp-wtmp.h | 28 ++++++++++++++++++++++++++++ + 7 files changed, 87 insertions(+), 19 deletions(-) + +diff --git a/Makefile-man.am b/Makefile-man.am +index bd5306e676..2b3fa95e70 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -23,7 +23,6 @@ MANPAGES += \ + man/machine-id.5 \ + man/machine-info.5 \ + man/os-release.5 \ +- man/runlevel.8 \ + man/sd-daemon.3 \ + man/sd-id128.3 \ + man/sd-journal.3 \ +@@ -93,7 +92,6 @@ MANPAGES += \ + man/systemd-tty-ask-password-agent.1 \ + man/systemd-udevd.service.8 \ + man/systemd-update-done.service.8 \ +- man/systemd-update-utmp.service.8 \ + man/systemd.1 \ + man/systemd.automount.5 \ + man/systemd.device.5 \ +@@ -227,8 +225,6 @@ MANPAGES_ALIAS += \ + man/systemd-udevd-kernel.socket.8 \ + man/systemd-udevd.8 \ + man/systemd-update-done.8 \ +- man/systemd-update-utmp-runlevel.service.8 \ +- man/systemd-update-utmp.8 \ + man/systemd-user.conf.5 + man/SD_ALERT.3: man/sd-daemon.3 + man/SD_CRIT.3: man/sd-daemon.3 +@@ -334,8 +330,6 @@ man/systemd-udevd-control.socket.8: man/systemd-udevd.service.8 + man/systemd-udevd-kernel.socket.8: man/systemd-udevd.service.8 + man/systemd-udevd.8: man/systemd-udevd.service.8 + man/systemd-update-done.8: man/systemd-update-done.service.8 +-man/systemd-update-utmp-runlevel.service.8: man/systemd-update-utmp.service.8 +-man/systemd-update-utmp.8: man/systemd-update-utmp.service.8 + man/systemd-user.conf.5: man/systemd-system.conf.5 + man/SD_ALERT.html: man/sd-daemon.html + $(html-alias) +@@ -649,12 +643,6 @@ man/systemd-udevd.html: man/systemd-udevd.service.html + man/systemd-update-done.html: man/systemd-update-done.service.html + $(html-alias) + +-man/systemd-update-utmp-runlevel.service.html: man/systemd-update-utmp.service.html +- $(html-alias) +- +-man/systemd-update-utmp.html: man/systemd-update-utmp.service.html +- $(html-alias) +- + man/systemd-user.conf.html: man/systemd-system.conf.html + $(html-alias) + +@@ -1509,6 +1497,23 @@ MANPAGES_ALIAS += \ + + endif + ++if HAVE_UTMP ++MANPAGES += \ ++ man/runlevel.8 \ ++ man/systemd-update-utmp.service.8 ++MANPAGES_ALIAS += \ ++ man/systemd-update-utmp-runlevel.service.8 \ ++ man/systemd-update-utmp.8 ++man/systemd-update-utmp-runlevel.service.8: man/systemd-update-utmp.service.8 ++man/systemd-update-utmp.8: man/systemd-update-utmp.service.8 ++man/systemd-update-utmp-runlevel.service.html: man/systemd-update-utmp.service.html ++ $(html-alias) ++ ++man/systemd-update-utmp.html: man/systemd-update-utmp.service.html ++ $(html-alias) ++ ++endif ++ + # Really, do not edit this file. + + EXTRA_DIST += \ +diff --git a/Makefile.am b/Makefile.am +index 0f54c5c014..e0cba76329 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -378,7 +378,6 @@ rootlibexec_PROGRAMS = \ + systemd \ + systemd-cgroups-agent \ + systemd-initctl \ +- systemd-update-utmp \ + systemd-shutdownd \ + systemd-shutdown \ + systemd-remount-fs \ +@@ -391,6 +390,11 @@ rootlibexec_PROGRAMS = \ + systemd-socket-proxyd \ + systemd-update-done + ++if HAVE_UTMP ++rootlibexec_PROGRAMS += \ ++ systemd-update-utmp ++endif ++ + systemgenerator_PROGRAMS = \ + systemd-getty-generator \ + systemd-fstab-generator \ +@@ -517,8 +521,6 @@ nodist_systemunit_DATA = \ + units/systemd-initctl.service \ + units/systemd-shutdownd.service \ + units/systemd-remount-fs.service \ +- units/systemd-update-utmp.service \ +- units/systemd-update-utmp-runlevel.service \ + units/systemd-ask-password-wall.service \ + units/systemd-ask-password-console.service \ + units/systemd-sysctl.service \ +@@ -544,6 +546,12 @@ nodist_systemunit_DATA = \ + units/systemd-nspawn@.service \ + units/systemd-update-done.service + ++if HAVE_UTMP ++nodist_systemunit_DATA += \ ++ units/systemd-update-utmp.service \ ++ units/systemd-update-utmp-runlevel.service ++endif ++ + dist_userunit_DATA = \ + units/user/basic.target \ + units/user/default.target \ +@@ -804,7 +812,6 @@ libsystemd_shared_la_SOURCES = \ + src/shared/cgroup-show.h \ + src/shared/unit-name.c \ + src/shared/unit-name.h \ +- src/shared/utmp-wtmp.c \ + src/shared/utmp-wtmp.h \ + src/shared/watchdog.c \ + src/shared/watchdog.h \ +@@ -878,6 +885,11 @@ libsystemd_shared_la_SOURCES = \ + src/shared/switch-root.c \ + src/shared/nss-util.h + ++if HAVE_UTMP ++libsystemd_shared_la_SOURCES += \ ++ src/shared/utmp-wtmp.c ++endif ++ + nodist_libsystemd_shared_la_SOURCES = \ + src/shared/errno-from-name.h \ + src/shared/errno-to-name.h \ +@@ -5856,6 +5868,7 @@ SOCKETS_TARGET_WANTS += \ + systemd-initctl.socket \ + systemd-shutdownd.socket + ++if HAVE_UTMP + if HAVE_SYSV_COMPAT + RUNLEVEL1_TARGET_WANTS += \ + systemd-update-utmp-runlevel.service +@@ -5870,7 +5883,10 @@ RUNLEVEL5_TARGET_WANTS += \ + endif + + SYSINIT_TARGET_WANTS += \ +- systemd-update-utmp.service \ ++ systemd-update-utmp.service ++endif ++ ++SYSINIT_TARGET_WANTS += \ + systemd-update-done.service + + LOCAL_FS_TARGET_WANTS += \ +diff --git a/configure.ac b/configure.ac +index 84644e163f..e33c8f75ac 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -346,6 +346,16 @@ AS_IF([test "x$enable_dbus" != "xno"], [ + AM_CONDITIONAL(HAVE_DBUS, [test "$have_dbus" = "yes"]) + + # ------------------------------------------------------------------------------ ++have_utmp=yes ++AC_ARG_ENABLE([utmp], AS_HELP_STRING([--disable-utmp], [disable utmp/wtmp log handling]), ++ AS_CASE("x${enableval}", ++ [xyes], [have_utmp=yes], ++ [xno], [have_utmp=no], ++ AC_MSG_ERROR(bad value ${enableval} for --enable-utmp))) ++AS_IF([test "x$have_utmp" = "xyes"], [AC_DEFINE(HAVE_UTMP, 1, [Define if utmp/wtmp support is enabled])]) ++AM_CONDITIONAL([HAVE_UTMP], [test "x$have_utmp" = "xyes"]) ++ ++# ------------------------------------------------------------------------------ + have_compat_libs=no + AC_ARG_ENABLE([compat_libs], AS_HELP_STRING([--enable-compat-libs],[Enable creation of compatibility libraries]), + [case "${enableval}" in +@@ -1372,6 +1382,7 @@ AC_MSG_RESULT([ + Split /usr: ${enable_split_usr} + SysV compatibility: ${SYSTEM_SYSV_COMPAT} + compatibility libraries: ${have_compat_libs} ++ utmp/wtmp support: ${have_utmp} + + prefix: ${prefix} + rootprefix: ${with_rootprefix} +diff --git a/man/runlevel.xml b/man/runlevel.xml +index 976753a737..db9a436724 100644 +--- a/man/runlevel.xml ++++ b/man/runlevel.xml +@@ -22,7 +22,8 @@ + --> + + ++ xmlns:xi="http://www.w3.org/2001/XInclude" ++ conditional="HAVE_UTMP"> + + + runlevel +diff --git a/man/systemd-update-utmp.service.xml b/man/systemd-update-utmp.service.xml +index 7d9e32e60a..caa1d8f568 100644 +--- a/man/systemd-update-utmp.service.xml ++++ b/man/systemd-update-utmp.service.xml +@@ -19,7 +19,7 @@ + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + --> +- ++ + + + systemd-update-utmp.service +diff --git a/src/core/build.h b/src/core/build.h +index a7f12a33e4..d5e55506cf 100644 +--- a/src/core/build.h ++++ b/src/core/build.h +@@ -63,6 +63,12 @@ + #define _SYSVINIT_FEATURE_ "-SYSVINIT" + #endif + ++#ifdef HAVE_UTMP ++#define _UTMP_FEATURE_ "+UTMP" ++#else ++#define _UTMP_FEATURE_ "-UTMP" ++#endif ++ + #ifdef HAVE_LIBCRYPTSETUP + #define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP" + #else +@@ -137,6 +143,7 @@ + _APPARMOR_FEATURE_ " " \ + _SMACK_FEATURE_ " " \ + _SYSVINIT_FEATURE_ " " \ ++ _UTMP_FEATURE_ " " \ + _LIBCRYPTSETUP_FEATURE_ " " \ + _GCRYPT_FEATURE_ " " \ + _GNUTLS_FEATURE_ " " \ +diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h +index 040a16e746..87d004e615 100644 +--- a/src/shared/utmp-wtmp.h ++++ b/src/shared/utmp-wtmp.h +@@ -23,6 +23,7 @@ + + #include "util.h" + ++#ifdef HAVE_UTMP + int utmp_get_runlevel(int *runlevel, int *previous); + + int utmp_put_shutdown(void); +@@ -33,3 +34,30 @@ int utmp_put_dead_process(const char *id, pid_t pid, int code, int status); + int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line); + + int utmp_wall(const char *message, const char *username, bool (*match_tty)(const char *tty)); ++ ++#else /* HAVE_UTMP */ ++ ++static inline int utmp_get_runlevel(int *runlevel, int *previous) { ++ return -ESRCH; ++} ++static inline int utmp_put_shutdown(void) { ++ return 0; ++} ++static inline int utmp_put_reboot(usec_t timestamp) { ++ return 0; ++} ++static inline int utmp_put_runlevel(int runlevel, int previous) { ++ return 0; ++} ++static inline int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) { ++ return 0; ++} ++static inline int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) { ++ return 0; ++} ++static inline int utmp_wall(const char *message, const char *username, ++ bool (*match_tty)(const char *tty)) { ++ return 0; ++} ++ ++#endif /* HAVE_UTMP */ diff --git a/0400-systemd-tmpfiles-Fix-IGNORE_DIRECTORY_PATH-age-handl.patch b/0400-systemd-tmpfiles-Fix-IGNORE_DIRECTORY_PATH-age-handl.patch new file mode 100644 index 0000000..f329ba4 --- /dev/null +++ b/0400-systemd-tmpfiles-Fix-IGNORE_DIRECTORY_PATH-age-handl.patch @@ -0,0 +1,36 @@ +From 9ed2a35e93f4a9e82585f860f54cdcbbdf3e1f86 Mon Sep 17 00:00:00 2001 +From: Richard Weinberger +Date: Tue, 9 Sep 2014 11:09:37 +0200 +Subject: [PATCH] systemd-tmpfiles: Fix IGNORE_DIRECTORY_PATH age handling + +If one has a config like: +d /tmp 1777 root root - +X /tmp/important_mount + +All files below /tmp/important_mount will be deleted as the +/tmp/important_mount item will spuriously inherit a max age of 0 +from /tmp. +/tmp has a max age of 0 but age_set is (of course) false. + +This affects also the PrivateTmp feature of systemd. +All tmp files of such services will be deleted unconditionally +and can cause service failures and data loss. + +Fix this by checking ->age_set in the IGNORE_DIRECTORY_PATH logic. +--- + 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 f9830c431d..7eafd6bb30 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1576,7 +1576,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) { + candidate_item = j; + } + +- if (candidate_item) { ++ if (candidate_item && candidate_item->age_set) { + i->age = candidate_item->age; + i->age_set = true; + } diff --git a/0401-test-bus-policy-load-policy-files-from-TEST_DIR.patch b/0401-test-bus-policy-load-policy-files-from-TEST_DIR.patch new file mode 100644 index 0000000..5757c72 --- /dev/null +++ b/0401-test-bus-policy-load-policy-files-from-TEST_DIR.patch @@ -0,0 +1,75 @@ +From 45f1b67a70a749ca14a7df256a177de74a3e73f6 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Fri, 26 Sep 2014 17:50:24 +0200 +Subject: [PATCH] test-bus-policy: load policy files from TEST_DIR + +'make distcheck' calls test-bus-policy outside of the source tree, so it +must consider the TEST_DIR variable to access its files. +--- + src/bus-proxyd/test-bus-policy.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/src/bus-proxyd/test-bus-policy.c b/src/bus-proxyd/test-bus-policy.c +index 37e66274f0..900e4d2b06 100644 +--- a/src/bus-proxyd/test-bus-policy.c ++++ b/src/bus-proxyd/test-bus-policy.c +@@ -44,6 +44,23 @@ + + #include + ++static int test_policy_load(Policy *p, const char *name) ++{ ++ char *path; ++ int r = 0; ++ ++ path = strjoin(TEST_DIR, "/bus-policy/", name, NULL); ++ ++ if (access(path, R_OK) == 0) ++ policy_load(p, STRV_MAKE(path)); ++ else ++ r = -ENOENT; ++ ++ free(path); ++ ++ return r; ++} ++ + int main(int argc, char *argv[]) { + + Policy p = {}; +@@ -52,7 +69,7 @@ int main(int argc, char *argv[]) { + Hashmap *names_hash; + + /* Ownership tests */ +- assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/ownerships.conf")) == 0); ++ assert_se(test_policy_load(&p, "ownerships.conf") == 0); + + ucred.uid = 0; + assert_se(policy_check_own(&p, &ucred, "org.test.test1") == true); +@@ -77,7 +94,7 @@ int main(int argc, char *argv[]) { + policy_free(&p); + + /* Signaltest */ +- assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/signals.conf")) == 0); ++ assert_se(test_policy_load(&p, "signals.conf") == 0); + names_strv = STRV_MAKE("bli.bla.blubb"); + + ucred.uid = 0; +@@ -89,7 +106,7 @@ int main(int argc, char *argv[]) { + policy_free(&p); + + /* Method calls */ +- assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/methods.conf")) == 0); ++ assert_se(test_policy_load(&p, "methods.conf") == 0); + names_strv = STRV_MAKE("org.test.test1"); + policy_dump(&p); + +@@ -108,7 +125,7 @@ int main(int argc, char *argv[]) { + policy_free(&p); + + /* User and groups */ +- assert_se(policy_load(&p, STRV_MAKE("test/bus-policy/hello.conf")) == 0); ++ assert_se(test_policy_load(&p, "hello.conf") == 0); + policy_dump(&p); + + ucred.uid = 0; diff --git a/0402-shutdownd-clean-up-initialization-of-struct.patch b/0402-shutdownd-clean-up-initialization-of-struct.patch new file mode 100644 index 0000000..49a02e0 --- /dev/null +++ b/0402-shutdownd-clean-up-initialization-of-struct.patch @@ -0,0 +1,27 @@ +From b748c7596f79945be5263a0d1c88de64eb0c5146 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sat, 27 Sep 2014 00:25:09 +0200 +Subject: [PATCH] shutdownd: clean up initialization of struct + +No functional change. We just don't assign the value twice. + +Found by coverity. Fixes: CID#1237616 and #1237617 +--- + src/shutdownd/shutdownd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c +index 99aa4b32b3..0f008a6100 100644 +--- a/src/shutdownd/shutdownd.c ++++ b/src/shutdownd/shutdownd.c +@@ -52,8 +52,8 @@ static int read_packet(int fd, union shutdown_buffer *_b) { + union shutdown_buffer b; /* We maintain our own copy here, in + * order not to corrupt the last message */ + struct iovec iovec = { +- iovec.iov_base = &b, +- iovec.iov_len = sizeof(b) - 1, ++ .iov_base = &b, ++ .iov_len = sizeof(b) - 1, + }; + union { + struct cmsghdr cmsghdr; diff --git a/0403-shell-completion-zsh-journalctl-s-b-changes.patch b/0403-shell-completion-zsh-journalctl-s-b-changes.patch new file mode 100644 index 0000000..d771cbc --- /dev/null +++ b/0403-shell-completion-zsh-journalctl-s-b-changes.patch @@ -0,0 +1,40 @@ +From c2026f28bdc64c608e9b00e8f7916c82f44ec610 Mon Sep 17 00:00:00 2001 +From: Eric Cook +Date: Sat, 27 Sep 2014 08:48:09 -0400 +Subject: [PATCH] shell-completion(zsh): journalctl's -b changes + +removed pointless index sort of bootids. +use `compadd -a' to add each array, instead of expanding possibly hundreds of words needlessly. +optional completion of -b +--- + shell-completion/zsh/_journalctl | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl +index 0d16a26a6f..a469bbc9a7 100644 +--- a/shell-completion/zsh/_journalctl ++++ b/shell-completion/zsh/_journalctl +@@ -41,11 +41,11 @@ _journal_fields() { + + _journal_boots() { + local -a _bootid _previousboots +- _bootid=( ${(fao)"$(_call_program bootid "$service -F _BOOT_ID")"} ) ++ _bootid=( ${(f)"$(_call_program bootid "$service -F _BOOT_ID")"} ) + _previousboots=( -{1..${#_bootid}} ) + _alternative : \ +- "offsets:boot offsets:(${_previousboots[1,-2]})" \ +- "bootid:boot ids:(${_bootid[@]})" ++ "offsets:boot offsets:compadd -a '_previousboots[1,-2]'" \ ++ "bootid:boot ids:compadd -a _bootid" + } + + _arguments -s \ +@@ -63,7 +63,7 @@ _arguments -s \ + {-x,--catalog}'[Show explanatory texts with each log line]' \ + {-q,--quiet}"[Don't show privilege warning]" \ + {-m,--merge}'[Show entries from all available journals]' \ +- {-b+,--boot=}'[Show data only from the specified boot or offset]:boot id or offset:_journal_boots' \ ++ {-b+,--boot=}'[Show data only from the specified boot or offset]::boot id or offset:_journal_boots' \ + '--list-boots[List boots ordered by time]' \ + {-k,--dmesg}'[Show only kernel messages from the current boot]' \ + {-u+,--unit=}'[Show data only from the specified unit]:units:_journal_fields _SYSTEMD_UNIT' \ diff --git a/0404-catalog-add-Polish-translation.patch b/0404-catalog-add-Polish-translation.patch new file mode 100644 index 0000000..5d75bda --- /dev/null +++ b/0404-catalog-add-Polish-translation.patch @@ -0,0 +1,293 @@ +From d6740361f2d7cd148856ca4f6f4610c1c71880c8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Piotr=20Dr=C4=85g?= +Date: Sat, 27 Sep 2014 23:30:15 +0200 +Subject: [PATCH] catalog: add Polish translation + +--- + Makefile.am | 3 +- + catalog/systemd.pl.catalog | 261 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 263 insertions(+), 1 deletion(-) + create mode 100644 catalog/systemd.pl.catalog + +diff --git a/Makefile.am b/Makefile.am +index e0cba76329..7bb7f75915 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4140,8 +4140,9 @@ dist_pkgsysconf_DATA += \ + + dist_catalog_DATA = \ + catalog/systemd.fr.catalog \ +- catalog/systemd.ru.catalog \ + catalog/systemd.it.catalog \ ++ catalog/systemd.pl.catalog \ ++ catalog/systemd.ru.catalog \ + catalog/systemd.catalog + + SOCKETS_TARGET_WANTS += \ +diff --git a/catalog/systemd.pl.catalog b/catalog/systemd.pl.catalog +new file mode 100644 +index 0000000000..0a172a2e30 +--- /dev/null ++++ b/catalog/systemd.pl.catalog +@@ -0,0 +1,261 @@ ++# This file is part of systemd. ++# ++# Copyright 2012 Lennart Poettering ++# Copyright 2014 Piotr Drąg ++# ++# 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 . ++ ++# Message catalog for systemd's own messages ++# Polish translation ++ ++# The catalog format is documented on ++# http://www.freedesktop.org/wiki/Software/systemd/catalog ++ ++# For an explanation why we do all this, see https://xkcd.com/1024/ ++ ++-- f77379a8490b408bbe5f6940505a777b ++Subject: Uruchomiono Journal ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Systemowy proces dziennika został uruchomiony, otworzył pliki dziennika do ++zapisu i jest gotowy do przetwarzania żądań. ++ ++-- d93fb3c9c24d451a97cea615ce59c00b ++Subject: Zatrzymano Journal ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Systemowy proces dziennika został wyłączony i zamknął wszystkie obecnie ++aktywne pliki dziennika. ++ ++-- a596d6fe7bfa4994828e72309e95d61e ++Subject: Ograniczono komunikaty z usługi ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++Documentation: man:journald.conf(5) ++ ++Usługa zapisała za dużo komunikatów w określonym czasie. Komunikaty z usługi ++zostały pominięte. ++ ++Proszę zauważyć, że tylko komunikaty z danej usługi zostały pominięte. Nie ma ++to wpływu na komunikaty innych usług. ++ ++Ograniczenia komunikatów mogą być konfigurowane za pomocą opcji ++RateLimitInterval= i RateLimitBurst= w pliku ++/etc/systemd/journald.conf. Strona journald.conf(5) zawiera więcej informacji. ++ ++-- e9bf28e6e834481bb6f48f548ad13606 ++Subject: Utracono komunikaty Journal ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Komunikaty jądra zostały utracone, ponieważ system dziennika nie mógł ++przetworzyć ich odpowiednio szybko. ++ ++-- fc2e22bc6ee647b6b90729ab34a250b1 ++Subject: Proces @COREDUMP_PID@ (@COREDUMP_COMM@) zrzucił plik core ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++Documentation: man:core(5) ++ ++Proces @COREDUMP_PID@ (@COREDUMP_COMM@) uległ awarii i zrzucił plik core. ++ ++Zwykle wskazuje to na błąd programistyczny w danym programie i powinno zostać zgłoszone jego producentowi jako błąd. ++ ++-- 8d45620c1a4348dbb17410da57c60c66 ++Subject: Utworzono nową sesję @SESSION_ID@ dla użytkownika @USER_ID@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat ++ ++Nowa sesja o identyfikatorze @SESSION_ID@ została utworzona dla użytkownika ++@USER_ID@. ++ ++Proces prowadzący sesji: @LEADER@. ++ ++-- 3354939424b4456d9802ca8333ed424a ++Subject: Zakończono sesję @SESSION_ID@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat ++ ++Sesja o identyfikatorze @SESSION_ID@ została zakończona. ++ ++-- fcbefc5da23d428093f97c82a9290f7b ++Subject: Dostępne jest nowe stanowisko @SEAT_ID@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat ++ ++Nowe stanowisko @SEAT_ID@ zostało skonfigurowane i jest teraz dostępne. ++ ++-- e7852bfe46784ed0accde04bc864c2d5 ++Subject: Usunięto stanowisko @SEAT_ID@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat ++ ++Stanowisko @SEAT_ID@ zostało usunięte i nie jest już dostępne. ++ ++-- c7a787079b354eaaa9e77b371893cd27 ++Subject: Zmiana czasu ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Zegar systemowy został zmieniony na @REALTIME@ μs po 1 stycznia 1970. ++ ++-- 45f82f4aef7a4bbf942ce861d1f20990 ++Subject: Zmiana strefy czasowej na @TIMEZONE@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Systemowa strefa czasowa została zmieniona na @TIMEZONE@. ++ ++-- b07a249cd024414a82dd00cd181378ff ++Subject: Ukończono uruchamianie systemu ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Wszystkie usługi systemowe obowiązkowo zakolejkowane do włączenia podczas ++uruchamiania systemu zostały pomyślnie uruchomione. Proszę zauważyć, że nie ++oznacza to, że komputer jest bezczynny, jako że usługi mogą wciąż kończyć ++proces uruchamiania. ++ ++Uruchamianie jądra zajęło @KERNEL_USEC@ μs. ++ ++Uruchamianie początkowego dysku RAM zajęło @INITRD_USEC@ μs. ++ ++Uruchamianie przestrzeni użytkownika zajęło @USERSPACE_USEC@ μs. ++ ++-- 6bbd95ee977941e497c48be27c254128 ++Subject: Przejście do stanu uśpienia @SLEEP@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++System przeszedł do stanu uśpienia @SLEEP@. ++ ++-- 8811e6df2a8e40f58a94cea26f8ebf14 ++Subject: Wyjście ze stanu uśpienia @SLEEP@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++System wyszedł ze stanu uśpienia @SLEEP@. ++ ++-- 98268866d1d54a499c4e98921d93bc40 ++Subject: Zainicjowano wyłączenie systemu ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Zainicjowano wyłączenie systemd. Wyłączenie zostało rozpoczęte i wszystkie ++usługi systemowe zostały zakończone, a wszystkie systemy plików odmontowane. ++ ++-- 7d4958e842da4a758f6c1cdc7b36dcc5 ++Subject: Rozpoczęto uruchamianie jednostki @UNIT@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jednostka @UNIT@ rozpoczęła uruchamianie. ++ ++-- 39f53479d3a045ac8e11786248231fbf ++Subject: Ukończono uruchamianie jednostki @UNIT@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jednostka @UNIT@ ukończyła uruchamianie. ++ ++Wynik uruchamiania: @RESULT@. ++ ++-- de5b426a63be47a7b6ac3eaac82e2f6f ++Subject: Rozpoczęto wyłączanie jednostki @UNIT@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jednostka @UNIT@ rozpoczęła wyłączanie. ++ ++-- 9d1aaa27d60140bd96365438aad20286 ++Subject: Ukończono wyłączanie jednostki @UNIT@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jednostka @UNIT@ ukończyła wyłączanie. ++ ++-- be02cf6855d2428ba40df7e9d022f03d ++Subject: Jednostka @UNIT@ się nie powiodła ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jednostka @UNIT@ się nie powiodła. ++ ++Wynik: @RESULT@. ++ ++-- d34d037fff1847e6ae669a370e694725 ++Subject: Rozpoczęto ponowne wczytywanie konfiguracji jednostki @UNIT@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jednostka @UNIT@ rozpoczęła ponowne wczytywanie swojej konfiguracji. ++ ++-- 7b05ebc668384222baa8881179cfda54 ++Subject: Ukończono ponowne wczytywanie konfiguracji jednostki @UNIT@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jednostka @UNIT@ ukończyła ponowne wczytywanie swojej konfiguracji. ++ ++Wynik: @RESULT@. ++ ++-- 641257651c1b4ec9a8624d7a40a9e1e7 ++Subject: Nie można wykonać procesu @EXECUTABLE@ ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Proces @EXECUTABLE@ nie mógł zostać wykonany i się nie powiódł. ++ ++Numer błędu zwrócony podczas wykonywania tego procesu: @ERRNO@. ++ ++-- 0027229ca0644181a76c4e92458afa2e ++Subject: Nie można przekazać jednego lub więcej komunikatów do syslog ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Jeden lub więcej komunikatów nie może zostać przekazanych do usługi syslog ++uruchomionej obok journald. Zwykle oznacza to, że implementacja syslog nie ++jest w stanie nadążyć za prędkością kolejki komunikatów. ++ ++-- 1dee0369c7fc4736b7099b38ecb46ee7 ++Subject: Punkt montowania nie jest pusty ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Katalog @WHERE@ został podany jako punkt montowania (drugie pole w pliku ++/etc/fstab lub pole Where= w pliku jednostki systemd) i nie jest pusty. Nie ++wpływa to na montowanie, ale wcześniej istniejące pliki w tym katalogu stają ++się niedostępne. Aby zobaczyć te pliki, proszę ręcznie zamontować system ++plików w innym położeniu. ++ ++-- 24d8d4452573402496068381a6312df2 ++Subject: Uruchomiono maszynę wirtualną lub kontener ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Maszyna wirtualna @NAME@ (PID prowadzący @LEADER@) została uruchomiona i jest ++gotowa do użycia. ++ ++-- 58432bd3bace477cb514b56381b8a758 ++Subject: Zakończono maszynę wirtualną lub kontener ++Defined-By: systemd ++Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel ++ ++Maszyna wirtualna @NAME@ (PID prowadzący @LEADER@) została wyłączona. diff --git a/0405-logind-add-support-for-TPS65217-Power-Button.patch b/0405-logind-add-support-for-TPS65217-Power-Button.patch new file mode 100644 index 0000000..f53e3a7 --- /dev/null +++ b/0405-logind-add-support-for-TPS65217-Power-Button.patch @@ -0,0 +1,68 @@ +From 492d7a3038b154e1813a1ece913a5a27148fec19 Mon Sep 17 00:00:00 2001 +From: Koen Kooi +Date: Sat, 27 Sep 2014 09:55:44 +0200 +Subject: [PATCH] logind: add support for TPS65217 Power Button + +This PMIC is found on TI AM335x based boards like the beaglebone and +beaglebone black. + +root@beaglebone-white:~# udevadm info -a /dev/input/event0 + +Udevadm info starts with the device specified by the devpath and then +walks up the chain of parent devices. It prints for every device +found, all possible attributes in the udev rules key format. +A rule to match, can be composed by the attributes of the device +and the attributes from one single parent device. + + looking at device +'/devices/ocp.3/44e0b000.i2c/i2c-0/0-0024/input/input0/event0': + KERNEL=="event0" + SUBSYSTEM=="input" + DRIVER=="" + + looking at parent device +'/devices/ocp.3/44e0b000.i2c/i2c-0/0-0024/input/input0': + KERNELS=="input0" + SUBSYSTEMS=="input" + DRIVERS=="" + ATTRS{name}=="tps65217_pwr_but" + ATTRS{phys}=="" + ATTRS{uniq}=="" + ATTRS{properties}=="0" + + looking at parent device '/devices/ocp.3/44e0b000.i2c/i2c-0/0-0024': + KERNELS=="0-0024" + SUBSYSTEMS=="i2c" + DRIVERS=="tps65217" + ATTRS{name}=="tps65217" + + looking at parent device '/devices/ocp.3/44e0b000.i2c/i2c-0': + KERNELS=="i2c-0" + SUBSYSTEMS=="i2c" + DRIVERS=="" + ATTRS{name}=="OMAP I2C adapter" + + looking at parent device '/devices/ocp.3/44e0b000.i2c': + KERNELS=="44e0b000.i2c" + SUBSYSTEMS=="platform" + DRIVERS=="omap_i2c" + + looking at parent device '/devices/ocp.3': + KERNELS=="ocp.3" + SUBSYSTEMS=="platform" + DRIVERS=="" +--- + src/login/70-power-switch.rules | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/login/70-power-switch.rules b/src/login/70-power-switch.rules +index a6997f7788..695d246370 100644 +--- a/src/login/70-power-switch.rules ++++ b/src/login/70-power-switch.rules +@@ -10,5 +10,6 @@ ACTION=="remove", GOTO="power_switch_end" + SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="acpi", TAG+="power-switch" + SUBSYSTEM=="input", KERNEL=="event*", KERNELS=="thinkpad_acpi", TAG+="power-switch" + SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="twl4030_pwrbutton", TAG+="power-switch" ++SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="tps65217_pwr_but", TAG+="power-switch" + + LABEL="power_switch_end" diff --git a/0406-bootchart-parse-userinput-with-safe_atoi.patch b/0406-bootchart-parse-userinput-with-safe_atoi.patch new file mode 100644 index 0000000..9431cb3 --- /dev/null +++ b/0406-bootchart-parse-userinput-with-safe_atoi.patch @@ -0,0 +1,31 @@ +From 9bcf7507fab6e6b022ae3cc7178237e6e0a09e9a Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Fri, 26 Sep 2014 21:41:02 +0200 +Subject: [PATCH] bootchart: parse userinput with safe_atoi + +Found by coverity. Fixes: CID#996409 +--- + src/bootchart/store.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/bootchart/store.c b/src/bootchart/store.c +index ed683e88d9..3099ff1208 100644 +--- a/src/bootchart/store.c ++++ b/src/bootchart/store.c +@@ -192,12 +192,14 @@ vmstat_next: + + m = buf; + while (m) { ++ int r; ++ + if (sscanf(m, "%s %*s %*s %*s %*s %*s %*s %s %s", key, rt, wt) < 3) + goto schedstat_next; + + if (strstr(key, "cpu")) { +- c = atoi((const char*)(key+3)); +- if (c > MAXCPUS) ++ r = safe_atoi((const char*)(key+3), &c); ++ if (r < 0 || c > MAXCPUS) + /* Oops, we only have room for MAXCPUS data */ + break; + sampledata->runtime[c] = atoll(rt); diff --git a/0407-bootchart-check-return-of-strftime.patch b/0407-bootchart-check-return-of-strftime.patch new file mode 100644 index 0000000..7378f8d --- /dev/null +++ b/0407-bootchart-check-return-of-strftime.patch @@ -0,0 +1,60 @@ +From e931d3f4241231e4102eda06adaf7cbfd68c6a5d Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sat, 27 Sep 2014 22:25:07 +0200 +Subject: [PATCH] bootchart: check return of strftime + +Found by coverity. Fixes: CID#996314 and #996312 +--- + src/bootchart/bootchart.c | 8 ++++++-- + src/bootchart/svg.c | 5 +++-- + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c +index 8ef5ad18a6..366a5ab5d0 100644 +--- a/src/bootchart/bootchart.c ++++ b/src/bootchart/bootchart.c +@@ -389,7 +389,9 @@ int main(int argc, char *argv[]) { + + if (!of && (access(arg_output_path, R_OK|W_OK|X_OK) == 0)) { + t = time(NULL); +- strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); ++ r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); ++ assert_se(r > 0); ++ + snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr); + of = fopen(output_file, "we"); + } +@@ -457,7 +459,9 @@ int main(int argc, char *argv[]) { + + if (!of) { + t = time(NULL); +- strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); ++ r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); ++ assert_se(r > 0); ++ + snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr); + of = fopen(output_file, "we"); + } +diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c +index 135883fb83..faf377e506 100644 +--- a/src/bootchart/svg.c ++++ b/src/bootchart/svg.c +@@ -162,7 +162,7 @@ static void svg_title(const char *build) { + char *c; + FILE *f; + time_t t; +- int fd; ++ int fd, r; + struct utsname uts; + + /* grab /proc/cmdline */ +@@ -196,7 +196,8 @@ static void svg_title(const char *build) { + + /* date */ + t = time(NULL); +- strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); ++ r = strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); ++ assert_se(r > 0); + + /* CPU type */ + fd = openat(procfd, "cpuinfo", O_RDONLY); diff --git a/0408-test-bus-policy-silence-coverity.patch b/0408-test-bus-policy-silence-coverity.patch new file mode 100644 index 0000000..26c6d35 --- /dev/null +++ b/0408-test-bus-policy-silence-coverity.patch @@ -0,0 +1,38 @@ +From 5e90b6a978d15efedc5b5cc4a3d2d922a0ecd2a9 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sun, 28 Sep 2014 18:46:15 +0200 +Subject: [PATCH] test-bus-policy: silence coverity + +Check if strjoin worked and also use _cleanup_free_ since we are +here. + +Found with Coverity. Fixes CID#1241962 +--- + src/bus-proxyd/test-bus-policy.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/bus-proxyd/test-bus-policy.c b/src/bus-proxyd/test-bus-policy.c +index 900e4d2b06..7bcebef905 100644 +--- a/src/bus-proxyd/test-bus-policy.c ++++ b/src/bus-proxyd/test-bus-policy.c +@@ -46,18 +46,17 @@ + + static int test_policy_load(Policy *p, const char *name) + { +- char *path; ++ _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) + policy_load(p, STRV_MAKE(path)); + else + r = -ENOENT; + +- free(path); +- + return r; + } + diff --git a/0409-bootchart-Do-not-try-to-access-data-for-non-existing.patch b/0409-bootchart-Do-not-try-to-access-data-for-non-existing.patch new file mode 100644 index 0000000..6fb65d6 --- /dev/null +++ b/0409-bootchart-Do-not-try-to-access-data-for-non-existing.patch @@ -0,0 +1,26 @@ +From c119700c06b248b1c2a082b40b1a346f58d89da0 Mon Sep 17 00:00:00 2001 +From: Philippe De Swert +Date: Sun, 28 Sep 2014 18:12:51 +0300 +Subject: [PATCH] bootchart: Do not try to access data for non-existing CPU's + +Cpu's are assigned normally, so starting at 0, so the MAX_CPU index will +always be one smaller than the actual number. + +Found with Coverity. +--- + src/bootchart/store.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bootchart/store.c b/src/bootchart/store.c +index 3099ff1208..9ea1b27de4 100644 +--- a/src/bootchart/store.c ++++ b/src/bootchart/store.c +@@ -199,7 +199,7 @@ vmstat_next: + + if (strstr(key, "cpu")) { + r = safe_atoi((const char*)(key+3), &c); +- if (r < 0 || c > MAXCPUS) ++ if (r < 0 || c > MAXCPUS -1) + /* Oops, we only have room for MAXCPUS data */ + break; + sampledata->runtime[c] = atoll(rt); diff --git a/0410-sd-bus-clean-up-string-length-calculation.patch b/0410-sd-bus-clean-up-string-length-calculation.patch new file mode 100644 index 0000000..15ca755 --- /dev/null +++ b/0410-sd-bus-clean-up-string-length-calculation.patch @@ -0,0 +1,54 @@ +From f0c5e28e58215682c832e1667b346b59c804f6a5 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Sun, 28 Sep 2014 21:19:22 +0200 +Subject: [PATCH] sd-bus: clean up string length calculation + +Move the +1 calculus onto the definition of the variable, just to make +the code a little easier to read. No functional change. +--- + src/libsystemd/sd-bus/bus-control.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c +index b22f4c4ff6..4ad44469b5 100644 +--- a/src/libsystemd/sd-bus/bus-control.c ++++ b/src/libsystemd/sd-bus/bus-control.c +@@ -58,15 +58,15 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags + assert(bus); + assert(name); + +- l = strlen(name); +- size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l + 1); ++ l = strlen(name) + 1; ++ size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l); + n = alloca0_align(size, 8); + n->size = size; + kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags); + +- n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l + 1; ++ n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; + n->items[0].type = KDBUS_ITEM_NAME; +- memcpy(n->items[0].str, name, l+1); ++ memcpy(n->items[0].str, name, l); + + #ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(n, n->size); +@@ -153,14 +153,14 @@ static int bus_release_name_kernel(sd_bus *bus, const char *name) { + assert(bus); + assert(name); + +- l = strlen(name); +- size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l + 1); ++ l = strlen(name) + 1; ++ size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l); + n = alloca0_align(size, 8); + n->size = size; + +- n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l + 1; ++ n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l; + n->items[0].type = KDBUS_ITEM_NAME; +- memcpy(n->items[0].str, name, l+1); ++ memcpy(n->items[0].str, name, l); + + #ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(n, n->size); diff --git a/0411-terminal-add-sysview_seat_switch_to.patch b/0411-terminal-add-sysview_seat_switch_to.patch new file mode 100644 index 0000000..a806c2b --- /dev/null +++ b/0411-terminal-add-sysview_seat_switch_to.patch @@ -0,0 +1,90 @@ +From 1c7830cc105bfe217abe6f304f4785bbeab209f6 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 29 Sep 2014 14:59:01 +0200 +Subject: [PATCH] terminal: add sysview_seat_switch_to() + +Add helper to perform session switches on a specific seat whenever we +retrieve a VT-switch keyboard event. +--- + src/libsystemd-terminal/sysview-internal.h | 1 + + src/libsystemd-terminal/sysview.c | 28 ++++++++++++++++++++++++++++ + src/libsystemd-terminal/sysview.h | 1 + + 3 files changed, 30 insertions(+) + +diff --git a/src/libsystemd-terminal/sysview-internal.h b/src/libsystemd-terminal/sysview-internal.h +index d9f7fe3301..39ff933eaa 100644 +--- a/src/libsystemd-terminal/sysview-internal.h ++++ b/src/libsystemd-terminal/sysview-internal.h +@@ -88,6 +88,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sysview_session*, sysview_session_free); + struct sysview_seat { + sysview_context *context; + char *name; ++ char *path; + + Hashmap *session_map; + Hashmap *device_map; +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index cd776f62d8..919fadf6fe 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -391,6 +391,10 @@ int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *name) { + if (!seat->name) + return -ENOMEM; + ++ r = sd_bus_path_encode("/org/freedesktop/login1/seat", seat->name, &seat->path); ++ if (r < 0) ++ return r; ++ + seat->session_map = hashmap_new(&string_hash_ops); + if (!seat->session_map) + return -ENOMEM; +@@ -422,6 +426,7 @@ sysview_seat *sysview_seat_free(sysview_seat *seat) { + + hashmap_free(seat->device_map); + hashmap_free(seat->session_map); ++ free(seat->path); + free(seat->name); + free(seat); + +@@ -434,6 +439,29 @@ const char *sysview_seat_get_name(sysview_seat *seat) { + return seat->name; + } + ++int sysview_seat_switch_to(sysview_seat *seat, uint32_t nr) { ++ _cleanup_bus_message_unref_ sd_bus_message *m = NULL; ++ int r; ++ ++ assert_return(seat, -EINVAL); ++ assert_return(seat->context->sysbus, -EINVAL); ++ ++ r = sd_bus_message_new_method_call(seat->context->sysbus, ++ &m, ++ "org.freedesktop.login1", ++ seat->path, ++ "org.freedesktop.login1.Seat", ++ "SwitchTo"); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_message_append(m, "u", nr); ++ if (r < 0) ++ return r; ++ ++ return sd_bus_send(seat->context->sysbus, m, NULL); ++} ++ + /* + * Contexts + */ +diff --git a/src/libsystemd-terminal/sysview.h b/src/libsystemd-terminal/sysview.h +index f691e492d5..31b800f698 100644 +--- a/src/libsystemd-terminal/sysview.h ++++ b/src/libsystemd-terminal/sysview.h +@@ -137,6 +137,7 @@ void sysview_session_release_control(sysview_session *session); + */ + + const char *sysview_seat_get_name(sysview_seat *seat); ++int sysview_seat_switch_to(sysview_seat *seat, uint32_t nr); + + /* + * Contexts diff --git a/0412-bus-sync-kdbus.h-ABI-break.patch b/0412-bus-sync-kdbus.h-ABI-break.patch new file mode 100644 index 0000000..e157905 --- /dev/null +++ b/0412-bus-sync-kdbus.h-ABI-break.patch @@ -0,0 +1,37 @@ +From 8bf4a42a2efcc53479a422e97240ce347dc3ffae Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 29 Sep 2014 15:35:51 +0200 +Subject: [PATCH] bus: sync kdbus.h (ABI break!) + +--- + src/libsystemd/sd-bus/kdbus.h | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index 77a153be37..7fb11713fc 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -4,6 +4,7 @@ + * Copyright (C) 2013-2014 Linux Foundation + * Copyright (C) 2013-2014 Lennart Poettering + * Copyright (C) 2013-2014 Daniel Mack ++ * Copyright (C) 2013-2014 David Herrmann + * + * kdbus 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 +@@ -212,7 +213,6 @@ struct kdbus_policy_access { + * bloom filter + * @KDBUS_ITEM_DST_NAME: Destination's well-known name + * @KDBUS_ITEM_MAKE_NAME: Name of domain, bus, endpoint +- * @KDBUS_ITEM_MEMFD_NAME: The human readable name of a memfd (debugging) + * @KDBUS_ITEM_ATTACH_FLAGS: Attach-flags, used for updating which metadata + * a connection subscribes to + * @_KDBUS_ITEM_ATTACH_BASE: Start of metadata attach items +@@ -253,7 +253,6 @@ enum kdbus_item_type { + KDBUS_ITEM_BLOOM_MASK, + KDBUS_ITEM_DST_NAME, + KDBUS_ITEM_MAKE_NAME, +- KDBUS_ITEM_MEMFD_NAME, + KDBUS_ITEM_ATTACH_FLAGS, + + _KDBUS_ITEM_ATTACH_BASE = 0x1000, diff --git a/0413-terminal-add-helper-to-retrieve-the-seat-of-a-sessio.patch b/0413-terminal-add-helper-to-retrieve-the-seat-of-a-sessio.patch new file mode 100644 index 0000000..5952a05 --- /dev/null +++ b/0413-terminal-add-helper-to-retrieve-the-seat-of-a-sessio.patch @@ -0,0 +1,40 @@ +From bfd6d8a322414a7ebd1a64a717c1834e6cb00d7d Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 29 Sep 2014 15:36:20 +0200 +Subject: [PATCH] terminal: add helper to retrieve the seat of a session + +Allow sysview users to retrieve the seat that a session is assigned to. +--- + src/libsystemd-terminal/sysview.c | 6 ++++++ + src/libsystemd-terminal/sysview.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c +index 919fadf6fe..70a6ca726c 100644 +--- a/src/libsystemd-terminal/sysview.c ++++ b/src/libsystemd-terminal/sysview.c +@@ -267,6 +267,12 @@ const char *sysview_session_get_name(sysview_session *session) { + return session->name; + } + ++sysview_seat *sysview_session_get_seat(sysview_session *session) { ++ assert_return(session, NULL); ++ ++ return session->seat; ++} ++ + static int session_take_control_fn(sd_bus *bus, + sd_bus_message *reply, + void *userdata, +diff --git a/src/libsystemd-terminal/sysview.h b/src/libsystemd-terminal/sysview.h +index 31b800f698..cad603d59f 100644 +--- a/src/libsystemd-terminal/sysview.h ++++ b/src/libsystemd-terminal/sysview.h +@@ -128,6 +128,7 @@ void sysview_session_set_userdata(sysview_session *session, void *userdata); + void *sysview_session_get_userdata(sysview_session *session); + + const char *sysview_session_get_name(sysview_session *session); ++sysview_seat *sysview_session_get_seat(sysview_session *session); + + int sysview_session_take_control(sysview_session *session); + void sysview_session_release_control(sysview_session *session); diff --git a/0414-bus-use-2M-as-maximum-message-size-in-benchmark.patch b/0414-bus-use-2M-as-maximum-message-size-in-benchmark.patch new file mode 100644 index 0000000..6be8fbb --- /dev/null +++ b/0414-bus-use-2M-as-maximum-message-size-in-benchmark.patch @@ -0,0 +1,24 @@ +From 1679ddc4601982a5b3a852c7ac75277e98781136 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 29 Sep 2014 15:44:44 +0200 +Subject: [PATCH] bus: use 2M as maximum message size in benchmark + +The kdbus limit is 2M and we removed the bus-owner override. Therefore, +use at most 2M as message size. +--- + src/libsystemd/sd-bus/test-bus-kernel-benchmark.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c b/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c +index cd88e67c9e..35f87e91bd 100644 +--- a/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c ++++ b/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c +@@ -33,7 +33,7 @@ + #include "bus-internal.h" + #include "bus-util.h" + +-#define MAX_SIZE (4*1024*1024) ++#define MAX_SIZE (2*1024*1024) + + static usec_t arg_loop_usec = 100 * USEC_PER_MSEC; + diff --git a/0415-journalctl-do-not-output-reboot-markers-when-running.patch b/0415-journalctl-do-not-output-reboot-markers-when-running.patch new file mode 100644 index 0000000..7cba339 --- /dev/null +++ b/0415-journalctl-do-not-output-reboot-markers-when-running.patch @@ -0,0 +1,24 @@ +From 4bed248505da4da94d82078fe60326a374970e97 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 26 Sep 2014 10:49:55 -0400 +Subject: [PATCH] journalctl: do not output --reboot-- markers when running + non-interactively + +They are not legal in the export format. +--- + src/journal/journalctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 47206d383a..89a922c067 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1939,7 +1939,7 @@ int main(int argc, char *argv[]) { + goto finish; + } + +- if (!arg_merge) { ++ if (!arg_merge && !arg_quiet) { + sd_id128_t boot_id; + + r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); diff --git a/0416-journal-remote-fix-handling-of-non-blocking-sources.patch b/0416-journal-remote-fix-handling-of-non-blocking-sources.patch new file mode 100644 index 0000000..cbbbd74 --- /dev/null +++ b/0416-journal-remote-fix-handling-of-non-blocking-sources.patch @@ -0,0 +1,54 @@ +From 70f1b2ddc6b94d3fa5539eb8503887b465f7fcc7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 27 Sep 2014 20:00:00 -0400 +Subject: [PATCH] journal-remote: fix handling of non-blocking sources + +In the conversion to sd-event loop, handling of normal files got +broken. We do not want to perform non-blocking reads on them, but +simply do read() in a loop. Install a statically-enabled "source" +to do that. +--- + src/journal-remote/journal-remote.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index ad87783510..c97cfe613e 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -295,6 +295,8 @@ static int dispatch_raw_source_event(sd_event_source *event, + int fd, + uint32_t revents, + void *userdata); ++static int dispatch_blocking_source_event(sd_event_source *event, ++ void *userdata); + static int dispatch_raw_connection_event(sd_event_source *event, + int fd, + uint32_t revents, +@@ -378,6 +380,13 @@ 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) { ++ 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); ++ if (r == 0) ++ sd_event_source_set_enabled(source->event, SD_EVENT_ON); ++ } + if (r < 0) { + log_error("Failed to register event source for fd:%d: %s", + fd, strerror(-r)); +@@ -1029,6 +1038,13 @@ static int dispatch_raw_source_event(sd_event_source *event, + return 1; + } + ++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); ++} ++ + static int accept_connection(const char* type, int fd, + SocketAddress *addr, char **hostname) { + int fd2, r; diff --git a/0417-swap-introduce-Discard-property.patch b/0417-swap-introduce-Discard-property.patch new file mode 100644 index 0000000..cb1fa69 --- /dev/null +++ b/0417-swap-introduce-Discard-property.patch @@ -0,0 +1,232 @@ +From 86b23b07c96b185126bfbf217227dad362a20c25 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 24 Sep 2014 14:29:05 +0200 +Subject: [PATCH] swap: introduce Discard property + +Process possible "discard" values from /etc/fstab. +--- + man/systemd.swap.xml | 14 ++++++++++ + src/core/execute.c | 25 ++++++++++++++++++ + src/core/execute.h | 1 + + src/core/load-fragment-gperf.gperf.m4 | 1 + + src/core/swap.c | 49 +++++++++++++++++++++++------------ + src/core/swap.h | 1 + + src/fstab-generator/fstab-generator.c | 10 +++++++ + 7 files changed, 84 insertions(+), 17 deletions(-) + +diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml +index 62a4d08b9c..481dc52454 100644 +--- a/man/systemd.swap.xml ++++ b/man/systemd.swap.xml +@@ -171,6 +171,20 @@ + + + ++ Discard= ++ ++ Enable discards, if the swap ++ backing device supports the discard or trim ++ operation. Can be one of none, ++ once, pages ++ or all. Defaults to ++ none. (See ++ swapon8 ++ for more information.) ++ ++ ++ ++ + TimeoutSec= + Configures the time to + wait for the swapon command to +diff --git a/src/core/execute.c b/src/core/execute.c +index 8c9dfde00a..07ec7a28d6 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2566,6 +2566,31 @@ int exec_command_set(ExecCommand *c, const char *path, ...) { + return 0; + } + ++int exec_command_append(ExecCommand *c, const char *path, ...) { ++ va_list ap; ++ char **l; ++ int r; ++ ++ assert(c); ++ assert(path); ++ ++ va_start(ap, path); ++ l = strv_new_ap(path, ap); ++ va_end(ap); ++ ++ if (!l) ++ return -ENOMEM; ++ ++ r = strv_extend_strv(&c->argv, l); ++ if (r < 0) { ++ strv_free(l); ++ return r; ++ } ++ ++ return 0; ++} ++ ++ + static int exec_runtime_allocate(ExecRuntime **rt) { + + if (*rt) +diff --git a/src/core/execute.h b/src/core/execute.h +index 6f35736eda..2694315155 100644 +--- a/src/core/execute.h ++++ b/src/core/execute.h +@@ -233,6 +233,7 @@ void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix); + void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix); + void exec_command_append_list(ExecCommand **l, ExecCommand *e); + int exec_command_set(ExecCommand *c, const char *path, ...); ++int exec_command_append(ExecCommand *c, const char *path, ...); + + void exec_context_init(ExecContext *c); + void exec_context_done(ExecContext *c); +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 050c5d819f..8805411f28 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -297,6 +297,7 @@ Automount.DirectoryMode, config_parse_mode, 0, + m4_dnl + Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) + Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) ++Swap.Discard, config_parse_string, 0, offsetof(Swap, parameters_fragment.discard) + Swap.TimeoutSec, config_parse_sec, 0, offsetof(Swap, timeout_usec) + EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl + CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl +diff --git a/src/core/swap.c b/src/core/swap.c +index b88a914f72..2e12824049 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -152,6 +152,9 @@ static void swap_done(Unit *u) { + free(s->parameters_fragment.what); + s->parameters_fragment.what = NULL; + ++ free(s->parameters_fragment.discard); ++ s->parameters_fragment.discard = NULL; ++ + s->exec_runtime = exec_runtime_unref(s->exec_runtime); + exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); + s->control_command = NULL; +@@ -602,10 +605,12 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { + fprintf(f, + "%sPriority: %i\n" + "%sNoAuto: %s\n" +- "%sNoFail: %s\n", ++ "%sNoFail: %s\n" ++ "%sDiscard: %s\n", + prefix, p->priority, + prefix, yes_no(p->noauto), +- prefix, yes_no(p->nofail)); ++ prefix, yes_no(p->nofail), ++ prefix, p->discard); + + if (s->control_pid > 0) + fprintf(f, +@@ -734,36 +739,46 @@ fail: + + static void swap_enter_activating(Swap *s) { + int r, priority; ++ char *discard; + + assert(s); + + s->control_command_id = SWAP_EXEC_ACTIVATE; + s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE; + +- if (s->from_fragment) ++ if (s->from_fragment) { + priority = s->parameters_fragment.priority; +- else ++ discard = s->parameters_fragment.discard; ++ } else { + priority = -1; ++ discard = NULL; ++ } ++ ++ r = exec_command_set(s->control_command, "/sbin/swapon", NULL); ++ if (r < 0) ++ goto fail; + + if (priority >= 0) { + char p[DECIMAL_STR_MAX(int)]; + + sprintf(p, "%i", priority); ++ r = exec_command_append(s->control_command, "-p", p, NULL); ++ if (r < 0) ++ goto fail; ++ } + +- r = exec_command_set( +- s->control_command, +- "/sbin/swapon", +- "-p", +- p, +- s->what, +- NULL); +- } else +- r = exec_command_set( +- s->control_command, +- "/sbin/swapon", +- s->what, +- NULL); ++ if (discard && !streq(discard, "none")) { ++ const char *discard_arg = "--discard"; ++ ++ if (!streq(discard, "all")) ++ discard_arg = strappenda("--discard=", discard); ++ ++ r = exec_command_append(s->control_command, discard_arg, NULL); ++ if (r < 0) ++ goto fail; ++ } + ++ r = exec_command_append(s->control_command, s->what, NULL); + if (r < 0) + goto fail; + +diff --git a/src/core/swap.h b/src/core/swap.h +index f2ae49b1de..3482d651ec 100644 +--- a/src/core/swap.h ++++ b/src/core/swap.h +@@ -63,6 +63,7 @@ typedef enum SwapResult { + + typedef struct SwapParameters { + char *what; ++ char *discard; + int priority; + bool noauto:1; + bool nofail:1; +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 2c38ab977c..5569325a16 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -73,6 +73,8 @@ static int mount_find_pri(struct mntent *me, int *ret) { + static int add_swap(const char *what, struct mntent *me) { + _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; + _cleanup_fclose_ FILE *f = NULL; ++ char *discard = NULL; ++ + bool noauto; + int r, pri = -1; + +@@ -118,6 +120,14 @@ static int add_swap(const char *what, struct mntent *me) { + "What=%s\n", + what); + ++ discard = mount_test_option(me->mnt_opts, "discard"); ++ if (discard) { ++ discard = strpbrk(discard, "="); ++ fprintf(f, ++ "Discard=%s\n", ++ discard ? discard+1 : "all"); ++ } ++ + if (pri >= 0) + fprintf(f, + "Priority=%i\n", diff --git a/0418-fstab-generator-properly-deal-with-discard-as-non-la.patch b/0418-fstab-generator-properly-deal-with-discard-as-non-la.patch new file mode 100644 index 0000000..5e76134 --- /dev/null +++ b/0418-fstab-generator-properly-deal-with-discard-as-non-la.patch @@ -0,0 +1,149 @@ +From 4f52d3fe2da7c3449b7fbfaa7c64a83354d3b56c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 27 Sep 2014 22:02:04 -0400 +Subject: [PATCH] fstab-generator: properly deal with discard as non-last + option + +Previous code would only return correct results when discard +was the last option. + +While at it, avoid incorrect behaviour for (invalid) 'pri' option +not followed by '=...', and also do not return -1 as the error code. +--- + src/core/swap.c | 2 +- + src/fstab-generator/fstab-generator.c | 73 ++++++++++++++++++++++++++--------- + 2 files changed, 55 insertions(+), 20 deletions(-) + +diff --git a/src/core/swap.c b/src/core/swap.c +index 2e12824049..36c9e029e9 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -610,7 +610,7 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { + prefix, p->priority, + prefix, yes_no(p->noauto), + prefix, yes_no(p->nofail), +- prefix, p->discard); ++ prefix, p->discard ?: "none"); + + if (s->control_pid > 0) + fprintf(f, +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 5569325a16..5dafcba3c0 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -46,34 +46,70 @@ static int arg_root_rw = -1; + + + static int mount_find_pri(struct mntent *me, int *ret) { +- char *end, *pri; ++ char *end, *opt; + unsigned long r; + + assert(me); + assert(ret); + +- pri = hasmntopt(me, "pri"); +- if (!pri) ++ opt = hasmntopt(me, "pri"); ++ if (!opt) + return 0; + +- pri += 4; ++ opt += strlen("pri"); ++ ++ if (*opt != '=') ++ return -EINVAL; + + errno = 0; +- r = strtoul(pri, &end, 10); ++ r = strtoul(opt + 1, &end, 10); + if (errno > 0) + return -errno; + +- if (end == pri || (*end != ',' && *end != 0)) ++ if (end == opt + 1 || (*end != ',' && *end != 0)) + return -EINVAL; + + *ret = (int) r; + return 1; + } + ++static int mount_find_discard(struct mntent *me, char **ret) { ++ char *opt, *ans; ++ size_t len; ++ ++ assert(me); ++ assert(ret); ++ ++ opt = hasmntopt(me, "discard"); ++ if (!opt) ++ return 0; ++ ++ opt += strlen("discard"); ++ ++ if (*opt == ',' || *opt == '\0') ++ ans = strdup("all"); ++ else { ++ if (*opt != '=') ++ return -EINVAL; ++ ++ len = strcspn(opt + 1, ","); ++ if (len == 0) ++ return -EINVAL; ++ ++ ans = strndup(opt + 1, len); ++ } ++ ++ if (!ans) ++ return -ENOMEM; ++ ++ *ret = ans; ++ return 1; ++} ++ + static int add_swap(const char *what, struct mntent *me) { + _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; + _cleanup_fclose_ FILE *f = NULL; +- char *discard = NULL; ++ _cleanup_free_ char *discard = NULL; + + bool noauto; + int r, pri = -1; +@@ -89,7 +125,13 @@ static int add_swap(const char *what, struct mntent *me) { + r = mount_find_pri(me, &pri); + if (r < 0) { + log_error("Failed to parse priority"); +- return pri; ++ return r; ++ } ++ ++ r = mount_find_discard(me, &discard); ++ if (r < 0) { ++ log_error("Failed to parse discard"); ++ return r; + } + + noauto = !!hasmntopt(me, "noauto"); +@@ -120,18 +162,11 @@ static int add_swap(const char *what, struct mntent *me) { + "What=%s\n", + what); + +- discard = mount_test_option(me->mnt_opts, "discard"); +- if (discard) { +- discard = strpbrk(discard, "="); +- fprintf(f, +- "Discard=%s\n", +- discard ? discard+1 : "all"); +- } +- + if (pri >= 0) +- fprintf(f, +- "Priority=%i\n", +- pri); ++ fprintf(f, "Priority=%i\n", pri); ++ ++ if (discard) ++ fprintf(f, "Discard=%s\n", discard); + + fflush(f); + if (ferror(f)) { diff --git a/0419-core-swap-follow-the-configured-unit-by-default.patch b/0419-core-swap-follow-the-configured-unit-by-default.patch new file mode 100644 index 0000000..6a01129 --- /dev/null +++ b/0419-core-swap-follow-the-configured-unit-by-default.patch @@ -0,0 +1,59 @@ +From cdc8982030271785d650af410230397bbb5a4be9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 28 Sep 2014 10:37:52 -0400 +Subject: [PATCH] core/swap: follow the configured unit by default + +Phenomenon: parameters configured in /etc/fstab for swap units are +ignored. E.g. pri= settings have no effect when systemd starts swap +units. What is even more confusing, .swap units for the name used in +/etc/fstab initially show proper values for Priority=, but after +starting them, they are re-initalized from /proc/swaps and show the -1 +value from /proc/swaps. + +Change swap units to follow the original configured unit. This way +proper settings are used when starting the swap. +--- + src/core/swap.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/src/core/swap.c b/src/core/swap.c +index 36c9e029e9..ef90d0efde 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -1208,11 +1208,25 @@ static Unit *swap_following(Unit *u) { + + assert(s); + +- if (streq_ptr(s->what, s->devnode)) ++ /* If the user configured the swap through /etc/fstab or ++ * a device unit, follow that. */ ++ ++ if (s->from_fragment) + return NULL; + +- /* Make everybody follow the unit that's named after the swap +- * device in the kernel */ ++ LIST_FOREACH_AFTER(same_devnode, other, s) ++ if (other->from_fragment) ++ return UNIT(other); ++ ++ LIST_FOREACH_BEFORE(same_devnode, other, s) ++ if (other->from_fragment) ++ return UNIT(other); ++ ++ /* Otherwise make everybody follow the unit that's named after ++ * the swap device in the kernel */ ++ ++ if (streq_ptr(s->what, s->devnode)) ++ return NULL; + + LIST_FOREACH_AFTER(same_devnode, other, s) + if (streq_ptr(other->what, other->devnode)) +@@ -1225,6 +1239,7 @@ static Unit *swap_following(Unit *u) { + first = other; + } + ++ /* Fall back to the first on the list */ + return UNIT(first); + } + diff --git a/0420-core-swap-advertise-Discard-over-dbus.patch b/0420-core-swap-advertise-Discard-over-dbus.patch new file mode 100644 index 0000000..bfb0782 --- /dev/null +++ b/0420-core-swap-advertise-Discard-over-dbus.patch @@ -0,0 +1,50 @@ +From 4afbccded23f5144e39a7f7b243393799186ba39 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 28 Sep 2014 22:13:07 -0400 +Subject: [PATCH] core/swap: advertise Discard over dbus + +--- + src/core/dbus-swap.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c +index 93eae53c29..c854716b48 100644 +--- a/src/core/dbus-swap.c ++++ b/src/core/dbus-swap.c +@@ -55,12 +55,36 @@ static int property_get_priority( + return sd_bus_message_append(reply, "i", p); + } + ++static int property_get_discard( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ++ Swap *s = SWAP(userdata); ++ const char *p; ++ ++ assert(bus); ++ assert(reply); ++ assert(s); ++ ++ if (s->from_fragment) ++ p = s->parameters_fragment.discard ?: "none"; ++ else ++ p = "none"; ++ return sd_bus_message_append(reply, "s", p); ++} ++ + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult); + + const sd_bus_vtable bus_swap_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("What", "s", NULL, offsetof(Swap, what), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Priority", "i", property_get_priority, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), ++ SD_BUS_PROPERTY("Discard", "s", property_get_discard, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Swap, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Swap, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Swap, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), diff --git a/0421-core-dbus-simplify-handling-of-CPUQuotaPerSecUSec.patch b/0421-core-dbus-simplify-handling-of-CPUQuotaPerSecUSec.patch new file mode 100644 index 0000000..461517b --- /dev/null +++ b/0421-core-dbus-simplify-handling-of-CPUQuotaPerSecUSec.patch @@ -0,0 +1,48 @@ +From ee26bcc0387f6eda83878eb85a08c01ee0d82c44 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 28 Sep 2014 23:42:33 -0400 +Subject: [PATCH] core/dbus: simplify handling of CPUQuotaPerSecUSec + +No functional change intended. +--- + src/core/dbus-cgroup.c | 20 +------------------- + 1 file changed, 1 insertion(+), 19 deletions(-) + +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index eb7c2b9d27..900566c29b 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -133,24 +133,6 @@ static int property_get_device_allow( + return sd_bus_message_close_container(reply); + } + +-static int property_get_cpu_quota_per_sec_usec( +- sd_bus *bus, +- const char *path, +- const char *interface, +- const char *property, +- sd_bus_message *reply, +- void *userdata, +- sd_bus_error *error) { +- +- CGroupContext *c = userdata; +- +- assert(bus); +- assert(reply); +- assert(c); +- +- return sd_bus_message_append(reply, "t", c->cpu_quota_per_sec_usec); +-} +- + static int property_get_ulong_as_u64( + sd_bus *bus, + const char *path, +@@ -174,7 +156,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = { + 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("CPUQuotaPerSecUSec", "t", property_get_cpu_quota_per_sec_usec, 0, 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), diff --git a/0422-Do-not-format-USEC_INFINITY-as-NULL.patch b/0422-Do-not-format-USEC_INFINITY-as-NULL.patch new file mode 100644 index 0000000..100efcb --- /dev/null +++ b/0422-Do-not-format-USEC_INFINITY-as-NULL.patch @@ -0,0 +1,161 @@ +From b1d6dcf5a5c5aa02843c026dede0638f77798cb4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 29 Sep 2014 07:31:14 -0500 +Subject: [PATCH] Do not format USEC_INFINITY as NULL + +systemctl would print 'CPUQuotaPerSecUSec=(null)' for no limit. This +does not look right. + +Since USEC_INFINITY is one of the valid values, format_timespan() +could return NULL, and we should wrap every use of it in strna() or +similar. But most callers didn't do that, and it seems more robust to +return a string ("infinity") that makes sense most of the time, even +if in some places the result will not be grammatically correct. +--- + src/core/cgroup.c | 2 +- + src/core/timer.c | 2 +- + src/network/networkd-link.c | 12 ++++-------- + src/shared/time-util.c | 21 +++++++++++++++------ + src/test/test-time.c | 7 +++++++ + 5 files changed, 28 insertions(+), 16 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 6c6e4f5e7b..e604c3cbc6 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -111,7 +111,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + prefix, yes_no(c->memory_accounting), + prefix, c->cpu_shares, + prefix, c->startup_cpu_shares, +- prefix, strna(format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1)), ++ prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1), + prefix, c->blockio_weight, + prefix, c->startup_blockio_weight, + prefix, c->memory_limit, +diff --git a/src/core/timer.c b/src/core/timer.c +index dc0f289c7a..a3713e2140 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -242,7 +242,7 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) { + "%s%s: %s\n", + prefix, + timer_base_to_string(v->base), +- strna(format_timespan(timespan1, sizeof(timespan1), v->value, 0))); ++ format_timespan(timespan1, sizeof(timespan1), v->value, 0)); + } + } + } +diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c +index 427f6953c5..dcbe38a90a 100644 +--- a/src/network/networkd-link.c ++++ b/src/network/networkd-link.c +@@ -1475,12 +1475,10 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, + case RTM_NEWADDR: + if (!address_dropped) + log_debug_link(link, "added address: %s/%u (valid for %s)", +- buf, address->prefixlen, +- strna(valid_str)); ++ buf, address->prefixlen, valid_str); + else + log_debug_link(link, "updated address: %s/%u (valid for %s)", +- buf, address->prefixlen, +- strna(valid_str)); ++ buf, address->prefixlen, valid_str); + + LIST_PREPEND(addresses, link->addresses, address); + address = NULL; +@@ -1491,15 +1489,13 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, + case RTM_DELADDR: + if (address_dropped) { + log_debug_link(link, "removed address: %s/%u (valid for %s)", +- buf, address->prefixlen, +- strna(valid_str)); ++ buf, address->prefixlen, valid_str); + + link_save(link); + } else + log_warning_link(link, + "removing non-existent address: %s/%u (valid for %s)", +- buf, address->prefixlen, +- strna(valid_str)); ++ buf, address->prefixlen, valid_str); + + break; + default: +diff --git a/src/shared/time-util.c b/src/shared/time-util.c +index 2dc01e6ed3..066ef973ac 100644 +--- a/src/shared/time-util.c ++++ b/src/shared/time-util.c +@@ -279,11 +279,8 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { + assert(buf); + assert(l > 0); + +- if (t == USEC_INFINITY) +- return NULL; +- +- if (t <= 0) { +- snprintf(p, l, "0"); ++ if (t == USEC_INFINITY || t <= 0) { ++ strncpy(p, t == USEC_INFINITY ? "infinity" : "0", l); + p[l-1] = 0; + return p; + } +@@ -628,7 +625,7 @@ int parse_sec(const char *t, usec_t *usec) { + { "", USEC_PER_SEC }, /* default is sec */ + }; + +- const char *p; ++ const char *p, *s; + usec_t r = 0; + bool something = false; + +@@ -636,6 +633,18 @@ int parse_sec(const char *t, usec_t *usec) { + assert(usec); + + p = t; ++ ++ p += strspn(p, WHITESPACE); ++ s = startswith(p, "infinity"); ++ if (s) { ++ s += strspn(s, WHITESPACE); ++ if (*s != 0) ++ return -EINVAL; ++ ++ *usec = USEC_INFINITY; ++ return 0; ++ } ++ + for (;;) { + long long l, z = 0; + char *e; +diff --git a/src/test/test-time.c b/src/test/test-time.c +index 87e7ae742a..8cfc4cc4fe 100644 +--- a/src/test/test-time.c ++++ b/src/test/test-time.c +@@ -43,12 +43,18 @@ static void test_parse_sec(void) { + assert_se(u == 2500 * USEC_PER_MSEC); + assert_se(parse_sec(".7", &u) >= 0); + assert_se(u == 700 * USEC_PER_MSEC); ++ assert_se(parse_sec("infinity", &u) >= 0); ++ assert_se(u == USEC_INFINITY); ++ assert_se(parse_sec(" infinity ", &u) >= 0); ++ assert_se(u == USEC_INFINITY); + + assert_se(parse_sec(" xyz ", &u) < 0); + assert_se(parse_sec("", &u) < 0); + assert_se(parse_sec(" . ", &u) < 0); + assert_se(parse_sec(" 5. ", &u) < 0); + assert_se(parse_sec(".s ", &u) < 0); ++ assert_se(parse_sec(" infinity .7", &u) < 0); ++ assert_se(parse_sec(".3 infinity", &u) < 0); + } + + static void test_parse_nsec(void) { +@@ -125,6 +131,7 @@ static void test_format_timespan(usec_t accuracy) { + test_format_timespan_one(986087, accuracy); + test_format_timespan_one(500 * USEC_PER_MSEC, accuracy); + test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy); ++ test_format_timespan_one(USEC_INFINITY, accuracy); + } + + static void test_timezone_is_valid(void) { diff --git a/0423-nspawn-log-when-tearing-down-of-loop-device-fails.patch b/0423-nspawn-log-when-tearing-down-of-loop-device-fails.patch new file mode 100644 index 0000000..fbe209d --- /dev/null +++ b/0423-nspawn-log-when-tearing-down-of-loop-device-fails.patch @@ -0,0 +1,44 @@ +From e8c8ddccfc63574069c30b7e75f0ccfd5b03eab9 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 29 Sep 2014 13:20:54 +0200 +Subject: [PATCH] nspawn: log when tearing down of loop device fails + +--- + src/nspawn/nspawn.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 4c1cfabca4..34436b82a2 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -2607,20 +2607,27 @@ static int mount_devices( + + static void loop_remove(int nr, int *image_fd) { + _cleanup_close_ int control = -1; ++ int r; + + if (nr < 0) + return; + + if (image_fd && *image_fd >= 0) { +- ioctl(*image_fd, LOOP_CLR_FD); ++ r = ioctl(*image_fd, LOOP_CLR_FD); ++ if (r < 0) ++ log_warning("Failed to close loop image: %m"); + *image_fd = safe_close(*image_fd); + } + + control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); +- if (control < 0) ++ if (control < 0) { ++ log_warning("Failed to open /dev/loop-control: %m"); + return; ++ } + +- ioctl(control, LOOP_CTL_REMOVE, nr); ++ r = ioctl(control, LOOP_CTL_REMOVE, nr); ++ if (r < 0) ++ log_warning("Failed to remove loop %d: %m", nr); + } + + static int spawn_getent(const char *database, const char *key, pid_t *rpid) { diff --git a/0424-util-silence-coverity.patch b/0424-util-silence-coverity.patch new file mode 100644 index 0000000..f71703c --- /dev/null +++ b/0424-util-silence-coverity.patch @@ -0,0 +1,46 @@ +From 9fb02b1d5df153aa522256aec821e422cca7f284 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Mon, 29 Sep 2014 14:30:15 +0200 +Subject: [PATCH] util: silence coverity + +Make it clear in the code that ignoring a failed safe_ato?() is intentional. +--- + src/shared/util.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 30b0364b64..ec33fc1263 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3272,8 +3272,13 @@ unsigned columns(void) { + + c = 0; + e = getenv("COLUMNS"); +- if (e) +- safe_atoi(e, &c); ++ if (e) { ++ int r; ++ ++ r = safe_atoi(e, &c); ++ if (r < 0) {} ++ /* do nothing, we fall back to c = 0 */ ++ } + + if (c <= 0) + c = fd_columns(STDOUT_FILENO); +@@ -3306,8 +3311,13 @@ unsigned lines(void) { + + l = 0; + e = getenv("LINES"); +- if (e) +- safe_atou(e, &l); ++ if (e) { ++ int r; ++ ++ r = safe_atou(e, &l); ++ if (r < 0) {} ++ /* do nothing, we fall back to l = 0 */ ++ } + + if (l <= 0) + l = fd_lines(STDOUT_FILENO); diff --git a/0425-udev-hwdb-New-Entry-for-Dell-XPS12-9Q33-keyboard.patch b/0425-udev-hwdb-New-Entry-for-Dell-XPS12-9Q33-keyboard.patch new file mode 100644 index 0000000..8f0b756 --- /dev/null +++ b/0425-udev-hwdb-New-Entry-for-Dell-XPS12-9Q33-keyboard.patch @@ -0,0 +1,26 @@ +From 24119cf10c7ed58a8fc0851745149dcc6dd5757f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Stefan=20Br=C3=BCns?= +Date: Mon, 29 Sep 2014 22:32:10 -0400 +Subject: [PATCH] udev/hwdb: New Entry for Dell XPS12 9Q33 keyboard + +https://bugs.freedesktop.org/show_bug.cgi?id=84437 +--- + hwdb/60-keyboard.hwdb | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb +index 0ffcb83277..8a1baa7c4b 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -243,6 +243,11 @@ keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:pvr* + keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:pvr* + KEYBOARD_KEY_8c=!unknown + ++# Dell XPS12 9Q33 ++keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr* ++ KEYBOARD_KEY_88=wlan ++ KEYBOARD_KEY_65=switchvideomode # Screen Rotate ++ + # Dell Latitude microphone mute + keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude* + KEYBOARD_KEY_150=f20 # Mic mute toggle, should be micmute diff --git a/0426-core-execute-don-t-leak-strv.patch b/0426-core-execute-don-t-leak-strv.patch new file mode 100644 index 0000000..59a2000 --- /dev/null +++ b/0426-core-execute-don-t-leak-strv.patch @@ -0,0 +1,35 @@ +From e63ff941eaa012ffd003e3791438c73b8a26227d Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 30 Sep 2014 11:34:01 +0200 +Subject: [PATCH] core: execute - don't leak strv + +--- + src/core/execute.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 07ec7a28d6..8b9bb27137 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2567,8 +2567,8 @@ int exec_command_set(ExecCommand *c, const char *path, ...) { + } + + int exec_command_append(ExecCommand *c, const char *path, ...) { ++ _cleanup_strv_free_ char **l = NULL; + va_list ap; +- char **l; + int r; + + assert(c); +@@ -2582,10 +2582,8 @@ int exec_command_append(ExecCommand *c, const char *path, ...) { + return -ENOMEM; + + r = strv_extend_strv(&c->argv, l); +- if (r < 0) { +- strv_free(l); ++ if (r < 0) + return r; +- } + + return 0; + } diff --git a/0427-shared-util-use-nicer-idiom-to-silence-Coverity.patch b/0427-shared-util-use-nicer-idiom-to-silence-Coverity.patch new file mode 100644 index 0000000..cc2c1cc --- /dev/null +++ b/0427-shared-util-use-nicer-idiom-to-silence-Coverity.patch @@ -0,0 +1,30 @@ +From c6828d2794fcd00b6b0d2a040301c90ad424d14f Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Tue, 30 Sep 2014 11:37:28 +0200 +Subject: [PATCH] shared: util - use nicer idiom to silence Coverity + +Suggested by Zbigniew. +--- + src/shared/util.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index ec33fc1263..ebacee55b1 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3272,13 +3272,8 @@ unsigned columns(void) { + + c = 0; + e = getenv("COLUMNS"); +- if (e) { +- int r; +- +- r = safe_atoi(e, &c); +- if (r < 0) {} +- /* do nothing, we fall back to c = 0 */ +- } ++ if (e) ++ (void) safe_atoi(e, &c); + + if (c <= 0) + c = fd_columns(STDOUT_FILENO); diff --git a/0428-vconsole-silence-coverity.patch b/0428-vconsole-silence-coverity.patch new file mode 100644 index 0000000..48465ea --- /dev/null +++ b/0428-vconsole-silence-coverity.patch @@ -0,0 +1,45 @@ +From 791a4fd837c713fe742d32cde1ce16f754dd30df Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 30 Sep 2014 21:14:58 +0200 +Subject: [PATCH] vconsole: silence coverity + +Let's silence coverity here too. There is not much to do if the +ioctls to copy the fonts and character maps should fail. +--- + src/vconsole/vconsole-setup.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c +index 645b1e6994..0db97f88bc 100644 +--- a/src/vconsole/vconsole-setup.c ++++ b/src/vconsole/vconsole-setup.c +@@ -212,15 +212,15 @@ static void font_copy_to_all_vcs(int fd) { + /* copy font from active VT, where the font was uploaded to */ + cfo.op = KD_FONT_OP_COPY; + cfo.height = vcs.v_active-1; /* tty1 == index 0 */ +- ioctl(vcfd, KDFONTOP, &cfo); ++ (void) ioctl(vcfd, KDFONTOP, &cfo); + + /* copy map of 8bit chars */ + if (ioctl(fd, GIO_SCRNMAP, map8) >= 0) +- ioctl(vcfd, PIO_SCRNMAP, map8); ++ (void) ioctl(vcfd, PIO_SCRNMAP, map8); + + /* copy map of 8bit chars -> 16bit Unicode values */ + if (ioctl(fd, GIO_UNISCRNMAP, map16) >= 0) +- ioctl(vcfd, PIO_UNISCRNMAP, map16); ++ (void) ioctl(vcfd, PIO_UNISCRNMAP, map16); + + /* copy unicode translation table */ + /* unimapd is a ushort count and a pointer to an +@@ -230,8 +230,8 @@ static void font_copy_to_all_vcs(int fd) { + if (ioctl(fd, GIO_UNIMAP, &unimapd) >= 0) { + struct unimapinit adv = { 0, 0, 0 }; + +- ioctl(vcfd, PIO_UNIMAPCLR, &adv); +- ioctl(vcfd, PIO_UNIMAP, &unimapd); ++ (void) ioctl(vcfd, PIO_UNIMAPCLR, &adv); ++ (void) ioctl(vcfd, PIO_UNIMAP, &unimapd); + } + } + } diff --git a/0429-test-path-util-fix-a-mem-leak-and-avoid-confusing-co.patch b/0429-test-path-util-fix-a-mem-leak-and-avoid-confusing-co.patch new file mode 100644 index 0000000..684b386 --- /dev/null +++ b/0429-test-path-util-fix-a-mem-leak-and-avoid-confusing-co.patch @@ -0,0 +1,65 @@ +From 59ae3a957388bb057c3388ee288c8fc96c2b0098 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 30 Sep 2014 22:18:18 +0200 +Subject: [PATCH] test-path-util: fix a mem leak and avoid confusing coverity + +Found with coverity. Fixes CID#1237754 and #1237790 +--- + src/test/test-path-util.c | 37 ++++++++++++++++++++++--------------- + 1 file changed, 22 insertions(+), 15 deletions(-) + +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index 01afb3e6fe..63d64b28b0 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -163,17 +163,24 @@ static void test_prefixes(void) { + } + + static void test_path_join(void) { +- assert_se(streq(path_join("/root", "/a/b", "/c"), "/root/a/b/c")); +- assert_se(streq(path_join("/root", "a/b", "c"), "/root/a/b/c")); +- assert_se(streq(path_join("/root", "/a/b", "c"), "/root/a/b/c")); +- assert_se(streq(path_join("/root", "/", "c"), "/root//c")); +- assert_se(streq(path_join("/root", "/", NULL), "/root/")); +- +- assert_se(streq(path_join(NULL, "/a/b", "/c"), "/a/b/c")); +- assert_se(streq(path_join(NULL, "a/b", "c"), "a/b/c")); +- assert_se(streq(path_join(NULL, "/a/b", "c"), "/a/b/c")); +- assert_se(streq(path_join(NULL, "/", "c"), "//c")); +- assert_se(streq(path_join(NULL, "/", NULL), "/")); ++ ++#define test_join(root, path, rest, expected) { \ ++ _cleanup_free_ char *z = NULL; \ ++ z = path_join(root, path, rest); \ ++ assert_se(streq(z, expected)); \ ++ } ++ ++ test_join("/root", "/a/b", "/c", "/root/a/b/c"); ++ test_join("/root", "a/b", "c", "/root/a/b/c"); ++ test_join("/root", "/a/b", "c", "/root/a/b/c"); ++ test_join("/root", "/", "c", "/root//c"); ++ test_join("/root", "/", NULL, "/root/"); ++ ++ test_join(NULL, "/a/b", "/c", "/a/b/c"); ++ test_join(NULL, "a/b", "c", "a/b/c"); ++ test_join(NULL, "/a/b", "c", "/a/b/c"); ++ test_join(NULL, "/", "c", "//c"); ++ test_join(NULL, "/", NULL, "/"); + } + + static void test_fsck_exists(void) { +@@ -192,10 +199,10 @@ static void test_make_relative(void) { + assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0); + assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0); + +-#define test(from_dir, to_path, expected) { \ +- path_make_relative(from_dir, to_path, &result); \ +- assert_se(streq(result, expected)); \ +- free(result); \ ++#define test(from_dir, to_path, expected) { \ ++ _cleanup_free_ char *z = NULL; \ ++ path_make_relative(from_dir, to_path, &z); \ ++ assert_se(streq(z, expected)); \ + } + + test("/", "/", "."); diff --git a/0430-test-date-don-t-fail-test-if-log_max_level-is-higher.patch b/0430-test-date-don-t-fail-test-if-log_max_level-is-higher.patch new file mode 100644 index 0000000..640801c --- /dev/null +++ b/0430-test-date-don-t-fail-test-if-log_max_level-is-higher.patch @@ -0,0 +1,34 @@ +From 14c35ce7c1b9649bef14efeb3121660e541dd97a Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 30 Sep 2014 23:30:30 +0200 +Subject: [PATCH] test-date: don't fail test if log_max_level is higher than + LOG_INFO + +--- + src/test/test-date.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/test/test-date.c b/src/test/test-date.c +index 0586b78b6d..00b569080c 100644 +--- a/src/test/test-date.c ++++ b/src/test/test-date.c +@@ -28,7 +28,8 @@ static void test_one(const char *p) { + char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX]; + + assert_se(parse_timestamp(p, &t) >= 0); +- log_info("%s", format_timestamp(buf, sizeof(buf), t)); ++ format_timestamp(buf, sizeof(buf), t); ++ log_info("%s", buf); + + /* Chop off timezone */ + *strrchr(buf, ' ') = 0; +@@ -36,7 +37,8 @@ static void test_one(const char *p) { + assert_se(parse_timestamp(buf, &q) >= 0); + assert_se(q == t); + +- log_info("%s", strna(format_timestamp_relative(buf_relative, sizeof(buf_relative), t))); ++ format_timestamp_relative(buf_relative, sizeof(buf_relative), t); ++ log_info("%s", strna(buf_relative)); + assert_se(parse_timestamp(buf, &q) >= 0); + } + diff --git a/0431-test-fileio-Remove-dead-check.patch b/0431-test-fileio-Remove-dead-check.patch new file mode 100644 index 0000000..aae0292 --- /dev/null +++ b/0431-test-fileio-Remove-dead-check.patch @@ -0,0 +1,23 @@ +From 2b01a801f6c597a60a1e622978bf7ac0105b9666 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Tue, 30 Sep 2014 23:37:10 +0200 +Subject: [PATCH] test-fileio: Remove dead check + +t cannot be null here +--- + src/test/test-fileio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index 1b99828191..ad65abf426 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -258,7 +258,7 @@ static void test_status_field(void) { + assert_se(safe_atollu(s, &buffers) == 0); + } + +- if (p && t) ++ if (p) + assert(buffers < total); + + /* Seccomp should be a good test for field full of zeros. */ diff --git a/0432-core-limit-timestamp-to-sane-precision.patch b/0432-core-limit-timestamp-to-sane-precision.patch new file mode 100644 index 0000000..abe6c93 --- /dev/null +++ b/0432-core-limit-timestamp-to-sane-precision.patch @@ -0,0 +1,23 @@ +From fdb14b7ef40d1f19f3bd7c8fa2a3821c2be87a5e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 1 Oct 2014 07:34:05 -0500 +Subject: [PATCH] core: limit timestamp to sane precision + +Anything below .1 s is meaningless anyway. +--- + src/core/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 64c2b3f3a1..1a62e04c80 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1725,7 +1725,7 @@ int main(int argc, char *argv[]) { + after_startup = now(CLOCK_MONOTONIC); + log_full(arg_action == ACTION_TEST ? LOG_INFO : LOG_DEBUG, + "Loaded units and determined initial transaction in %s.", +- format_timespan(timespan, sizeof(timespan), after_startup - before_startup, 0)); ++ format_timespan(timespan, sizeof(timespan), after_startup - before_startup, 100 * USEC_PER_MSEC)); + + if (arg_action == ACTION_TEST) { + printf("-> By jobs:\n"); diff --git a/0433-tmpfiles-use-allocated-buffer-for-path.patch b/0433-tmpfiles-use-allocated-buffer-for-path.patch new file mode 100644 index 0000000..1d9f2e8 --- /dev/null +++ b/0433-tmpfiles-use-allocated-buffer-for-path.patch @@ -0,0 +1,37 @@ +From 9348f0e690c28f86a69c96e3e9b9f19a31c6d466 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 1 Oct 2014 07:33:22 -0500 +Subject: [PATCH] tmpfiles: use allocated buffer for path + +Paths can in principle be longer then PATH_MAX, so +simply allocate the buffer with malloc(). + +CID #1237773 +--- + src/tmpfiles/tmpfiles.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 7eafd6bb30..dafb9aee2f 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1064,7 +1064,7 @@ static int clean_item(Item *i) { + + static int process_item(Item *i) { + int r, q, p; +- char prefix[PATH_MAX]; ++ _cleanup_free_ char *prefix = NULL; + + assert(i); + +@@ -1073,6 +1073,10 @@ static int process_item(Item *i) { + + i->done = true; + ++ prefix = malloc(strlen(i->path) + 1); ++ if (!prefix) ++ return log_oom(); ++ + PATH_FOREACH_PREFIX(prefix, i->path) { + Item *j; + diff --git a/0434-shared-util-use-nicer-idiom-to-silence-Coverity.patch b/0434-shared-util-use-nicer-idiom-to-silence-Coverity.patch new file mode 100644 index 0000000..355e062 --- /dev/null +++ b/0434-shared-util-use-nicer-idiom-to-silence-Coverity.patch @@ -0,0 +1,30 @@ +From acb3b3ddc082880eaaa1d7773296ad9abd756f23 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 30 Sep 2014 07:44:04 -0400 +Subject: [PATCH] shared: util - use nicer idiom to silence Coverity + +Change the other spot too. +--- + src/shared/util.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index ebacee55b1..bbd9bd11d6 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3306,13 +3306,8 @@ unsigned lines(void) { + + l = 0; + e = getenv("LINES"); +- if (e) { +- int r; +- +- r = safe_atou(e, &l); +- if (r < 0) {} +- /* do nothing, we fall back to l = 0 */ +- } ++ if (e) ++ (void) safe_atou(e, &l); + + if (l <= 0) + l = fd_lines(STDOUT_FILENO); diff --git a/0435-tests-add-tests-for-hashmap-set-_steal_first.patch b/0435-tests-add-tests-for-hashmap-set-_steal_first.patch new file mode 100644 index 0000000..8d9cdb9 --- /dev/null +++ b/0435-tests-add-tests-for-hashmap-set-_steal_first.patch @@ -0,0 +1,130 @@ +From 647f68249f90855814de6eb6b0959c6096b41cae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 1 Oct 2014 09:32:16 -0400 +Subject: [PATCH] tests: add tests for {hashmap,set}_steal_first + +Just to make sure that coverity is wrong. +--- + Makefile.am | 7 +++++++ + src/test/test-hashmap.c | 21 +++++++++++++++++++++ + src/test/test-set.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 75 insertions(+) + create mode 100644 src/test/test-set.c + +diff --git a/Makefile.am b/Makefile.am +index 7bb7f75915..9e087bd9fb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1341,6 +1341,7 @@ tests += \ + test-fileio \ + test-time \ + test-hashmap \ ++ test-set \ + test-list \ + test-tables \ + test-device-nodes \ +@@ -1572,6 +1573,12 @@ test_hashmap_SOURCES = \ + test_hashmap_LDADD = \ + libsystemd-core.la + ++test_set_SOURCES = \ ++ src/test/test-set.c ++ ++test_set_LDADD = \ ++ libsystemd-core.la ++ + test_xml_SOURCES = \ + src/test/test-xml.c + +diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c +index d9863f8dab..f4afbb8e9d 100644 +--- a/src/test/test-hashmap.c ++++ b/src/test/test-hashmap.c +@@ -507,6 +507,26 @@ static void test_hashmap_steal_first_key(void) { + assert_se(hashmap_isempty(m)); + } + ++static void test_hashmap_steal_first(void) { ++ _cleanup_hashmap_free_ Hashmap *m = NULL; ++ int seen[3] = {}; ++ char *val; ++ ++ m = hashmap_new(&string_hash_ops); ++ assert_se(m); ++ ++ assert_se(hashmap_put(m, "key 1", (void*) "1") == 1); ++ assert_se(hashmap_put(m, "key 2", (void*) "22") == 1); ++ assert_se(hashmap_put(m, "key 3", (void*) "333") == 1); ++ ++ while ((val = hashmap_steal_first(m))) ++ seen[strlen(val) - 1]++; ++ ++ assert(seen[0] == 1 && seen[1] == 1 && seen[2] == 1); ++ ++ assert_se(hashmap_isempty(m)); ++} ++ + static void test_hashmap_clear_free_free(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + +@@ -560,6 +580,7 @@ int main(int argc, const char *argv[]) { + test_hashmap_many(); + test_hashmap_first_key(); + test_hashmap_steal_first_key(); ++ test_hashmap_steal_first(); + test_hashmap_clear_free_free(); + test_uint64_compare_func(); + test_trivial_compare_func(); +diff --git a/src/test/test-set.c b/src/test/test-set.c +new file mode 100644 +index 0000000000..060dba42df +--- /dev/null ++++ b/src/test/test-set.c +@@ -0,0 +1,47 @@ ++/*** ++ 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 "util.h" ++#include "set.h" ++ ++static void test_set_steal_first(void) { ++ _cleanup_set_free_ Set *m = NULL; ++ int seen[3] = {}; ++ char *val; ++ ++ m = set_new(&string_hash_ops); ++ assert_se(m); ++ ++ assert_se(set_put(m, (void*) "1") == 1); ++ assert_se(set_put(m, (void*) "22") == 1); ++ assert_se(set_put(m, (void*) "333") == 1); ++ ++ while ((val = set_steal_first(m))) ++ seen[strlen(val) - 1]++; ++ ++ assert(seen[0] == 1 && seen[1] == 1 && seen[2] == 1); ++ ++ assert_se(set_isempty(m)); ++} ++ ++int main(int argc, const char *argv[]) { ++ test_set_steal_first(); ++ ++ return 0; ++} diff --git a/0436-gitignore-add-test-set.patch b/0436-gitignore-add-test-set.patch new file mode 100644 index 0000000..93f4f12 --- /dev/null +++ b/0436-gitignore-add-test-set.patch @@ -0,0 +1,21 @@ +From 56a7dd42d3a680691f417bd8a4c46ea1b6283ff5 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Wed, 1 Oct 2014 23:22:02 +0200 +Subject: [PATCH] gitignore: add test-set + +--- + .gitignore | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/.gitignore b/.gitignore +index b78a4cb4e1..cb1af8de5b 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -220,6 +220,7 @@ + /test-rtnl + /test-rtnl-manual + /test-sched-prio ++/test-set + /test-sleep + /test-socket-util + /test-ssd diff --git a/0437-Remove-repeated-includes.patch b/0437-Remove-repeated-includes.patch new file mode 100644 index 0000000..b99f7bc --- /dev/null +++ b/0437-Remove-repeated-includes.patch @@ -0,0 +1,89 @@ +From cf4acf84c6304d34108dadd5e87c9a19ca24dceb Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Wed, 1 Oct 2014 23:15:34 +0200 +Subject: [PATCH] Remove repeated includes + +In pty.c there was both an include of our pty.h and the system installed pty.h. +The latter contains only two functions openpty and forkpty. We use neither so +I assume it was a typo and removed it. We still compile and pass all tests. +--- + src/bus-proxyd/bus-proxyd.c | 1 - + src/bus-proxyd/test-bus-policy.c | 1 - + src/shared/locale-util.c | 1 - + src/shared/missing.h | 1 - + src/shared/pty.c | 1 - + src/sysv-generator/sysv-generator.c | 1 - + 6 files changed, 6 deletions(-) + +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +index 6a0fc7edfb..5d58cd2af4 100644 +--- a/src/bus-proxyd/bus-proxyd.c ++++ b/src/bus-proxyd/bus-proxyd.c +@@ -40,7 +40,6 @@ + #include "bus-internal.h" + #include "bus-message.h" + #include "bus-util.h" +-#include "bus-internal.h" + #include "build.h" + #include "strv.h" + #include "def.h" +diff --git a/src/bus-proxyd/test-bus-policy.c b/src/bus-proxyd/test-bus-policy.c +index 7bcebef905..5267788b70 100644 +--- a/src/bus-proxyd/test-bus-policy.c ++++ b/src/bus-proxyd/test-bus-policy.c +@@ -36,7 +36,6 @@ + #include "bus-internal.h" + #include "bus-message.h" + #include "bus-util.h" +-#include "bus-internal.h" + #include "build.h" + #include "strv.h" + #include "def.h" +diff --git a/src/shared/locale-util.c b/src/shared/locale-util.c +index d5eaff3d9e..9addb05f09 100644 +--- a/src/shared/locale-util.c ++++ b/src/shared/locale-util.c +@@ -25,7 +25,6 @@ + #include "util.h" + #include "utf8.h" + #include "strv.h" +-#include "util.h" + + #include "locale-util.h" + +diff --git a/src/shared/missing.h b/src/shared/missing.h +index b441149945..031fe2d1ce 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + + #ifdef HAVE_AUDIT + #include +diff --git a/src/shared/pty.c b/src/shared/pty.c +index 31123e5af2..adcb32d0be 100644 +--- a/src/shared/pty.c ++++ b/src/shared/pty.c +@@ -46,7 +46,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 43bcaa862f..6e4cdd694e 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -31,7 +31,6 @@ + #include "path-util.h" + #include "path-lookup.h" + #include "log.h" +-#include "strv.h" + #include "unit.h" + #include "unit-name.h" + #include "special.h" diff --git a/0438-core-swap-only-make-configured-units-part-of-swap.ta.patch b/0438-core-swap-only-make-configured-units-part-of-swap.ta.patch new file mode 100644 index 0000000..6835079 --- /dev/null +++ b/0438-core-swap-only-make-configured-units-part-of-swap.ta.patch @@ -0,0 +1,73 @@ +From 3018d31238caabc2e204aa161e647dc1c1b5d1c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 2 Oct 2014 00:11:36 -0400 +Subject: [PATCH] core/swap: only make configured units part of swap.target + +We used to make all .swap units either RequiredBy=swap.target or +WantedBy=swap.target. But swap.target should be the "configured swap +units", either through /etc/fstab or non-generated .swap units. It +is surprising when systemd starts treating a swap device that was +possibly temporarily enabled as a hard dependency for other units. +So do not add dependencies with swap.target for units gleaned from +/proc/swaps. + +Similarly, we added dependencies for all aliases of the device name, +which clutters up the dependency graph but does not seem to bring any +value, since the status of those following units is consistent with +the main one anyway. + +This should be a fix for [1], and it seems the right thing to do +anyway. + +[1] https://bugzilla.redhat.com/show_bug.cgi?id=1114786 +--- + src/core/swap.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/src/core/swap.c b/src/core/swap.c +index ef90d0efde..b2ca048bcb 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -213,7 +213,7 @@ static int swap_add_device_links(Swap *s) { + } + + static int swap_add_default_dependencies(Swap *s) { +- bool nofail = false, noauto = false; ++ bool nofail, noauto; + int r; + + assert(s); +@@ -228,23 +228,25 @@ static int swap_add_default_dependencies(Swap *s) { + if (r < 0) + return r; + +- if (s->from_fragment) { +- SwapParameters *p = &s->parameters_fragment; ++ if (!s->from_fragment) ++ /* The swap unit can either be for an alternative device name, in which ++ * case we don't need to add the dependency on swap.target because this unit ++ * is following a different unit which will have this dependency added, ++ * or it can be derived from /proc/swaps, in which case it was started ++ * manually, and should not become a dependency of swap.target. */ ++ return 0; + +- nofail = p->nofail; +- noauto = p->noauto; +- } ++ nofail = s->parameters_fragment.nofail; ++ noauto = s->parameters_fragment.noauto; + + if (!noauto) { + if (nofail) + r = unit_add_dependency_by_name_inverse(UNIT(s), UNIT_WANTS, SPECIAL_SWAP_TARGET, NULL, true); + else + r = unit_add_two_dependencies_by_name_inverse(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SWAP_TARGET, NULL, true); +- if (r < 0) +- return r; + } + +- return 0; ++ return r < 0 ? r : 0; + } + + static int swap_verify(Swap *s) { diff --git a/0439-hwdb-Update-database-of-Bluetooth-company-identifier.patch b/0439-hwdb-Update-database-of-Bluetooth-company-identifier.patch new file mode 100644 index 0000000..a6ecb3d --- /dev/null +++ b/0439-hwdb-Update-database-of-Bluetooth-company-identifier.patch @@ -0,0 +1,35 @@ +From 2e3390ea4684b954edce66b7758b5371d3338a9f Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Thu, 2 Oct 2014 07:53:15 +0200 +Subject: [PATCH] hwdb: Update database of Bluetooth company identifiers + +--- + hwdb/20-bluetooth-vendor-product.hwdb | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb +index 14aee74a1a..ee2efdff2e 100644 +--- a/hwdb/20-bluetooth-vendor-product.hwdb ++++ b/hwdb/20-bluetooth-vendor-product.hwdb +@@ -1148,3 +1148,21 @@ bluetooth:v017B* + + bluetooth:v017C* + ID_VENDOR_FROM_DATABASE=Daimler AG ++ ++bluetooth:v017D* ++ ID_VENDOR_FROM_DATABASE=BatAndCat ++ ++bluetooth:v017E* ++ ID_VENDOR_FROM_DATABASE=BluDotz Ltd ++ ++bluetooth:v017F* ++ ID_VENDOR_FROM_DATABASE=XTel ApS ++ ++bluetooth:v0180* ++ ID_VENDOR_FROM_DATABASE=Gigaset Communications GmbH ++ ++bluetooth:v0181* ++ ID_VENDOR_FROM_DATABASE=Gecko Health Innovations, Inc. ++ ++bluetooth:v0182* ++ ID_VENDOR_FROM_DATABASE=HOP Ubiquitous diff --git a/0440-PORTING-DBUS1-we-use-1.-llu-not-0.-llu-for-D-Bus-uni.patch b/0440-PORTING-DBUS1-we-use-1.-llu-not-0.-llu-for-D-Bus-uni.patch new file mode 100644 index 0000000..d835068 --- /dev/null +++ b/0440-PORTING-DBUS1-we-use-1.-llu-not-0.-llu-for-D-Bus-uni.patch @@ -0,0 +1,23 @@ +From e1ffdb90d92849a2bb5c27ebc035e7f885ffdafb Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Wed, 1 Oct 2014 16:12:00 +0100 +Subject: [PATCH] PORTING-DBUS1: we use :1.%llu not :0.%llu for D-Bus unique + bus names + +--- + src/libsystemd/sd-bus/PORTING-DBUS1 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/PORTING-DBUS1 b/src/libsystemd/sd-bus/PORTING-DBUS1 +index 9f0a91d695..63c345b11a 100644 +--- a/src/libsystemd/sd-bus/PORTING-DBUS1 ++++ b/src/libsystemd/sd-bus/PORTING-DBUS1 +@@ -66,7 +66,7 @@ fields as you need. + + The kernel will return in the "id" field your unique id. This is a + simple numeric value. For compatibility with classic dbus1 simply +-format this as string and prefix ":0.". ++format this as string and prefix ":1.". + + The kernel will also return the bloom filter size and bloom filter + hash function number used for the signal broadcast bloom filter (see diff --git a/0441-sd-bus-use-terms-from-the-D-Bus-Specification-a-bit-.patch b/0441-sd-bus-use-terms-from-the-D-Bus-Specification-a-bit-.patch new file mode 100644 index 0000000..f79c3b6 --- /dev/null +++ b/0441-sd-bus-use-terms-from-the-D-Bus-Specification-a-bit-.patch @@ -0,0 +1,60 @@ +From d20a3daaa79edfa4c8d84d243f2a98c82dddd5c6 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Wed, 1 Oct 2014 16:11:59 +0100 +Subject: [PATCH] sd-bus: use terms from the D-Bus Specification a bit more + +D-Bus' type hierarchy as described in the spec is: + +\- basic + \- fixed type (u, i, etc.) + \- string-like type (s, o, g) +\- container + +Someone seems to have referred to basic types as "simple types" at +some point, but that term isn't defined in the D-Bus Specification, +and seems redundant. + +So far I haven't renamed functions that use "trivial" in their names +to mean "fixed type", to avoid confusion about whether a struct of +constant length, like (iu), is a fixed type. The answer is that it is +fixed-length, but is not a "fixed type", so I can see that something +like bus_type_is_fixed() might be ambiguous. +--- + src/libsystemd/sd-bus/PORTING-DBUS1 | 10 +++++----- + src/libsystemd/sd-bus/bus-type.h | 2 ++ + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-bus/PORTING-DBUS1 b/src/libsystemd/sd-bus/PORTING-DBUS1 +index 63c345b11a..81e94132b3 100644 +--- a/src/libsystemd/sd-bus/PORTING-DBUS1 ++++ b/src/libsystemd/sd-bus/PORTING-DBUS1 +@@ -156,11 +156,11 @@ multiple items. Some restrictions apply however: + contained in the payload, as well is immediately before framing of a + Gvariant, as well after as any padding bytes if there are any. The + padding bytes must be wholly contained in the preceding +- PAYLOAD_VEC/PAYLOAD_MEMFD item. You may not split up simple types +- nor arrays of trivial types. The latter is necessary to allow APIs +- to return direct pointers to linear chunks of fixed size trivial +- arrays. Examples: The simple types "u", "s", "t" have to be in the +- same payload item. The array of simple types "ay", "ai" have to be ++ PAYLOAD_VEC/PAYLOAD_MEMFD item. You may not split up basic types ++ nor arrays of fixed types. The latter is necessary to allow APIs ++ to return direct pointers to linear arrays of numeric ++ values. Examples: The basic types "u", "s", "t" have to be in the ++ same payload item. The array of fixed types "ay", "ai" have to be + fully in contained in the same payload item. For an array "as" or + "a(si)" the only restriction however is to keep each string + individually in an uninterrupted item, to keep the framing of each +diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h +index 2e423bbfdb..581e8d5841 100644 +--- a/src/libsystemd/sd-bus/bus-type.h ++++ b/src/libsystemd/sd-bus/bus-type.h +@@ -29,6 +29,8 @@ + bool bus_type_is_valid(char c) _const_; + bool bus_type_is_valid_in_signature(char c) _const_; + bool bus_type_is_basic(char c) _const_; ++/* "trivial" is systemd's term for what the D-Bus Specification calls ++ * a "fixed type": that is, a basic type of fixed length */ + bool bus_type_is_trivial(char c) _const_; + bool bus_type_is_container(char c) _const_; + diff --git a/0442-terminal-move-unifont-internal.h-to-unifont.h.patch b/0442-terminal-move-unifont-internal.h-to-unifont.h.patch new file mode 100644 index 0000000..636e11f --- /dev/null +++ b/0442-terminal-move-unifont-internal.h-to-unifont.h.patch @@ -0,0 +1,60 @@ +From c2977e5cb874e696994bcb93b8148f52c315b901 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 1 Oct 2014 11:23:02 +0200 +Subject: [PATCH] terminal: move unifont-internal.h to unifont.h + +All the definitions are for outside users, so drop the -internal suffix. +Internal definitions are in unifont-def.h and unifont.c, no need to share +those. +--- + Makefile.am | 3 ++- + src/libsystemd-terminal/test-unifont.c | 2 +- + src/libsystemd-terminal/unifont.c | 2 +- + src/libsystemd-terminal/{unifont-internal.h => unifont.h} | 0 + 4 files changed, 4 insertions(+), 3 deletions(-) + rename src/libsystemd-terminal/{unifont-internal.h => unifont.h} (100%) + +diff --git a/Makefile.am b/Makefile.am +index 9e087bd9fb..da36a8c1c2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3059,7 +3059,8 @@ libsystemd_terminal_la_SOURCES = \ + src/libsystemd-terminal/term-parser.c \ + src/libsystemd-terminal/term-screen.c \ + src/libsystemd-terminal/term-wcwidth.c \ +- src/libsystemd-terminal/unifont-internal.h \ ++ src/libsystemd-terminal/unifont.h \ ++ src/libsystemd-terminal/unifont-def.h \ + src/libsystemd-terminal/unifont.c + + libsystemd_terminal_la_LIBADD = \ +diff --git a/src/libsystemd-terminal/test-unifont.c b/src/libsystemd-terminal/test-unifont.c +index 2c415941fb..cfeef61a47 100644 +--- a/src/libsystemd-terminal/test-unifont.c ++++ b/src/libsystemd-terminal/test-unifont.c +@@ -30,7 +30,7 @@ + #include + #include "macro.h" + #include "unifont-def.h" +-#include "unifont-internal.h" ++#include "unifont.h" + #include "util.h" + + static void render(char *w, const unifont_glyph *g) { +diff --git a/src/libsystemd-terminal/unifont.c b/src/libsystemd-terminal/unifont.c +index 9e0f718665..aa91794410 100644 +--- a/src/libsystemd-terminal/unifont.c ++++ b/src/libsystemd-terminal/unifont.c +@@ -37,7 +37,7 @@ + #include + #include "macro.h" + #include "unifont-def.h" +-#include "unifont-internal.h" ++#include "unifont.h" + #include "util.h" + + struct unifont { +diff --git a/src/libsystemd-terminal/unifont-internal.h b/src/libsystemd-terminal/unifont.h +similarity index 100% +rename from src/libsystemd-terminal/unifont-internal.h +rename to src/libsystemd-terminal/unifont.h diff --git a/0443-terminal-add-unifont_get_width-height.patch b/0443-terminal-add-unifont_get_width-height.patch new file mode 100644 index 0000000..3575cab --- /dev/null +++ b/0443-terminal-add-unifont_get_width-height.patch @@ -0,0 +1,47 @@ +From fa9653457302c106f8d47060ef3dda2b4c8038a8 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 1 Oct 2014 11:24:08 +0200 +Subject: [PATCH] terminal: add unifont_get_width/height() + +Allow unifont users to retrieve the width and height of unifont glyphs. In +version 1 this is hard-coded as 8/16, but may be changed in the future. +--- + src/libsystemd-terminal/unifont.c | 12 ++++++++++++ + src/libsystemd-terminal/unifont.h | 2 ++ + 2 files changed, 14 insertions(+) + +diff --git a/src/libsystemd-terminal/unifont.c b/src/libsystemd-terminal/unifont.c +index aa91794410..7520015988 100644 +--- a/src/libsystemd-terminal/unifont.c ++++ b/src/libsystemd-terminal/unifont.c +@@ -181,6 +181,18 @@ unifont *unifont_unref(unifont *u) { + return NULL; + } + ++unsigned int unifont_get_width(unifont *u) { ++ assert(u); ++ ++ return 8U; ++} ++ ++unsigned int unifont_get_height(unifont *u) { ++ assert(u); ++ ++ return 16U; ++} ++ + unsigned int unifont_get_stride(unifont *u) { + assert(u); + +diff --git a/src/libsystemd-terminal/unifont.h b/src/libsystemd-terminal/unifont.h +index c39512d2c6..0ded61472f 100644 +--- a/src/libsystemd-terminal/unifont.h ++++ b/src/libsystemd-terminal/unifont.h +@@ -50,5 +50,7 @@ unifont *unifont_unref(unifont *u); + + DEFINE_TRIVIAL_CLEANUP_FUNC(unifont*, unifont_unref); + ++unsigned int unifont_get_width(unifont *u); ++unsigned int unifont_get_height(unifont *u); + unsigned int unifont_get_stride(unifont *u); + int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4); diff --git a/0444-terminal-move-unifont-map-to-datadir.patch b/0444-terminal-move-unifont-map-to-datadir.patch new file mode 100644 index 0000000..6f1e55a --- /dev/null +++ b/0444-terminal-move-unifont-map-to-datadir.patch @@ -0,0 +1,41 @@ +From 056e86ee7fdae86d358aa068303845dff2cbb598 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 1 Oct 2014 11:25:27 +0200 +Subject: [PATCH] terminal: move unifont-map to datadir + +Lets avoid putting stuff into /usr/shared/unifont/, but keep it in +/usr/share/systemd/. Upstream lacks interest in this, so don't bother for +now. +--- + Makefile.am | 4 +--- + src/libsystemd-terminal/unifont-def.h | 2 +- + 2 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index da36a8c1c2..5fa4e4a5e8 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3025,9 +3025,7 @@ noinst_PROGRAMS += \ + systemd-modeset \ + systemd-subterm + +-unifontdatadir=$(datadir)/unifont +- +-dist_unifontdata_DATA = \ ++dist_pkgdata_DATA += \ + src/libsystemd-terminal/unifont-glyph-array.bin + + tests += \ +diff --git a/src/libsystemd-terminal/unifont-def.h b/src/libsystemd-terminal/unifont-def.h +index 7a0d48505a..2b0b859eb0 100644 +--- a/src/libsystemd-terminal/unifont-def.h ++++ b/src/libsystemd-terminal/unifont-def.h +@@ -115,7 +115,7 @@ typedef struct unifont_glyph_header unifont_glyph_header; + */ + + /* path to binary file */ +-#define UNIFONT_PATH "/usr/share/unifont/unifont-glyph-array.bin" ++#define UNIFONT_PATH "/usr/share/systemd/unifont-glyph-array.bin" + + /* header-size of version 1 */ + #define UNIFONT_HEADER_SIZE_MIN 32 diff --git a/0445-terminal-add-term.h-header-for-library-users.patch b/0445-terminal-add-term.h-header-for-library-users.patch new file mode 100644 index 0000000..ddddb3b --- /dev/null +++ b/0445-terminal-add-term.h-header-for-library-users.patch @@ -0,0 +1,373 @@ +From a30f1425133d2b64a1c3f0113a710528872a3cbb Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 1 Oct 2014 11:27:46 +0200 +Subject: [PATCH] terminal: add term.h header for library users + +Like all the other parts of libsystemd-terminal, split API of +term-internal.h into term.h so we can use it from systemd-consoled. +--- + Makefile.am | 1 + + src/libsystemd-terminal/term-internal.h | 132 +---------------------------- + src/libsystemd-terminal/term.h | 146 ++++++++++++++++++++++++++++++++ + 3 files changed, 148 insertions(+), 131 deletions(-) + create mode 100644 src/libsystemd-terminal/term.h + +diff --git a/Makefile.am b/Makefile.am +index 5fa4e4a5e8..503302851b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3051,6 +3051,7 @@ libsystemd_terminal_la_SOURCES = \ + src/libsystemd-terminal/sysview.h \ + src/libsystemd-terminal/sysview-internal.h \ + src/libsystemd-terminal/sysview.c \ ++ src/libsystemd-terminal/term.h \ + src/libsystemd-terminal/term-internal.h \ + src/libsystemd-terminal/term-charset.c \ + src/libsystemd-terminal/term-page.c \ +diff --git a/src/libsystemd-terminal/term-internal.h b/src/libsystemd-terminal/term-internal.h +index 345996b943..f0f4432c80 100644 +--- a/src/libsystemd-terminal/term-internal.h ++++ b/src/libsystemd-terminal/term-internal.h +@@ -24,26 +24,20 @@ + #include + #include + #include ++#include "term.h" + #include "util.h" + + typedef struct term_char term_char_t; + typedef struct term_charbuf term_charbuf_t; + +-typedef struct term_color term_color; +-typedef struct term_attr term_attr; + typedef struct term_cell term_cell; + typedef struct term_line term_line; + + typedef struct term_page term_page; + typedef struct term_history term_history; + +-typedef struct term_utf8 term_utf8; +-typedef struct term_seq term_seq; +-typedef struct term_parser term_parser; + typedef uint32_t term_charset[96]; + +-typedef struct term_screen term_screen; +- + /* + * Miscellaneous + * Sundry things and external helpers. +@@ -55,24 +49,6 @@ int mk_wcswidth(const wchar_t *str, size_t len); + int mk_wcswidth_cjk(const wchar_t *str, size_t len); + + /* +- * Ageing +- * Redrawing terminals is quite expensive. Therefore, we avoid redrawing on +- * each single modification and mark modified cells instead. This way, we know +- * which cells to redraw on the next frame. However, a single DIRTY flag is not +- * enough for double/triple buffered screens, hence, we use an AGE field for +- * each cell. If the cell is modified, we simply increase the age by one. Each +- * framebuffer can then remember its last rendered age and request an update of +- * all newer cells. +- * TERM_AGE_NULL is special. If used as cell age, the cell must always be +- * redrawn (forced update). If used as framebuffer age, all cells are drawn. +- * This way, we can allow integer wrap-arounds. +- */ +- +-typedef uint64_t term_age_t; +- +-#define TERM_AGE_NULL 0 +- +-/* + * Characters + * Each cell in a terminal page contains only a single character. This is + * usually a single UCS-4 value. However, Unicode allows combining-characters, +@@ -143,68 +119,6 @@ static inline void term_char_freep(term_char_t *p) { + } + + /* +- * Attributes +- * Each cell in a terminal page can have its own set of attributes. These alter +- * the behavior of the renderer for this single cell. We use term_attr to +- * specify attributes. +- * The only non-obvious field is "ccode" for foreground and background colors. +- * This field contains the terminal color-code in case no full RGB information +- * was given by the host. It is also required for dynamic color palettes. If it +- * is set to TERM_CCODE_RGB, the "red", "green" and "blue" fields contain the +- * full RGB color. +- */ +- +-enum { +- /* special color-codes */ +- TERM_CCODE_DEFAULT, /* default foreground/background color */ +- TERM_CCODE_256, /* 256color code */ +- TERM_CCODE_RGB, /* color is specified as RGB */ +- +- /* dark color-codes */ +- TERM_CCODE_BLACK, +- TERM_CCODE_RED, +- TERM_CCODE_GREEN, +- TERM_CCODE_YELLOW, +- TERM_CCODE_BLUE, +- TERM_CCODE_MAGENTA, +- TERM_CCODE_CYAN, +- TERM_CCODE_WHITE, /* technically: light grey */ +- +- /* light color-codes */ +- TERM_CCODE_LIGHT_BLACK = TERM_CCODE_BLACK + 8, /* technically: dark grey */ +- TERM_CCODE_LIGHT_RED = TERM_CCODE_RED + 8, +- TERM_CCODE_LIGHT_GREEN = TERM_CCODE_GREEN + 8, +- TERM_CCODE_LIGHT_YELLOW = TERM_CCODE_YELLOW + 8, +- TERM_CCODE_LIGHT_BLUE = TERM_CCODE_BLUE + 8, +- TERM_CCODE_LIGHT_MAGENTA = TERM_CCODE_MAGENTA + 8, +- TERM_CCODE_LIGHT_CYAN = TERM_CCODE_CYAN + 8, +- TERM_CCODE_LIGHT_WHITE = TERM_CCODE_WHITE + 8, +- +- TERM_CCODE_CNT, +-}; +- +-struct term_color { +- uint8_t ccode; +- uint8_t c256; +- uint8_t red; +- uint8_t green; +- uint8_t blue; +-}; +- +-struct term_attr { +- term_color fg; /* foreground color */ +- term_color bg; /* background color */ +- +- unsigned int bold : 1; /* bold font */ +- unsigned int italic : 1; /* italic font */ +- unsigned int underline : 1; /* underline text */ +- unsigned int inverse : 1; /* inverse fg/bg */ +- unsigned int protect : 1; /* protect from erase */ +- unsigned int blink : 1; /* blink text */ +- unsigned int hidden : 1; /* hidden */ +-}; +- +-/* + * Cells + * The term_cell structure respresents a single cell in a terminal page. It + * contains the stored character, the age of the cell and all its attributes. +@@ -344,26 +258,6 @@ term_line *term_history_pop(term_history *history, unsigned int reserve_width, c + unsigned int term_history_peek(term_history *history, unsigned int max, unsigned int reserve_width, const term_attr *attr, term_age_t age); + + /* +- * UTF-8 +- * The UTF-decoder and encoder are adjusted for terminals and provide proper +- * fallbacks for invalid UTF-8. In terminals it's quite usual to use fallbacks +- * instead of rejecting invalid input. This way, old legacy applications still +- * work (this is especially important for 7bit/ASCII DEC modes). +- */ +- +-struct term_utf8 { +- uint32_t chars[5]; +- uint32_t ucs4; +- +- unsigned int i_bytes : 3; +- unsigned int n_bytes : 3; +- unsigned int valid : 1; +-}; +- +-size_t term_utf8_encode(char *out_utf8, uint32_t g); +-const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c); +- +-/* + * Parsers + * The term_parser object parses control-sequences for both host and terminal + * side. Based on this parser, there is a set of command-parsers that take a +@@ -680,13 +574,6 @@ struct term_parser { + bool is_host : 1; + }; + +-int term_parser_new(term_parser **out, bool host); +-term_parser *term_parser_free(term_parser *parser); +-int term_parser_feed(term_parser *parser, const term_seq **seq_out, uint32_t raw); +- +-#define _term_parser_free_ _cleanup_(term_parser_freep) +-DEFINE_TRIVIAL_CLEANUP_FUNC(term_parser*, term_parser_free); +- + /* + * Screens + * A term_screen object represents the terminal-side of the communication. It +@@ -713,9 +600,6 @@ enum { + TERM_CONFORMANCE_LEVEL_CNT, + }; + +-typedef int (*term_screen_write_fn) (term_screen *screen, void *userdata, const void *buf, size_t size); +-typedef int (*term_screen_cmd_fn) (term_screen *screen, void *userdata, unsigned int cmd, const term_seq *seq); +- + struct term_screen { + unsigned long ref; + term_age_t age; +@@ -766,17 +650,3 @@ struct term_screen { + unsigned int flags; + } saved; + }; +- +-int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *write_fn_data, term_screen_cmd_fn cmd_fn, void *cmd_fn_data); +-term_screen *term_screen_ref(term_screen *screen); +-term_screen *term_screen_unref(term_screen *screen); +- +-DEFINE_TRIVIAL_CLEANUP_FUNC(term_screen*, term_screen_unref); +- +-int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size); +-int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods); +-int term_screen_resize(term_screen *screen, unsigned int width, unsigned int height); +-void term_screen_soft_reset(term_screen *screen); +-void term_screen_hard_reset(term_screen *screen); +- +-int term_screen_set_answerback(term_screen *screen, const char *answerback); +diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h +new file mode 100644 +index 0000000000..2f2bb479cb +--- /dev/null ++++ b/src/libsystemd-terminal/term.h +@@ -0,0 +1,146 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright (C) 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 . ++***/ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include "util.h" ++ ++typedef struct term_color term_color; ++typedef struct term_attr term_attr; ++ ++typedef struct term_utf8 term_utf8; ++typedef struct term_seq term_seq; ++typedef struct term_parser term_parser; ++ ++typedef struct term_screen term_screen; ++ ++/* ++ * Ageing ++ */ ++ ++typedef uint64_t term_age_t; ++ ++#define TERM_AGE_NULL 0 ++ ++/* ++ * Attributes ++ */ ++ ++enum { ++ /* special color-codes */ ++ TERM_CCODE_DEFAULT, /* default foreground/background color */ ++ TERM_CCODE_256, /* 256color code */ ++ TERM_CCODE_RGB, /* color is specified as RGB */ ++ ++ /* dark color-codes */ ++ TERM_CCODE_BLACK, ++ TERM_CCODE_RED, ++ TERM_CCODE_GREEN, ++ TERM_CCODE_YELLOW, ++ TERM_CCODE_BLUE, ++ TERM_CCODE_MAGENTA, ++ TERM_CCODE_CYAN, ++ TERM_CCODE_WHITE, /* technically: light grey */ ++ ++ /* light color-codes */ ++ TERM_CCODE_LIGHT_BLACK = TERM_CCODE_BLACK + 8, /* technically: dark grey */ ++ TERM_CCODE_LIGHT_RED = TERM_CCODE_RED + 8, ++ TERM_CCODE_LIGHT_GREEN = TERM_CCODE_GREEN + 8, ++ TERM_CCODE_LIGHT_YELLOW = TERM_CCODE_YELLOW + 8, ++ TERM_CCODE_LIGHT_BLUE = TERM_CCODE_BLUE + 8, ++ TERM_CCODE_LIGHT_MAGENTA = TERM_CCODE_MAGENTA + 8, ++ TERM_CCODE_LIGHT_CYAN = TERM_CCODE_CYAN + 8, ++ TERM_CCODE_LIGHT_WHITE = TERM_CCODE_WHITE + 8, ++ ++ TERM_CCODE_CNT, ++}; ++ ++struct term_color { ++ uint8_t ccode; ++ uint8_t c256; ++ uint8_t red; ++ uint8_t green; ++ uint8_t blue; ++}; ++ ++struct term_attr { ++ term_color fg; /* foreground color */ ++ term_color bg; /* background color */ ++ ++ unsigned int bold : 1; /* bold font */ ++ unsigned int italic : 1; /* italic font */ ++ unsigned int underline : 1; /* underline text */ ++ unsigned int inverse : 1; /* inverse fg/bg */ ++ unsigned int protect : 1; /* protect from erase */ ++ unsigned int blink : 1; /* blink text */ ++ unsigned int hidden : 1; /* hidden */ ++}; ++ ++/* ++ * UTF-8 ++ */ ++ ++struct term_utf8 { ++ uint32_t chars[5]; ++ uint32_t ucs4; ++ ++ unsigned int i_bytes : 3; ++ unsigned int n_bytes : 3; ++ unsigned int valid : 1; ++}; ++ ++size_t term_utf8_encode(char *out_utf8, uint32_t g); ++const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c); ++ ++/* ++ * Parsers ++ */ ++ ++int term_parser_new(term_parser **out, bool host); ++term_parser *term_parser_free(term_parser *parser); ++int term_parser_feed(term_parser *parser, const term_seq **seq_out, uint32_t raw); ++ ++#define _term_parser_free_ _cleanup_(term_parser_freep) ++DEFINE_TRIVIAL_CLEANUP_FUNC(term_parser*, term_parser_free); ++ ++/* ++ * Screens ++ */ ++ ++typedef int (*term_screen_write_fn) (term_screen *screen, void *userdata, const void *buf, size_t size); ++typedef int (*term_screen_cmd_fn) (term_screen *screen, void *userdata, unsigned int cmd, const term_seq *seq); ++ ++int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *write_fn_data, term_screen_cmd_fn cmd_fn, void *cmd_fn_data); ++term_screen *term_screen_ref(term_screen *screen); ++term_screen *term_screen_unref(term_screen *screen); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(term_screen*, term_screen_unref); ++ ++int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size); ++int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods); ++int term_screen_resize(term_screen *screen, unsigned int width, unsigned int height); ++void term_screen_soft_reset(term_screen *screen); ++void term_screen_hard_reset(term_screen *screen); ++ ++int term_screen_set_answerback(term_screen *screen, const char *answerback); diff --git a/0446-terminal-add-helpers-to-retrieve-page-dimensions.patch b/0446-terminal-add-helpers-to-retrieve-page-dimensions.patch new file mode 100644 index 0000000..ea2313b --- /dev/null +++ b/0446-terminal-add-helpers-to-retrieve-page-dimensions.patch @@ -0,0 +1,49 @@ +From dda57d9143644d39091207b287f142f91f55d0ad Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 1 Oct 2014 11:29:09 +0200 +Subject: [PATCH] terminal: add helpers to retrieve page dimensions + +Allow term users to retrieve the page dimensions of a terminal screen. +This is needed to properly calculate the grid dimensions when rendering. +--- + src/libsystemd-terminal/term-screen.c | 12 ++++++++++++ + src/libsystemd-terminal/term.h | 3 +++ + 2 files changed, 15 insertions(+) + +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 67f9056d57..14c32aceb9 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -3743,6 +3743,18 @@ static int screen_feed_cmd(term_screen *screen, const term_seq *seq) { + return 0; + } + ++unsigned int term_screen_get_width(term_screen *screen) { ++ assert_return(screen, -EINVAL); ++ ++ return screen->page->width; ++} ++ ++unsigned int term_screen_get_height(term_screen *screen) { ++ assert_return(screen, -EINVAL); ++ ++ return screen->page->height; ++} ++ + int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) { + const uint32_t *ucs4_str; + size_t i, j, ucs4_len; +diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h +index 2f2bb479cb..021cf1c42b 100644 +--- a/src/libsystemd-terminal/term.h ++++ b/src/libsystemd-terminal/term.h +@@ -137,6 +137,9 @@ term_screen *term_screen_unref(term_screen *screen); + + DEFINE_TRIVIAL_CLEANUP_FUNC(term_screen*, term_screen_unref); + ++unsigned int term_screen_get_width(term_screen *screen); ++unsigned int term_screen_get_height(term_screen *screen); ++ + int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size); + int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods); + int term_screen_resize(term_screen *screen, unsigned int width, unsigned int height); diff --git a/0447-barrier-fix-up-constructor-error-handling.patch b/0447-barrier-fix-up-constructor-error-handling.patch new file mode 100644 index 0000000..81783cd --- /dev/null +++ b/0447-barrier-fix-up-constructor-error-handling.patch @@ -0,0 +1,63 @@ +From fc808616227115ccab8c04f00f8f7472c7353ae5 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 08:31:28 +0200 +Subject: [PATCH] barrier: fix up constructor error handling + +We cannot rely on "errno" to be non-zero on failure, if we perform +multiple glibc calls. That is, if the first eventfd() call fails, but the +second succeeds, we cleanup the barrier but return 0. + +Fix this by always testing the return value immediately. This should also +fix all the coverity warnings. +--- + src/shared/barrier.c | 19 ++++++++++++++----- + src/shared/barrier.h | 2 ++ + 2 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/src/shared/barrier.c b/src/shared/barrier.c +index 4a5544de27..f65363a67b 100644 +--- a/src/shared/barrier.c ++++ b/src/shared/barrier.c +@@ -112,15 +112,24 @@ + * Returns: 0 on success, negative error code on failure. + */ + int barrier_create(Barrier *b) { ++ _cleanup_(barrier_destroyp) Barrier *staging = b; ++ int r; ++ + assert(b); + +- if ((b->me = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) < 0 || +- (b->them = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) < 0 || +- pipe2(b->pipe, O_CLOEXEC | O_NONBLOCK) < 0) { +- barrier_destroy(b); ++ b->me = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); ++ if (b->me < 0) ++ return -errno; ++ ++ b->them = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); ++ if (b->them < 0) ++ return -errno; ++ ++ r = pipe2(b->pipe, O_CLOEXEC | O_NONBLOCK); ++ if (r < 0) + return -errno; +- } + ++ staging = NULL; + return 0; + } + +diff --git a/src/shared/barrier.h b/src/shared/barrier.h +index 53b4439fb2..c55e311344 100644 +--- a/src/shared/barrier.h ++++ b/src/shared/barrier.h +@@ -62,6 +62,8 @@ struct Barrier { + int barrier_create(Barrier *obj); + void barrier_destroy(Barrier *b); + ++DEFINE_TRIVIAL_CLEANUP_FUNC(Barrier*, barrier_destroy); ++ + void barrier_set_role(Barrier *b, unsigned int role); + + bool barrier_place(Barrier *b); diff --git a/0448-Correct-a-few-typos.patch b/0448-Correct-a-few-typos.patch new file mode 100644 index 0000000..20375ba --- /dev/null +++ b/0448-Correct-a-few-typos.patch @@ -0,0 +1,36 @@ +From 4cf07da260b6c21596fec9a6a03a615729f617dc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Torstein=20Huseb=C3=B8?= +Date: Tue, 30 Sep 2014 15:25:47 +0200 +Subject: [PATCH] Correct a few typos + +--- + man/systemd-debug-generator.xml | 2 +- + src/tty-ask-password-agent/tty-ask-password-agent.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/man/systemd-debug-generator.xml b/man/systemd-debug-generator.xml +index ce4750e530..a2bef5fe28 100644 +--- a/man/systemd-debug-generator.xml ++++ b/man/systemd-debug-generator.xml +@@ -68,7 +68,7 @@ + If the option is + specified and followed by a unit name, a start job for + this unit is added to the initial transaction. This is +- useful to start one ore more additional units at ++ useful to start one or more additional units at + boot. May be specified more than once. + + If the +diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c +index 8a02fb0b5e..e7cbde285c 100644 +--- a/src/tty-ask-password-agent/tty-ask-password-agent.c ++++ b/src/tty-ask-password-agent/tty-ask-password-agent.c +@@ -183,7 +183,7 @@ static int ask_password_plymouth( + uint32_t size; + char **l; + +- /* One ore more answers */ ++ /* One or more answers */ + if (p < 5) + continue; + diff --git a/0449-sd-bus-sync-kdbus.h-ABI-break.patch b/0449-sd-bus-sync-kdbus.h-ABI-break.patch new file mode 100644 index 0000000..6e8e9bd --- /dev/null +++ b/0449-sd-bus-sync-kdbus.h-ABI-break.patch @@ -0,0 +1,51 @@ +From 581fe6c8176c6ea4ad998566df0746bf7b56456f Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Thu, 2 Oct 2014 13:02:41 +0200 +Subject: [PATCH] sd-bus: sync kdbus.h (ABI break) + +struct kdbus_cmd_conn_info takes a list of items now instead of a string. + +Fix the only user in SD of that ioctl. +--- + src/libsystemd/sd-bus/bus-control.c | 10 +++++++--- + src/libsystemd/sd-bus/kdbus.h | 2 +- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c +index 4ad44469b5..d9a53c702f 100644 +--- a/src/libsystemd/sd-bus/bus-control.c ++++ b/src/libsystemd/sd-bus/bus-control.c +@@ -389,13 +389,17 @@ static int bus_get_owner_kdbus( + if (r < 0) + return r; + if (r > 0) { +- size = offsetof(struct kdbus_cmd_conn_info, name); ++ size = offsetof(struct kdbus_cmd_conn_info, items); + cmd = alloca0_align(size, 8); + cmd->id = id; + } else { +- size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1; ++ size_t item_size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; ++ ++ size = offsetof(struct kdbus_cmd_conn_info, items) + item_size; + cmd = alloca0_align(size, 8); +- strcpy(cmd->name, name); ++ cmd->items[0].size = item_size; ++ cmd->items[0].type = KDBUS_ITEM_NAME; ++ strcpy(cmd->items[0].str, name); + } + + cmd->size = size; +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index 7fb11713fc..c97994974b 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -681,7 +681,7 @@ struct kdbus_cmd_conn_info { + __u64 flags; + __u64 id; + __u64 offset; +- char name[0]; ++ struct kdbus_item items[0]; + } __attribute__((aligned(8))); + + /** diff --git a/0450-localectl-count-locale-variables-from-0-instead-of-V.patch b/0450-localectl-count-locale-variables-from-0-instead-of-V.patch new file mode 100644 index 0000000..ad09023 --- /dev/null +++ b/0450-localectl-count-locale-variables-from-0-instead-of-V.patch @@ -0,0 +1,34 @@ +From 63229aa1abdb98aa69fda9819ed2f40c8082762b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Oct 2014 14:34:55 +0200 +Subject: [PATCH] localectl: count locale variables from 0, instead of + VARIABLE_LANG + +That way the we make our code safe regarding reordering of the variables +in the enum. +--- + src/locale/localectl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/locale/localectl.c b/src/locale/localectl.c +index 5917364d7c..9325d9af6d 100644 +--- a/src/locale/localectl.c ++++ b/src/locale/localectl.c +@@ -114,7 +114,7 @@ static void print_overriden_variables(void) { + goto finish; + } + +- for (j = VARIABLE_LANG; j < _VARIABLE_LC_MAX; j++) ++ for (j = 0; j < _VARIABLE_LC_MAX; j++) + if (variables[j]) { + if (print_warning) { + printf("Warning: Settings on Kernel Command Line override system locale settings in /etc/locale.conf\n"); +@@ -126,7 +126,7 @@ static void print_overriden_variables(void) { + printf(" %s=%s\n", locale_variable_to_string(j), variables[j]); + } + finish: +- for (j = VARIABLE_LANG; j < _VARIABLE_LC_MAX; j++) ++ for (j = 0; j < _VARIABLE_LC_MAX; j++) + free(variables[j]); + } + diff --git a/0451-localectl-always-print-warnings-with-log_warning-ins.patch b/0451-localectl-always-print-warnings-with-log_warning-ins.patch new file mode 100644 index 0000000..38b37e2 --- /dev/null +++ b/0451-localectl-always-print-warnings-with-log_warning-ins.patch @@ -0,0 +1,33 @@ +From b344bcbbfda8fbe14dadc5aa4b5dfb3ced6d76e2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Oct 2014 14:35:34 +0200 +Subject: [PATCH] localectl: always print warnings with log_warning() instead + of printf() + +They really should got to stderr, not stdout. +--- + src/locale/localectl.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/src/locale/localectl.c b/src/locale/localectl.c +index 9325d9af6d..3690f9fc89 100644 +--- a/src/locale/localectl.c ++++ b/src/locale/localectl.c +@@ -117,13 +117,12 @@ static void print_overriden_variables(void) { + for (j = 0; j < _VARIABLE_LC_MAX; j++) + if (variables[j]) { + if (print_warning) { +- printf("Warning: Settings on Kernel Command Line override system locale settings in /etc/locale.conf\n"); +- printf(" Command Line: %s=%s\n", locale_variable_to_string(j), variables[j]); ++ log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n" ++ " Command Line: %s=%s\n", locale_variable_to_string(j), variables[j]); + + print_warning = false; +- continue; +- } +- printf(" %s=%s\n", locale_variable_to_string(j), variables[j]); ++ } else ++ log_warning(" %s=%s\n", locale_variable_to_string(j), variables[j]); + } + finish: + for (j = 0; j < _VARIABLE_LC_MAX; j++) diff --git a/0452-journalctl-add-utc-option.patch b/0452-journalctl-add-utc-option.patch new file mode 100644 index 0000000..2adf1d2 --- /dev/null +++ b/0452-journalctl-add-utc-option.patch @@ -0,0 +1,134 @@ +From 9fd290443f5f99fca0dcd4216b1de70f7d3b8db1 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 2 Oct 2014 14:39:29 +0200 +Subject: [PATCH] journalctl: add --utc option + +Introduce option to display time in UTC. +--- + man/journalctl.xml | 7 +++++++ + src/journal/journalctl.c | 11 ++++++++++- + src/shared/logs-show.c | 8 +++++--- + src/shared/output-mode.h | 1 + + 4 files changed, 23 insertions(+), 4 deletions(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index acd75a6370..7fb6afc8f6 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -380,6 +380,13 @@ + + + ++ ++ ++ Express time in Coordinated Universal ++ Time (UTC). ++ ++ ++ + + + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 89a922c067..395f85c9ae 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -63,6 +63,7 @@ + #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) + + static OutputMode arg_output = OUTPUT_SHORT; ++static bool arg_utc = false; + static bool arg_pager_end = false; + static bool arg_follow = false; + static bool arg_full = true; +@@ -191,6 +192,7 @@ static void help(void) { + " -o --output=STRING Change journal output mode (short, short-iso,\n" + " short-precise, short-monotonic, verbose,\n" + " export, json, json-pretty, json-sse, cat)\n" ++ " --utc Express time in Coordinated Universal Time (UTC)\n" + " -x --catalog Add message explanations where available\n" + " --no-full Ellipsize fields\n" + " -a --all Show all fields, including long and unprintable\n" +@@ -250,6 +252,7 @@ static int parse_argv(int argc, char *argv[]) { + ARG_DUMP_CATALOG, + ARG_UPDATE_CATALOG, + ARG_FORCE, ++ ARG_UTC, + }; + + static const struct option options[] = { +@@ -299,6 +302,7 @@ static int parse_argv(int argc, char *argv[]) { + { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG }, + { "reverse", no_argument, NULL, 'r' }, + { "machine", required_argument, NULL, 'M' }, ++ { "utc", no_argument, NULL, ARG_UTC }, + {} + }; + +@@ -639,6 +643,10 @@ static int parse_argv(int argc, char *argv[]) { + arg_reverse = true; + break; + ++ case ARG_UTC: ++ arg_utc = true; ++ break; ++ + case '?': + return -EINVAL; + +@@ -1958,7 +1966,8 @@ int main(int argc, char *argv[]) { + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH | + on_tty() * OUTPUT_COLOR | +- arg_catalog * OUTPUT_CATALOG; ++ arg_catalog * OUTPUT_CATALOG | ++ arg_utc * OUTPUT_UTC; + + r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized); + need_seek = true; +diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c +index 5a7bbaf03a..d5d9d090b5 100644 +--- a/src/shared/logs-show.c ++++ b/src/shared/logs-show.c +@@ -311,8 +311,10 @@ static int output_short( + uint64_t x; + time_t t; + struct tm tm; ++ struct tm *(*gettime_r)(const time_t *, struct tm *); + + r = -ENOENT; ++ gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r; + + if (realtime) + r = safe_atou64(realtime, &x); +@@ -329,17 +331,17 @@ static int output_short( + + switch(mode) { + case OUTPUT_SHORT_ISO: +- r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm)); ++ r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)); + break; + case OUTPUT_SHORT_PRECISE: +- r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)); ++ r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)); + if (r > 0) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + ".%06llu", (unsigned long long) (x % USEC_PER_SEC)); + } + break; + default: +- r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)); ++ r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)); + } + + if (r <= 0) { +diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h +index ac1bb0123b..81d7f05d91 100644 +--- a/src/shared/output-mode.h ++++ b/src/shared/output-mode.h +@@ -44,4 +44,5 @@ typedef enum OutputFlags { + OUTPUT_COLOR = 1 << 4, + OUTPUT_CATALOG = 1 << 5, + OUTPUT_BEGIN_NEWLINE = 1 << 6, ++ OUTPUT_UTC = 1 << 7, + } OutputFlags; diff --git a/0453-add-a-transient-user-unit-directory.patch b/0453-add-a-transient-user-unit-directory.patch new file mode 100644 index 0000000..ff56b90 --- /dev/null +++ b/0453-add-a-transient-user-unit-directory.patch @@ -0,0 +1,201 @@ +From 718880ba0d557a045e2f969e141cbd59e78c76f4 Mon Sep 17 00:00:00 2001 +From: Steven Allen +Date: Sun, 28 Sep 2014 14:54:25 -0700 +Subject: [PATCH] add a transient user unit directory + +This patch adds a transient user unit directory under +`$XDG_RUNTIME_DIR/systemd/user/` and stores transient user-instance +units (such as those created by `systemd-run --user`) under there +instead of putting them in $XDG_CONFIG_HOME/systemd/user/. + +Fixes https://bugs.freedesktop.org/show_bug.cgi?id=67331 +--- + src/core/unit.c | 8 ++++++-- + src/shared/install.c | 37 +++++++++++++++++++------------------ + src/shared/path-lookup.c | 32 ++++++++++++++++++++++++++++++-- + src/shared/path-lookup.h | 1 + + 4 files changed, 56 insertions(+), 22 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 5978e21f56..8a7df01284 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3080,7 +3080,11 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, + if (u->manager->running_as == SYSTEMD_USER) { + int r; + +- r = user_config_home(dir); ++ if (mode == UNIT_PERSISTENT && !transient) ++ r = user_config_home(dir); ++ else ++ r = user_runtime(dir); ++ + if (r == 0) + return -ENOENT; + return r; +@@ -3228,7 +3232,7 @@ int unit_make_transient(Unit *u) { + if (u->manager->running_as == SYSTEMD_USER) { + _cleanup_free_ char *c = NULL; + +- r = user_config_home(&c); ++ r = user_runtime(&c); + if (r < 0) + return r; + if (r == 0) +diff --git a/src/shared/install.c b/src/shared/install.c +index 61e572bdf3..302b5237a6 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -105,10 +105,14 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d + + case UNIT_FILE_USER: + +- if (root_dir || runtime) ++ if (root_dir) + return -EINVAL; + +- r = user_config_home(&p); ++ if (runtime) ++ r = user_runtime(&p); ++ else ++ r = user_config_home(&p); ++ + if (r <= 0) + return r < 0 ? r : -ENOENT; + +@@ -527,36 +531,33 @@ static int find_symlinks_in_scope( + UnitFileState *state) { + + int r; +- _cleanup_free_ char *path2 = NULL; ++ _cleanup_free_ char *path = NULL; + bool same_name_link_runtime = false, same_name_link = false; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) { +- _cleanup_free_ char *path = NULL; + +- /* First look in runtime config path */ +- r = get_config_path(scope, true, root_dir, &path); +- if (r < 0) +- return r; ++ /* First look in runtime config path */ ++ r = get_config_path(scope, true, root_dir, &path); ++ if (r < 0) ++ return r; + +- r = find_symlinks(name, path, &same_name_link_runtime); +- if (r < 0) +- return r; +- else if (r > 0) { +- *state = UNIT_FILE_ENABLED_RUNTIME; +- return r; +- } ++ r = find_symlinks(name, path, &same_name_link_runtime); ++ if (r < 0) ++ return r; ++ else if (r > 0) { ++ *state = UNIT_FILE_ENABLED_RUNTIME; ++ return r; + } + + /* Then look in the normal config path */ +- r = get_config_path(scope, false, root_dir, &path2); ++ r = get_config_path(scope, false, root_dir, &path); + if (r < 0) + return r; + +- r = find_symlinks(name, path2, &same_name_link); ++ r = find_symlinks(name, path, &same_name_link); + if (r < 0) + return r; + else if (r > 0) { +diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c +index 40fb0b8b4a..3a6e117d28 100644 +--- a/src/shared/path-lookup.c ++++ b/src/shared/path-lookup.c +@@ -61,6 +61,23 @@ int user_config_home(char **config_home) { + return 0; + } + ++int user_runtime(char **user_runtime_path) { ++ const char *e; ++ char *r; ++ ++ e = getenv("XDG_RUNTIME_DIR"); ++ if (e) { ++ r = strappend(e, "/systemd/user"); ++ if (!r) ++ return -ENOMEM; ++ ++ *user_runtime_path = r; ++ return 1; ++ } ++ ++ return 0; ++} ++ + static char** user_dirs( + const char *generator, + const char *generator_early, +@@ -69,10 +86,11 @@ static char** user_dirs( + const char * const config_unit_paths[] = { + USER_CONFIG_UNIT_PATH, + "/etc/systemd/user", +- "/run/systemd/user", + NULL + }; + ++ const char * const runtime_unit_path = "/run/systemd/user"; ++ + const char * const data_unit_paths[] = { + "/usr/local/lib/systemd/user", + "/usr/local/share/systemd/user", +@@ -83,7 +101,7 @@ static char** user_dirs( + }; + + const char *home, *e; +- _cleanup_free_ char *config_home = NULL, *data_home = NULL; ++ _cleanup_free_ char *config_home = NULL, *user_runtime_dir = NULL, *data_home = NULL; + _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL; + char **r = NULL; + +@@ -99,6 +117,9 @@ static char** user_dirs( + if (user_config_home(&config_home) < 0) + goto fail; + ++ if (user_runtime(&user_runtime_dir) < 0) ++ goto fail; ++ + home = getenv("HOME"); + + e = getenv("XDG_CONFIG_DIRS"); +@@ -141,6 +162,13 @@ static char** user_dirs( + if (strv_extend(&r, config_home) < 0) + goto fail; + ++ if (user_runtime_dir) ++ if (strv_extend(&r, user_runtime_dir) < 0) ++ goto fail; ++ ++ if (strv_extend(&r, runtime_unit_path) < 0) ++ goto fail; ++ + if (!strv_isempty(config_dirs)) + if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0) + goto fail; +diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h +index 4bbd47ec39..8da076a30b 100644 +--- a/src/shared/path-lookup.h ++++ b/src/shared/path-lookup.h +@@ -39,6 +39,7 @@ typedef enum SystemdRunningAs { + } SystemdRunningAs; + + int user_config_home(char **config_home); ++int user_runtime(char **user_runtime_path); + + int lookup_paths_init(LookupPaths *p, + SystemdRunningAs running_as, diff --git a/0454-Rename-user_runtime-to-user_runtime_dir.patch b/0454-Rename-user_runtime-to-user_runtime_dir.patch new file mode 100644 index 0000000..1f20934 --- /dev/null +++ b/0454-Rename-user_runtime-to-user_runtime_dir.patch @@ -0,0 +1,113 @@ +From 4d5dec2389d8e6ce78b45d3058220888f4a93db7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 2 Oct 2014 08:01:00 -0400 +Subject: [PATCH] Rename user_runtime to user_runtime_dir + +This makes this function name similar to user_config_home() and makes +it match the name of the environment variable. +--- + src/core/unit.c | 4 ++-- + src/shared/install.c | 2 +- + src/shared/path-lookup.c | 12 ++++++------ + src/shared/path-lookup.h | 2 +- + 4 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 8a7df01284..399d202738 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3083,7 +3083,7 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, + if (mode == UNIT_PERSISTENT && !transient) + r = user_config_home(dir); + else +- r = user_runtime(dir); ++ r = user_runtime_dir(dir); + + if (r == 0) + return -ENOENT; +@@ -3232,7 +3232,7 @@ int unit_make_transient(Unit *u) { + if (u->manager->running_as == SYSTEMD_USER) { + _cleanup_free_ char *c = NULL; + +- r = user_runtime(&c); ++ r = user_runtime_dir(&c); + if (r < 0) + return r; + if (r == 0) +diff --git a/src/shared/install.c b/src/shared/install.c +index 302b5237a6..fa064c230f 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -109,7 +109,7 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d + return -EINVAL; + + if (runtime) +- r = user_runtime(&p); ++ r = user_runtime_dir(&p); + else + r = user_config_home(&p); + +diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c +index 3a6e117d28..d7ed6e9e3c 100644 +--- a/src/shared/path-lookup.c ++++ b/src/shared/path-lookup.c +@@ -61,7 +61,7 @@ int user_config_home(char **config_home) { + return 0; + } + +-int user_runtime(char **user_runtime_path) { ++int user_runtime_dir(char **runtime_dir) { + const char *e; + char *r; + +@@ -71,7 +71,7 @@ int user_runtime(char **user_runtime_path) { + if (!r) + return -ENOMEM; + +- *user_runtime_path = r; ++ *runtime_dir = r; + return 1; + } + +@@ -101,7 +101,7 @@ static char** user_dirs( + }; + + const char *home, *e; +- _cleanup_free_ char *config_home = NULL, *user_runtime_dir = NULL, *data_home = NULL; ++ _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL; + _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL; + char **r = NULL; + +@@ -117,7 +117,7 @@ static char** user_dirs( + if (user_config_home(&config_home) < 0) + goto fail; + +- if (user_runtime(&user_runtime_dir) < 0) ++ if (user_runtime_dir(&runtime_dir) < 0) + goto fail; + + home = getenv("HOME"); +@@ -162,8 +162,8 @@ static char** user_dirs( + if (strv_extend(&r, config_home) < 0) + goto fail; + +- if (user_runtime_dir) +- if (strv_extend(&r, user_runtime_dir) < 0) ++ if (runtime_dir) ++ if (strv_extend(&r, runtime_dir) < 0) + goto fail; + + if (strv_extend(&r, runtime_unit_path) < 0) +diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h +index 8da076a30b..b8a0aace83 100644 +--- a/src/shared/path-lookup.h ++++ b/src/shared/path-lookup.h +@@ -39,7 +39,7 @@ typedef enum SystemdRunningAs { + } SystemdRunningAs; + + int user_config_home(char **config_home); +-int user_runtime(char **user_runtime_path); ++int user_runtime_dir(char **runtime_dir); + + int lookup_paths_init(LookupPaths *p, + SystemdRunningAs running_as, diff --git a/0455-Fix-order-and-document-user-unit-dirs.patch b/0455-Fix-order-and-document-user-unit-dirs.patch new file mode 100644 index 0000000..6c01f4d --- /dev/null +++ b/0455-Fix-order-and-document-user-unit-dirs.patch @@ -0,0 +1,63 @@ +From aa08982d62cf45b59ea6a06c915391f5db1fb86e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 2 Oct 2014 08:11:21 -0400 +Subject: [PATCH] Fix order and document user unit dirs + +Fixup for 718880ba0d 'add a transient user unit directory'. +--- + man/systemd.unit.xml | 5 +++++ + src/shared/path-lookup.c | 12 ++++++------ + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml +index 67d46eda98..ec7ca5634e 100644 +--- a/man/systemd.unit.xml ++++ b/man/systemd.unit.xml +@@ -73,6 +73,7 @@ + $XDG_CONFIG_HOME/systemd/user/* + $HOME/.config/systemd/user/* + /etc/systemd/user/* ++$XDG_RUNTIME_DIR/systemd/user/* + /run/systemd/user/* + $XDG_DATA_HOME/systemd/user/* + $HOME/.local/share/systemd/user/* +@@ -344,6 +345,10 @@ + Local configuration + + ++ $XDG_RUNTIME_DIR/systemd/user ++ Runtime units (only used when $XDG_RUNTIME_DIR is set) ++ ++ + /run/systemd/user + Runtime units + +diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c +index d7ed6e9e3c..8f75a8e832 100644 +--- a/src/shared/path-lookup.c ++++ b/src/shared/path-lookup.c +@@ -162,18 +162,18 @@ static char** user_dirs( + if (strv_extend(&r, config_home) < 0) + goto fail; + +- if (runtime_dir) +- if (strv_extend(&r, runtime_dir) < 0) ++ if (!strv_isempty(config_dirs)) ++ if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0) + goto fail; + +- if (strv_extend(&r, runtime_unit_path) < 0) ++ if (strv_extend_strv(&r, (char**) config_unit_paths) < 0) + goto fail; + +- if (!strv_isempty(config_dirs)) +- if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0) ++ if (runtime_dir) ++ if (strv_extend(&r, runtime_dir) < 0) + goto fail; + +- if (strv_extend_strv(&r, (char**) config_unit_paths) < 0) ++ if (strv_extend(&r, runtime_unit_path) < 0) + goto fail; + + if (generator) diff --git a/0456-virt-detect-that-we-are-running-inside-the-docker-co.patch b/0456-virt-detect-that-we-are-running-inside-the-docker-co.patch new file mode 100644 index 0000000..fbdf324 --- /dev/null +++ b/0456-virt-detect-that-we-are-running-inside-the-docker-co.patch @@ -0,0 +1,22 @@ +From 893e72da6b27c21b102e1589276e651e9e4f591c Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 9 Sep 2014 18:14:25 +0200 +Subject: [PATCH] virt: detect that we are running inside the docker container + +--- + src/shared/virt.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/shared/virt.c b/src/shared/virt.c +index b4368952ff..f9c4e67c74 100644 +--- a/src/shared/virt.c ++++ b/src/shared/virt.c +@@ -310,6 +310,8 @@ int detect_container(const char **id) { + _id = "lxc-libvirt"; + else if (streq(e, "systemd-nspawn")) + _id = "systemd-nspawn"; ++ else if (streq(e, "docker")) ++ _id = "docker"; + else + _id = "other"; + diff --git a/0457-sd-bus-sync-kdbus.h-ABI-break.patch b/0457-sd-bus-sync-kdbus.h-ABI-break.patch new file mode 100644 index 0000000..5240ea7 --- /dev/null +++ b/0457-sd-bus-sync-kdbus.h-ABI-break.patch @@ -0,0 +1,40 @@ +From 995a1063dbdc94e2c0846216363636e8ebbc60f9 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Thu, 2 Oct 2014 17:12:13 +0200 +Subject: [PATCH] sd-bus: sync kdbus.h (ABI break!) + +struct kdbus_cmd_match got a flags field, which systemd currently makes no +use of. +--- + src/libsystemd/sd-bus/kdbus.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index c97994974b..801125946b 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -714,6 +714,16 @@ struct kdbus_cmd_update { + } __attribute__((aligned(8))); + + /** ++ * enum kdbus_cmd_match_flags - flags to control the KDBUS_CMD_MATCH_ADD ioctl ++ * @KDBUS_MATCH_REPLACE: If entries with the supplied cookie already ++ * exists, remove them before installing the new ++ * matches. ++ */ ++enum kdbus_cmd_match_flags { ++ KDBUS_MATCH_REPLACE = 1ULL << 0, ++}; ++ ++/** + * struct kdbus_cmd_match - struct to add or remove matches + * @size: The total size of the struct + * @cookie: Userspace supplied cookie. When removing, the cookie +@@ -726,6 +736,7 @@ struct kdbus_cmd_update { + struct kdbus_cmd_match { + __u64 size; + __u64 cookie; ++ __u64 flags; + struct kdbus_item items[0]; + } __attribute__((aligned(8))); + diff --git a/0458-sd-dhcp6-client-support-custom-DUIDs.patch b/0458-sd-dhcp6-client-support-custom-DUIDs.patch new file mode 100644 index 0000000..6661d9b --- /dev/null +++ b/0458-sd-dhcp6-client-support-custom-DUIDs.patch @@ -0,0 +1,134 @@ +From 66eac1201a9c1596f5901f8dbbf24bda7e350878 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Fri, 26 Sep 2014 15:12:36 -0500 +Subject: [PATCH] sd-dhcp6-client: support custom DUIDs + +The caller may have an existing DUID that it wants to use, and may +want to use some other DUID generation scheme than systemd's +default DUID-EN. + +[tomegun: whitespace - we never use tabs] +--- + src/libsystemd-network/sd-dhcp6-client.c | 43 +++++++++++++++++++++++--------- + src/systemd/sd-dhcp6-client.h | 2 ++ + 2 files changed, 33 insertions(+), 12 deletions(-) + +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index c190b560ea..130fe43cf2 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -39,6 +39,8 @@ + #define SYSTEMD_PEN 43793 + #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) + ++#define MAX_DUID_LEN 32 ++ + struct sd_dhcp6_client { + RefCount n_ref; + +@@ -62,12 +64,8 @@ struct sd_dhcp6_client { + sd_event_source *timeout_resend_expire; + sd_dhcp6_client_cb_t cb; + void *userdata; +- +- struct duid_en { +- uint16_t type; /* DHCP6_DUID_EN */ +- uint32_t pen; +- uint8_t id[8]; +- } _packed_ duid; ++ uint8_t duid[MAX_DUID_LEN]; ++ size_t duid_len; + }; + + static const uint16_t default_req_opts[] = { +@@ -147,6 +145,19 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, + return 0; + } + ++int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint8_t *duid, ++ size_t duid_len) ++{ ++ assert_return(client, -EINVAL); ++ assert_return(duid, -EINVAL); ++ assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); ++ ++ memcpy(&client->duid, duid, duid_len); ++ client->duid_len = duid_len; ++ ++ return 0; ++} ++ + int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, + uint16_t option) { + size_t t; +@@ -308,7 +319,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { + return r; + + r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID, +- sizeof(client->duid), &client->duid); ++ client->duid_len, &client->duid); + if (r < 0) + return r; + +@@ -616,7 +627,7 @@ static int client_parse_message(sd_dhcp6_client *client, + return -EINVAL; + } + +- if (optlen != sizeof(client->duid) || ++ if (optlen != client->duid_len || + memcmp(&client->duid, optval, optlen) != 0) { + log_dhcp6_client(client, "%s DUID does not match", + dhcp6_message_type_to_string(message->type)); +@@ -1116,9 +1127,16 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { + return client; + } + ++struct duid_en { ++ uint16_t type; /* DHCP6_DUID_EN */ ++ uint32_t pen; ++ uint8_t id[8]; ++} _packed_; ++ + int sd_dhcp6_client_new(sd_dhcp6_client **ret) + { + _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; ++ struct duid_en *duid; + sd_id128_t machine_id; + int r; + size_t t; +@@ -1138,8 +1156,9 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) + client->fd = -1; + + /* initialize DUID */ +- client->duid.type = htobe16(DHCP6_DUID_EN); +- client->duid.pen = htobe32(SYSTEMD_PEN); ++ duid = (struct duid_en *) &client->duid; ++ duid->type = htobe16(DHCP6_DUID_EN); ++ duid->pen = htobe32(SYSTEMD_PEN); + + r = sd_id128_get_machine(&machine_id); + if (r < 0) +@@ -1147,8 +1166,8 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) + + /* a bit of snake-oil perhaps, but no need to expose the machine-id + directly */ +- siphash24(client->duid.id, &machine_id, sizeof(machine_id), +- HASH_KEY.bytes); ++ siphash24(duid->id, &machine_id, sizeof(machine_id), HASH_KEY.bytes); ++ client->duid_len = sizeof (struct duid_en); + + client->req_opts_len = ELEMENTSOF(default_req_opts); + +diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h +index 93edcc41fc..7b7f098b0c 100644 +--- a/src/systemd/sd-dhcp6-client.h ++++ b/src/systemd/sd-dhcp6-client.h +@@ -45,6 +45,8 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, + int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); + int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, + const struct ether_addr *mac_addr); ++int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint8_t *duid, ++ size_t duid_len); + int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, + uint16_t option); + diff --git a/0459-sd-dhcp6-support-custom-DUID-s-up-to-the-size-specif.patch b/0459-sd-dhcp6-support-custom-DUID-s-up-to-the-size-specif.patch new file mode 100644 index 0000000..c79ebb9 --- /dev/null +++ b/0459-sd-dhcp6-support-custom-DUID-s-up-to-the-size-specif.patch @@ -0,0 +1,26 @@ +From 9547267dc56d5bf84b8119dfcb8e101202fac7d3 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 2 Oct 2014 16:00:55 +0200 +Subject: [PATCH] sd-dhcp6: support custom DUID's up to the size specified in + the RFC + +--- + src/libsystemd-network/sd-dhcp6-client.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index 130fe43cf2..ad6c5eb4d8 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -39,7 +39,10 @@ + #define SYSTEMD_PEN 43793 + #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) + +-#define MAX_DUID_LEN 32 ++/* RFC 3315 section 9.1: ++ * A DUID can be no more than 128 octets long (not including the type code). ++ */ ++#define MAX_DUID_LEN 128 + + struct sd_dhcp6_client { + RefCount n_ref; diff --git a/0460-sd-dhcp6-specify-the-type-explicitly-when-setting-cu.patch b/0460-sd-dhcp6-specify-the-type-explicitly-when-setting-cu.patch new file mode 100644 index 0000000..05bc1ab --- /dev/null +++ b/0460-sd-dhcp6-specify-the-type-explicitly-when-setting-cu.patch @@ -0,0 +1,107 @@ +From ebe207d4acf38165adbc45298662982eecdb9e9f Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 2 Oct 2014 16:04:20 +0200 +Subject: [PATCH] sd-dhcp6: specify the type explicitly when setting custom + DUID + +This would make it simple to verify that the data is on the right format when +the type is known. +--- + src/libsystemd-network/sd-dhcp6-client.c | 33 +++++++++++++++++--------------- + src/systemd/sd-dhcp6-client.h | 2 +- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index ad6c5eb4d8..42ad41887d 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -67,7 +67,17 @@ struct sd_dhcp6_client { + sd_event_source *timeout_resend_expire; + sd_dhcp6_client_cb_t cb; + void *userdata; +- uint8_t duid[MAX_DUID_LEN]; ++ union { ++ struct { ++ uint16_t type; /* DHCP6_DUID_EN */ ++ uint32_t pen; ++ uint8_t id[8]; ++ } _packed_ en; ++ struct { ++ uint16_t type; ++ uint8_t data[MAX_DUID_LEN]; ++ } _packed_ raw; ++ } duid; + size_t duid_len; + }; + +@@ -148,14 +158,15 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, + return 0; + } + +-int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint8_t *duid, ++int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, + size_t duid_len) + { + assert_return(client, -EINVAL); + assert_return(duid, -EINVAL); + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + +- memcpy(&client->duid, duid, duid_len); ++ client->duid.raw.type = htobe16(type); ++ memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len; + + return 0; +@@ -1130,16 +1141,9 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { + return client; + } + +-struct duid_en { +- uint16_t type; /* DHCP6_DUID_EN */ +- uint32_t pen; +- uint8_t id[8]; +-} _packed_; +- + int sd_dhcp6_client_new(sd_dhcp6_client **ret) + { + _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; +- struct duid_en *duid; + sd_id128_t machine_id; + int r; + size_t t; +@@ -1159,9 +1163,9 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) + client->fd = -1; + + /* initialize DUID */ +- duid = (struct duid_en *) &client->duid; +- duid->type = htobe16(DHCP6_DUID_EN); +- duid->pen = htobe32(SYSTEMD_PEN); ++ client->duid.en.type = htobe16(DHCP6_DUID_EN); ++ client->duid.en.pen = htobe32(SYSTEMD_PEN); ++ client->duid_len = sizeof(client->duid.en); + + r = sd_id128_get_machine(&machine_id); + if (r < 0) +@@ -1169,8 +1173,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) + + /* a bit of snake-oil perhaps, but no need to expose the machine-id + directly */ +- siphash24(duid->id, &machine_id, sizeof(machine_id), HASH_KEY.bytes); +- client->duid_len = sizeof (struct duid_en); ++ siphash24(client->duid.en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes); + + client->req_opts_len = ELEMENTSOF(default_req_opts); + +diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h +index 7b7f098b0c..a4409e8d4e 100644 +--- a/src/systemd/sd-dhcp6-client.h ++++ b/src/systemd/sd-dhcp6-client.h +@@ -45,7 +45,7 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, + int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); + int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, + const struct ether_addr *mac_addr); +-int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint8_t *duid, ++int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, + size_t duid_len); + int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, + uint16_t option); diff --git a/0461-sd-dhcp6-do-basic-sanity-checking-of-supplied-DUID.patch b/0461-sd-dhcp6-do-basic-sanity-checking-of-supplied-DUID.patch new file mode 100644 index 0000000..0c7f5c9 --- /dev/null +++ b/0461-sd-dhcp6-do-basic-sanity-checking-of-supplied-DUID.patch @@ -0,0 +1,69 @@ +From fe4b2156256c5bdf52341576571ce9f095d9f085 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Thu, 2 Oct 2014 16:25:08 +0200 +Subject: [PATCH] sd-dhcp6: do basic sanity-checking of supplied DUID + +--- + src/libsystemd-network/sd-dhcp6-client.c | 37 ++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c +index 42ad41887d..6ea68c915f 100644 +--- a/src/libsystemd-network/sd-dhcp6-client.c ++++ b/src/libsystemd-network/sd-dhcp6-client.c +@@ -69,11 +69,26 @@ struct sd_dhcp6_client { + void *userdata; + union { + struct { ++ uint16_t type; /* DHCP6_DUID_LLT */ ++ uint16_t htype; ++ uint32_t time; ++ uint8_t haddr[0]; ++ } _packed_ llt; ++ struct { + uint16_t type; /* DHCP6_DUID_EN */ + uint32_t pen; + uint8_t id[8]; + } _packed_ en; + struct { ++ uint16_t type; /* DHCP6_DUID_LL */ ++ uint16_t htype; ++ uint8_t haddr[0]; ++ } _packed_ ll; ++ struct { ++ uint16_t type; /* DHCP6_DUID_UUID */ ++ sd_id128_t uuid; ++ } _packed_ uuid; ++ struct { + uint16_t type; + uint8_t data[MAX_DUID_LEN]; + } _packed_ raw; +@@ -165,6 +180,28 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du + assert_return(duid, -EINVAL); + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + ++ switch (type) { ++ case DHCP6_DUID_LLT: ++ if (duid_len <= sizeof(client->duid.llt)) ++ return -EINVAL; ++ break; ++ case DHCP6_DUID_EN: ++ if (duid_len != sizeof(client->duid.en)) ++ return -EINVAL; ++ break; ++ case DHCP6_DUID_LL: ++ if (duid_len <= sizeof(client->duid.ll)) ++ return -EINVAL; ++ break; ++ case DHCP6_DUID_UUID: ++ if (duid_len != sizeof(client->duid.uuid)) ++ return -EINVAL; ++ break; ++ default: ++ /* accept unknown type in order to be forward compatible */ ++ break; ++ } ++ + client->duid.raw.type = htobe16(type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len; diff --git a/0462-update-TODO.patch b/0462-update-TODO.patch new file mode 100644 index 0000000..5408cba --- /dev/null +++ b/0462-update-TODO.patch @@ -0,0 +1,22 @@ +From c7eff5ec06c3025d1ef14f955c653259ae7c615b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Oct 2014 20:36:23 +0200 +Subject: [PATCH] update TODO + +--- + TODO | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/TODO b/TODO +index 9ac6fac8cf..526926f862 100644 +--- a/TODO ++++ b/TODO +@@ -26,6 +26,8 @@ External: + + Features: + ++* busctl: add a pcap writer, using LINKTYPE_DBUS/231 ++ + * man: maybe use the word "inspect" rather than "introspect"? + + * introduce machines.target to order after all nspawn instances diff --git a/0463-kdbus-make-sure-we-never-invoke-free-on-an-uninitial.patch b/0463-kdbus-make-sure-we-never-invoke-free-on-an-uninitial.patch new file mode 100644 index 0000000..51eb60d --- /dev/null +++ b/0463-kdbus-make-sure-we-never-invoke-free-on-an-uninitial.patch @@ -0,0 +1,23 @@ +From 8e00bfc234f43f49b16aa0124fb4b3f1c8eae4ef Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Oct 2014 20:36:58 +0200 +Subject: [PATCH] kdbus: make sure we never invoke free() on an uninitialized + pointer on OOM + +--- + src/libsystemd/sd-bus/bus-kernel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 236e8787b7..0e74f9136a 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -1411,7 +1411,7 @@ int bus_kernel_open_bus_fd(const char *bus, char **path) { + } + + int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **ep_path) { +- _cleanup_free_ char *path; ++ _cleanup_free_ char *path = NULL; + struct kdbus_cmd_make *make; + struct kdbus_item *n; + size_t size; diff --git a/0464-kdbus-don-t-clobber-return-values-use-strjoin-instea.patch b/0464-kdbus-don-t-clobber-return-values-use-strjoin-instea.patch new file mode 100644 index 0000000..c1e123e --- /dev/null +++ b/0464-kdbus-don-t-clobber-return-values-use-strjoin-instea.patch @@ -0,0 +1,32 @@ +From 2c652b6bfe816296a5664dae1125e6bb665b9d5e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Oct 2014 20:37:36 +0200 +Subject: [PATCH] kdbus: don't clobber return values, use strjoin() instead of + asprintf(), keep function invocations and variable declarations separate + +--- + src/libsystemd/sd-bus/bus-kernel.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 0e74f9136a..0c39e22ed7 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -1447,11 +1447,15 @@ int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char * + } + + if (ep_path) { +- int r = asprintf(ep_path, "%s/%s", dirname(path), ep_name); +- if (r == -1 || !*ep_path) { ++ char *p; ++ ++ p = strjoin(dirname(path), "/", ep_name, NULL); ++ if (!p) { + safe_close(fd); + return -ENOMEM; + } ++ ++ *ep_path = p; + } + + return fd; diff --git a/0465-systemctl-remove-spurious-newline.patch b/0465-systemctl-remove-spurious-newline.patch new file mode 100644 index 0000000..2aaf08e --- /dev/null +++ b/0465-systemctl-remove-spurious-newline.patch @@ -0,0 +1,24 @@ +From cc19881a694c26af2d941246f72221df7e76ee02 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Oct 2014 20:37:50 +0200 +Subject: [PATCH] systemctl: remove spurious newline + +--- + src/systemctl/systemctl.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 901212852d..1c6fef484e 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4466,9 +4466,7 @@ static int cat(sd_bus *bus, char **args) { + STRV_FOREACH(name, names) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **dropin_paths = NULL; +- _cleanup_free_ char *fragment_path = NULL; +- _cleanup_free_ char *unit = NULL; +- ++ _cleanup_free_ char *fragment_path = NULL, *unit = NULL; + char **path; + + unit = unit_dbus_path_from_name(*name); diff --git a/0466-Revert-mount-order-options-before-other-arguments-to.patch b/0466-Revert-mount-order-options-before-other-arguments-to.patch new file mode 100644 index 0000000..154b2a7 --- /dev/null +++ b/0466-Revert-mount-order-options-before-other-arguments-to.patch @@ -0,0 +1,43 @@ +From 2ff8abbd40feee90dbac8788efba2218b546df6c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Oct 2014 21:02:03 +0200 +Subject: [PATCH] Revert "mount: order options before other arguments to mount" + +This reverts commit 141a1ceaa62578f1ed14f04cae2113dd0f49fd7f. + +People should fix their libc's getopt(), instead of us using a weird +option ordering... +--- + src/core/mount.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index f3ec7365d1..e284357c6f 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -903,10 +903,10 @@ static void mount_enter_mounting(Mount *m) { + m->control_command, + "/bin/mount", + m->sloppy_options ? "-ns" : "-n", +- "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", +- "-o", m->parameters_fragment.options ? m->parameters_fragment.options : "", + m->parameters_fragment.what, + m->where, ++ "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", ++ m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options, + NULL); + else + r = -ENOENT; +@@ -951,10 +951,10 @@ static void mount_enter_remounting(Mount *m) { + m->control_command, + "/bin/mount", + m->sloppy_options ? "-ns" : "-n", +- "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", +- "-o", o, + m->parameters_fragment.what, + m->where, ++ "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", ++ "-o", o, + NULL); + } else + r = -ENOENT; diff --git a/0467-firstboot-silence-coverity.patch b/0467-firstboot-silence-coverity.patch new file mode 100644 index 0000000..4362c9f --- /dev/null +++ b/0467-firstboot-silence-coverity.patch @@ -0,0 +1,23 @@ +From 94956f8fba498d5d34a88a7e26b0418a4a0e9e6d Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Thu, 2 Oct 2014 21:26:11 +0200 +Subject: [PATCH] firstboot: silence coverity + +CID#1237537 +--- + src/firstboot/firstboot.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c +index 215c059ee2..f586c2ef7f 100644 +--- a/src/firstboot/firstboot.c ++++ b/src/firstboot/firstboot.c +@@ -68,7 +68,7 @@ static bool press_any_key(void) { + printf("-- Press any key to proceed --"); + fflush(stdout); + +- read_one_char(stdin, &k, USEC_INFINITY, &need_nl); ++ (void) read_one_char(stdin, &k, USEC_INFINITY, &need_nl); + + if (need_nl) + putchar('\n'); diff --git a/0468-man-add-sd_event_get_fd-3.patch b/0468-man-add-sd_event_get_fd-3.patch new file mode 100644 index 0000000..a932085 --- /dev/null +++ b/0468-man-add-sd_event_get_fd-3.patch @@ -0,0 +1,177 @@ +From ba4b35669ef233fef414b1429fbdc085537b33e7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 2 Oct 2014 20:49:30 -0400 +Subject: [PATCH] man: add sd_event_get_fd(3) + +Example from Tom Gundersen is included using xi:include. +The copyright notice stands out a bit. Maybe it should be removed, +and the code placed in public domain. +--- + Makefile-man.am | 2 + + man/sd_event_get_fd.xml | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 139 insertions(+) + create mode 100644 man/sd_event_get_fd.xml + +diff --git a/Makefile-man.am b/Makefile-man.am +index 2b3fa95e70..aff5186c2d 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -733,6 +733,7 @@ MANPAGES += \ + man/sd_event_add_defer.3 \ + man/sd_event_add_signal.3 \ + man/sd_event_add_time.3 \ ++ man/sd_event_get_fd.3 \ + man/sd_event_new.3 \ + man/systemd-bus-proxyd.8 \ + man/systemd-bus-proxyd@.service.8 +@@ -1574,6 +1575,7 @@ EXTRA_DIST += \ + man/sd_event_add_defer.xml \ + man/sd_event_add_signal.xml \ + man/sd_event_add_time.xml \ ++ man/sd_event_get_fd.xml \ + man/sd_event_new.xml \ + man/sd_get_seats.xml \ + man/sd_id128_get_machine.xml \ +diff --git a/man/sd_event_get_fd.xml b/man/sd_event_get_fd.xml +new file mode 100644 +index 0000000000..f60d807136 +--- /dev/null ++++ b/man/sd_event_get_fd.xml +@@ -0,0 +1,137 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd_event_get_fd ++ systemd ++ ++ ++ ++ More text ++ Zbigniew ++ Jędrzejewski-Szmek ++ zbyszek@in.waw.pl ++ ++ ++ ++ ++ ++ sd_event_get_fd ++ 3 ++ ++ ++ ++ sd_event_get_fd ++ ++ Obtain a file descriptor to poll for event loop events ++ ++ ++ ++ ++ #include <systemd/sd-bus.h> ++ ++ ++ int sd_event_get_fd ++ sd_bus *event ++ ++ ++ ++ ++ ++ ++ Description ++ ++ sd_event_get_fd() returns the file ++ descriptor that the event loop object returned by the ++ sd_event_new3 ++ function uses to wait for events. This file descriptor can be ++ polled for events. This makes it possible to embed the ++ sd-event3 ++ event loop inside of another event loop. ++ ++ ++ ++ Return Value ++ ++ On success, sd_event_get_fd() returns a ++ non-negative integer. On failure, it returns a negative ++ errno-style error code. ++ ++ ++ ++ Errors ++ ++ Returned errors may indicate the following problems: ++ ++ ++ ++ -EINVAL ++ ++ event is not a valid ++ pointer to an sd_event structure. ++ ++ ++ ++ ++ -ECHILD ++ ++ The event loop has been created in a different process. ++ ++ ++ ++ ++ ++ ++ Examples ++ ++ ++ Integration in glib event loop ++ ++ ++ ++ ++ ++ ++ Notes ++ ++ sd_event_get_fd() is available as a ++ shared library, which can be compiled and linked to with the ++ libsystemd pkg-config1 ++ file. ++ ++ ++ ++ See Also ++ ++ ++ sd-event3, ++ sd_event_new3, ++ sd_event_ref3 ++ ++ ++ ++ diff --git a/0469-man-add-sd_event_set_name-3.patch b/0469-man-add-sd_event_set_name-3.patch new file mode 100644 index 0000000..3c2795c --- /dev/null +++ b/0469-man-add-sd_event_set_name-3.patch @@ -0,0 +1,214 @@ +From 043f62949e6eb400ad42fd891a957ecf514c35f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 2 Oct 2014 21:14:26 -0400 +Subject: [PATCH] man: add sd_event_set_name(3) + +--- + Makefile-man.am | 7 +++ + man/sd_event_set_name.xml | 151 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 158 insertions(+) + create mode 100644 man/sd_event_set_name.xml + +diff --git a/Makefile-man.am b/Makefile-man.am +index aff5186c2d..a13e948bc8 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -735,6 +735,7 @@ MANPAGES += \ + man/sd_event_add_time.3 \ + man/sd_event_get_fd.3 \ + man/sd_event_new.3 \ ++ man/sd_event_set_name.3 \ + man/systemd-bus-proxyd.8 \ + man/systemd-bus-proxyd@.service.8 + MANPAGES_ALIAS += \ +@@ -795,6 +796,7 @@ MANPAGES_ALIAS += \ + man/sd_event_add_exit.3 \ + man/sd_event_add_post.3 \ + man/sd_event_default.3 \ ++ man/sd_event_get_name.3 \ + man/sd_event_ref.3 \ + man/sd_event_source_get_child_pid.3 \ + man/sd_event_source_get_signal.3 \ +@@ -862,6 +864,7 @@ man/sd_bus_unref.3: man/sd_bus_new.3 + man/sd_event_add_exit.3: man/sd_event_add_defer.3 + man/sd_event_add_post.3: man/sd_event_add_defer.3 + man/sd_event_default.3: man/sd_event_new.3 ++man/sd_event_get_name.3: man/sd_event_set_name.3 + man/sd_event_ref.3: man/sd_event_new.3 + man/sd_event_source_get_child_pid.3: man/sd_event_add_child.3 + man/sd_event_source_get_signal.3: man/sd_event_add_signal.3 +@@ -1043,6 +1046,9 @@ man/sd_event_add_post.html: man/sd_event_add_defer.html + man/sd_event_default.html: man/sd_event_new.html + $(html-alias) + ++man/sd_event_get_name.html: man/sd_event_set_name.html ++ $(html-alias) ++ + man/sd_event_ref.html: man/sd_event_new.html + $(html-alias) + +@@ -1577,6 +1583,7 @@ EXTRA_DIST += \ + man/sd_event_add_time.xml \ + man/sd_event_get_fd.xml \ + man/sd_event_new.xml \ ++ man/sd_event_set_name.xml \ + man/sd_get_seats.xml \ + man/sd_id128_get_machine.xml \ + man/sd_id128_randomize.xml \ +diff --git a/man/sd_event_set_name.xml b/man/sd_event_set_name.xml +new file mode 100644 +index 0000000000..406d124972 +--- /dev/null ++++ b/man/sd_event_set_name.xml +@@ -0,0 +1,151 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd_event_set_name ++ systemd ++ ++ ++ ++ More text ++ Zbigniew ++ Jędrzejewski-Szmek ++ zbyszek@in.waw.pl ++ ++ ++ ++ ++ ++ sd_event_set_name ++ 3 ++ ++ ++ ++ sd_event_set_name ++ sd_event_get_name ++ ++ Set human-readable names for event sources ++ ++ ++ ++ ++ #include <systemd/sd-bus.h> ++ ++ ++ int sd_event_set_name ++ sd_event_source *source ++ const char *name ++ ++ ++ ++ int sd_event_get_name ++ sd_event_source *source ++ const char **name ++ ++ ++ ++ ++ ++ ++ Description ++ ++ sd_event_set_name() can be used to set ++ an arbitrary name for the event source ++ source. This name will be used in error ++ messages generated by ++ sd-event3 ++ for this source. Specified name must point ++ to a NUL-terminated string or be ++ NULL. In the latter case, the name will be ++ unset. The string is copied internally, so the ++ name argument is not referenced after the ++ function returns. ++ ++ sd_event_set_name() can be used to ++ query the current name assigned to source ++ source. It returns a pointer to the current ++ name (possibly NULL) in ++ name. ++ ++ ++ ++ Return Value ++ ++ On success, sd_event_set_name() and ++ sd_event_get_name() return a ++ non-negative integer. On failure, they return a negative ++ errno-style error code. ++ ++ ++ ++ Errors ++ ++ Returned errors may indicate the following problems: ++ ++ ++ ++ -EINVAL ++ ++ source is not a valid ++ pointer to an sd_event_source ++ structure or the name argument for ++ sd_event_get_name() is ++ NULL. ++ ++ ++ ++ -ENOMEM ++ ++ Not enough memory to copy the ++ name. ++ ++ ++ ++ ++ ++ Notes ++ ++ Functions described here are available as a ++ shared library, which can be compiled and linked to with the ++ libsystemd pkg-config1 ++ file. ++ ++ ++ ++ See Also ++ ++ ++ sd-event3, ++ sd_event_add_time3, ++ sd_event_add_child3, ++ sd_event_add_signal3, ++ sd_event_add_defer3, ++ sd_event_run3 ++ ++ ++ ++ diff --git a/0470-test-barrier-add-checks-after-the-barrier-constructo.patch b/0470-test-barrier-add-checks-after-the-barrier-constructo.patch new file mode 100644 index 0000000..624b18c --- /dev/null +++ b/0470-test-barrier-add-checks-after-the-barrier-constructo.patch @@ -0,0 +1,29 @@ +From 2ad8887a12aeff9108606bb31e1557103a3b95df Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Fri, 3 Oct 2014 03:58:51 +0200 +Subject: [PATCH] test-barrier: add checks after the barrier constructor + +Coverity seems to think that we can later end up with the "them" +fd having a negative value. Even after a succesful barrier_create. +Add some test to verify that the constructor went well. If coverity +still complains then it must mean that it thinks the the value is +overwritten later. +--- + src/test/test-barrier.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c +index 36f27809ca..cb75f7314d 100644 +--- a/src/test/test-barrier.c ++++ b/src/test/test-barrier.c +@@ -64,6 +64,10 @@ static void sleep_for(usec_t usecs) { + pid_t pid1, pid2; \ + \ + assert_se(barrier_create(&b) >= 0); \ ++ assert_se(b.me > 0); \ ++ assert_se(b.them > 0); \ ++ assert_se(b.pipe[0] > 0); \ ++ assert_se(b.pipe[1] > 0); \ + \ + pid1 = fork(); \ + assert_se(pid1 >= 0); \ diff --git a/0471-glib-event-glue-remove-some-unnecessary-lines.patch b/0471-glib-event-glue-remove-some-unnecessary-lines.patch new file mode 100644 index 0000000..458f2f1 --- /dev/null +++ b/0471-glib-event-glue-remove-some-unnecessary-lines.patch @@ -0,0 +1,29 @@ +From c3b128736dbde629db87751cd706a0b68a41e7d0 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 3 Oct 2014 08:43:34 +0200 +Subject: [PATCH] glib-event-glue: remove some unnecessary lines + +Not needed in an example. Should still shorten the license, but should make sure it is still complete so people can copy-paste without problems. +--- + man/glib-event-glue.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/man/glib-event-glue.c b/man/glib-event-glue.c +index 95aaea1e63..c3719e3378 100644 +--- a/man/glib-event-glue.c ++++ b/man/glib-event-glue.c +@@ -1,5 +1,3 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- + /*** + Copyright 2014 Tom Gundersen + +@@ -28,8 +26,6 @@ + #include + #include + +-#include "glib-event-glue.h" +- + typedef struct SDEventSource { + GSource source; + GPollFD pollfd; diff --git a/0472-man-fix-sd_event_set_name-compilation.patch b/0472-man-fix-sd_event_set_name-compilation.patch new file mode 100644 index 0000000..7479f54 --- /dev/null +++ b/0472-man-fix-sd_event_set_name-compilation.patch @@ -0,0 +1,22 @@ +From 7889087d6ecf865f332eb325d8f68ff49be8277e Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Fri, 3 Oct 2014 08:43:53 +0200 +Subject: [PATCH] man: fix sd_event_set_name compilation + +--- + man/sd_event_set_name.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/sd_event_set_name.xml b/man/sd_event_set_name.xml +index 406d124972..551eef3de7 100644 +--- a/man/sd_event_set_name.xml ++++ b/man/sd_event_set_name.xml +@@ -21,7 +21,7 @@ You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + --> + +- + + diff --git a/0473-bootchart-use-n-a-if-PRETTY_NAME-is-not-found.patch b/0473-bootchart-use-n-a-if-PRETTY_NAME-is-not-found.patch new file mode 100644 index 0000000..9e782e6 --- /dev/null +++ b/0473-bootchart-use-n-a-if-PRETTY_NAME-is-not-found.patch @@ -0,0 +1,28 @@ +From 1c92ff85b786c423f4436ec26007e79369c9ac05 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Fri, 26 Sep 2014 22:01:32 +0200 +Subject: [PATCH] bootchart: use 'n/a' if PRETTY_NAME is not found + +Spotted with coverity. If parsing both /etc/os-release and +/usr/lib/os-release fails then null would be passed on. The calls +to parse the two files are allowed to fail. A empty /etc may not +have had the /etc/os-release symlink restored yet and we just +try again in the loop. If for whatever reason that does not happen +then we now pass on 'n/a' instead of null. +--- + src/bootchart/bootchart.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c +index 366a5ab5d0..813e38deeb 100644 +--- a/src/bootchart/bootchart.c ++++ b/src/bootchart/bootchart.c +@@ -471,7 +471,7 @@ int main(int argc, char *argv[]) { + exit (EXIT_FAILURE); + } + +- svg_do(build); ++ svg_do(strna(build)); + + fprintf(stderr, "systemd-bootchart wrote %s\n", output_file); + diff --git a/0474-journalctl-make-utc-work-everywhere.patch b/0474-journalctl-make-utc-work-everywhere.patch new file mode 100644 index 0000000..b232e65 --- /dev/null +++ b/0474-journalctl-make-utc-work-everywhere.patch @@ -0,0 +1,133 @@ +From a62e83b48cda6a709a796a361abaf6b129650b3c Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 3 Oct 2014 09:51:33 +0200 +Subject: [PATCH] journalctl: make --utc work everywhere + +The --utc option was introduced by commit +9fd290443f5f99fca0dcd4216b1de70f7d3b8db1. +Howerver, the implementation was incomplete. +--- + src/journal/journalctl.c | 14 +++++++------- + src/shared/logs-show.c | 2 +- + src/shared/time-util.c | 19 +++++++++++++++---- + src/shared/time-util.h | 3 ++- + 4 files changed, 25 insertions(+), 13 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 395f85c9ae..816934ee6b 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -890,8 +890,8 @@ static int list_boots(sd_journal *j) { + printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n", + w, i - count + 1, + SD_ID128_FORMAT_VAL(id->id), +- format_timestamp(a, sizeof(a), id->first), +- format_timestamp(b, sizeof(b), id->last)); ++ format_timestamp_internal(a, sizeof(a), id->first, arg_utc), ++ format_timestamp_internal(b, sizeof(b), id->last, arg_utc)); + } + + return 0; +@@ -1502,8 +1502,8 @@ static int verify(sd_journal *j) { + if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) { + if (validated > 0) { + log_info("=> Validated from %s to %s, final %s entries not sealed.", +- format_timestamp(a, sizeof(a), first), +- format_timestamp(b, sizeof(b), validated), ++ format_timestamp_internal(a, sizeof(a), first, arg_utc), ++ format_timestamp_internal(b, sizeof(b), validated, arg_utc), + format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0)); + } else if (last > 0) + log_info("=> No sealing yet, %s of entries not sealed.", +@@ -1898,11 +1898,11 @@ int main(int argc, char *argv[]) { + if (r > 0) { + if (arg_follow) + printf("-- Logs begin at %s. --\n", +- format_timestamp(start_buf, sizeof(start_buf), start)); ++ format_timestamp_internal(start_buf, sizeof(start_buf), start, arg_utc)); + else + printf("-- Logs begin at %s, end at %s. --\n", +- format_timestamp(start_buf, sizeof(start_buf), start), +- format_timestamp(end_buf, sizeof(end_buf), end)); ++ format_timestamp_internal(start_buf, sizeof(start_buf), start, arg_utc), ++ format_timestamp_internal(end_buf, sizeof(end_buf), end, arg_utc)); + } + } + +diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c +index d5d9d090b5..e30e6865ac 100644 +--- a/src/shared/logs-show.c ++++ b/src/shared/logs-show.c +@@ -447,7 +447,7 @@ static int output_verbose( + } + + fprintf(f, "%s [%s]\n", +- format_timestamp_us(ts, sizeof(ts), realtime), ++ format_timestamp_us(ts, sizeof(ts), realtime, flags & OUTPUT_UTC), + cursor); + + JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) { +diff --git a/src/shared/time-util.c b/src/shared/time-util.c +index 066ef973ac..09f4a21354 100644 +--- a/src/shared/time-util.c ++++ b/src/shared/time-util.c +@@ -152,7 +152,7 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) { + return tv; + } + +-char *format_timestamp(char *buf, size_t l, usec_t t) { ++char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) { + struct tm tm; + time_t sec; + +@@ -164,13 +164,21 @@ char *format_timestamp(char *buf, size_t l, usec_t t) { + + sec = (time_t) (t / USEC_PER_SEC); + +- if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0) ++ if (utc) ++ gmtime_r(&sec, &tm); ++ else ++ localtime_r(&sec, &tm); ++ if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) + return NULL; + + return buf; + } + +-char *format_timestamp_us(char *buf, size_t l, usec_t t) { ++char *format_timestamp(char *buf, size_t l, usec_t t) { ++ return format_timestamp_internal(buf, l, t, false); ++} ++ ++char *format_timestamp_us(char *buf, size_t l, usec_t t, bool utc) { + struct tm tm; + time_t sec; + +@@ -181,7 +189,10 @@ char *format_timestamp_us(char *buf, size_t l, usec_t t) { + return NULL; + + sec = (time_t) (t / USEC_PER_SEC); +- localtime_r(&sec, &tm); ++ if (utc) ++ gmtime_r(&sec, &tm); ++ else ++ localtime_r(&sec, &tm); + + if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) + return NULL; +diff --git a/src/shared/time-util.h b/src/shared/time-util.h +index 8ba1cfee8e..16cc593cf5 100644 +--- a/src/shared/time-util.h ++++ b/src/shared/time-util.h +@@ -84,8 +84,9 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u); + usec_t timeval_load(const struct timeval *tv) _pure_; + struct timeval *timeval_store(struct timeval *tv, usec_t u); + ++char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc); + char *format_timestamp(char *buf, size_t l, usec_t t); +-char *format_timestamp_us(char *buf, size_t l, usec_t t); ++char *format_timestamp_us(char *buf, size_t l, usec_t t, bool utc); + char *format_timestamp_relative(char *buf, size_t l, usec_t t); + char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); + diff --git a/0475-fileio-label-return-error-when-writing-fails.patch b/0475-fileio-label-return-error-when-writing-fails.patch new file mode 100644 index 0000000..0292855 --- /dev/null +++ b/0475-fileio-label-return-error-when-writing-fails.patch @@ -0,0 +1,32 @@ +From 754fc0c720eb998b8e47e695c12807ced0ff3602 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 08:58:40 -0400 +Subject: [PATCH] fileio-label: return error when writing fails + +The status of actually writing the file was totally ignored. +--- + src/shared/fileio-label.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/fileio-label.c b/src/shared/fileio-label.c +index c3def3c568..d5ce24c0d9 100644 +--- a/src/shared/fileio-label.c ++++ b/src/shared/fileio-label.c +@@ -34,7 +34,7 @@ int write_string_file_atomic_label(const char *fn, const char *line) { + if (r < 0) + return r; + +- write_string_file_atomic(fn, line); ++ r = write_string_file_atomic(fn, line); + + label_context_clear(); + +@@ -48,7 +48,7 @@ int write_env_file_label(const char *fname, char **l) { + if (r < 0) + return r; + +- write_env_file(fname, l); ++ r = write_env_file(fname, l); + + label_context_clear(); + diff --git a/0476-terminal-fix-back-buffer-selection-on-DRM-page-flip.patch b/0476-terminal-fix-back-buffer-selection-on-DRM-page-flip.patch new file mode 100644 index 0000000..5aeffc8 --- /dev/null +++ b/0476-terminal-fix-back-buffer-selection-on-DRM-page-flip.patch @@ -0,0 +1,38 @@ +From db1a606610e5a528903a4380f30c9934a0c5a134 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 13:11:53 +0200 +Subject: [PATCH] terminal: fix back-buffer selection on DRM page-flip + +We currently select front-buffers as new back-buffer if they happen to be +the last buffer in our framebuffer-array. Fix this by never selecting a +new front buffer as back buffer. +--- + src/libsystemd-terminal/grdev-drm.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 5393ebf988..7a6e1d993b 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -1362,10 +1362,9 @@ static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct + fb = fb_from_base(pipe->base.fbs[i]); + if (counter != 0 && counter == pipe->counter && fb->flipid == counter) { + pipe->base.front = &fb->base; ++ fb->flipid = 0; + flipped = true; +- } +- +- if (counter - fb->flipid < UINT16_MAX) { ++ } else if (counter - fb->flipid < UINT16_MAX) { + fb->flipid = 0; + back = fb; + } else if (fb->flipid == 0) { +@@ -1373,7 +1372,7 @@ static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct + } + } + +- if (!pipe->base.back) ++ if (!pipe->base.back && back) + pipe->base.back = &back->base; + + if (flipped) { diff --git a/0477-terminal-make-utf8-decoder-return-length.patch b/0477-terminal-make-utf8-decoder-return-length.patch new file mode 100644 index 0000000..56b7a97 --- /dev/null +++ b/0477-terminal-make-utf8-decoder-return-length.patch @@ -0,0 +1,217 @@ +From f1f5b2a3bdc3178d57c4088a7cd7758afaeba9cb Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 16:36:09 +0200 +Subject: [PATCH] terminal: make utf8 decoder return length + +Lets return the parsed length in term_utf8_decode() instead of a buffer +pointer. Store the pointer in the passed argument. + +This makes it adhere to the systemd coding-style, were we always avoid +returning pointers, but store them in output arguments. In this case, the +storage is not allocated, so it doesn't fit 100% to this idiom, but still +looks much nicer. +--- + src/libsystemd-terminal/subterm.c | 4 +-- + src/libsystemd-terminal/term-parser.c | 24 ++++++++------- + src/libsystemd-terminal/term-screen.c | 4 +-- + src/libsystemd-terminal/term.h | 2 +- + src/libsystemd-terminal/test-term-parser.c | 49 +++++++++++++++--------------- + 5 files changed, 43 insertions(+), 40 deletions(-) + +diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c +index 3990fb392b..adc4caa42e 100644 +--- a/src/libsystemd-terminal/subterm.c ++++ b/src/libsystemd-terminal/subterm.c +@@ -716,10 +716,10 @@ static int terminal_io_fn(sd_event_source *source, int fd, uint32_t revents, voi + + for (i = 0; i < len; ++i) { + const term_seq *seq; +- const uint32_t *str; ++ uint32_t *str; + size_t n_str, j; + +- str = term_utf8_decode(&t->utf8, &n_str, buf[i]); ++ n_str = term_utf8_decode(&t->utf8, &str, buf[i]); + for (j = 0; j < n_str; ++j) { + type = term_parser_feed(t->parser, &seq, str[j]); + if (type < 0) { +diff --git a/src/libsystemd-terminal/term-parser.c b/src/libsystemd-terminal/term-parser.c +index c8c1d13d2e..f9326d563a 100644 +--- a/src/libsystemd-terminal/term-parser.c ++++ b/src/libsystemd-terminal/term-parser.c +@@ -81,15 +81,16 @@ size_t term_utf8_encode(char *out_utf8, uint32_t g) { + /** + * term_utf8_decode() - Try decoding the next UCS-4 character + * @p: decoder object to operate on or NULL +- * @out_len: output buffer for length of decoded UCS-4 string or NULL ++ * @out_len: output storage for pointer to decoded UCS-4 string or NULL + * @c: next char to push into decoder + * + * This decodes a UTF-8 stream. It must be called for each input-byte of the +- * UTF-8 stream and returns a UCS-4 stream. The length of the returned UCS-4 +- * string (number of parsed characters) is stored in @out_len if non-NULL. A +- * pointer to the string is returned (or NULL if none was parsed). The string +- * is not zero-terminated! Furthermore, the string is only valid until the next +- * invokation of this function. It is also bound to the parser-state @p. ++ * UTF-8 stream and returns a UCS-4 stream. A pointer to the parsed UCS-4 ++ * string is stored in @out_buf if non-NULL. The length of this string (number ++ * of parsed UCS4 characters) is returned as result. The string is not ++ * zero-terminated! Furthermore, the string is only valid until the next ++ * invocation of this function. It is also bound to the parser state @p and ++ * must not be freed nor written to by the caller. + * + * This function is highly optimized to work with terminal-emulators. Instead + * of being strict about UTF-8 validity, this tries to perform a fallback to +@@ -100,9 +101,10 @@ size_t term_utf8_encode(char *out_utf8, uint32_t g) { + * no helpers to do that for you. To initialize it, simply reset it to all + * zero. You can reset or free the object at any point in time. + * +- * Returns: Pointer to the UCS-4 string or NULL. ++ * Returns: Number of parsed UCS4 characters + */ +-const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) { ++size_t term_utf8_decode(term_utf8 *p, uint32_t **out_buf, char c) { ++ static uint32_t ucs4_null = 0; + uint32_t t, *res = NULL; + uint8_t byte; + size_t len = 0; +@@ -246,9 +248,9 @@ const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) { + p->n_bytes = 0; + + out: +- if (out_len) +- *out_len = len; +- return len > 0 ? res : NULL; ++ if (out_buf) ++ *out_buf = res ? : &ucs4_null; ++ return len; + } + + /* +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 14c32aceb9..2f3f6f91cb 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -3756,7 +3756,7 @@ unsigned int term_screen_get_height(term_screen *screen) { + } + + int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) { +- const uint32_t *ucs4_str; ++ uint32_t *ucs4_str; + size_t i, j, ucs4_len; + const term_seq *seq; + int r; +@@ -3768,7 +3768,7 @@ int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) { + * 8bit mode if the stream is not valid UTF-8. This should be more than + * enough to support old 7bit/8bit modes. */ + for (i = 0; i < size; ++i) { +- ucs4_str = term_utf8_decode(&screen->utf8, &ucs4_len, in[i]); ++ ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]); + for (j = 0; j < ucs4_len; ++j) { + r = term_parser_feed(screen->parser, &seq, ucs4_str[j]); + if (r < 0) { +diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h +index 021cf1c42b..d5b934fc59 100644 +--- a/src/libsystemd-terminal/term.h ++++ b/src/libsystemd-terminal/term.h +@@ -111,7 +111,7 @@ struct term_utf8 { + }; + + size_t term_utf8_encode(char *out_utf8, uint32_t g); +-const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c); ++size_t term_utf8_decode(term_utf8 *p, uint32_t **out_buf, char c); + + /* + * Parsers +diff --git a/src/libsystemd-terminal/test-term-parser.c b/src/libsystemd-terminal/test-term-parser.c +index ed16f5f276..e8d5dcfbf2 100644 +--- a/src/libsystemd-terminal/test-term-parser.c ++++ b/src/libsystemd-terminal/test-term-parser.c +@@ -33,39 +33,40 @@ + + static void test_term_utf8_invalid(void) { + term_utf8 p = { }; +- const uint32_t *res; ++ uint32_t *res; + size_t len; + +- res = term_utf8_decode(NULL, NULL, 0); +- assert_se(res == NULL); ++ len = term_utf8_decode(NULL, NULL, 0); ++ assert_se(!len); + +- res = term_utf8_decode(&p, NULL, 0); +- assert_se(res != NULL); +- +- len = 5; +- res = term_utf8_decode(NULL, &len, 0); +- assert_se(res == NULL); +- assert_se(len == 0); ++ len = term_utf8_decode(&p, NULL, 0); ++ assert_se(len == 1); + +- len = 5; +- res = term_utf8_decode(&p, &len, 0); ++ res = NULL; ++ len = term_utf8_decode(NULL, &res, 0); ++ assert_se(!len); + assert_se(res != NULL); ++ assert_se(!*res); ++ ++ len = term_utf8_decode(&p, &res, 0); + assert_se(len == 1); ++ assert_se(res != NULL); ++ assert_se(!*res); + +- len = 5; +- res = term_utf8_decode(&p, &len, 0xCf); +- assert_se(res == NULL); ++ len = term_utf8_decode(&p, &res, 0xCf); + assert_se(len == 0); +- +- len = 5; +- res = term_utf8_decode(&p, &len, 0x0); + assert_se(res != NULL); ++ assert_se(!*res); ++ ++ len = term_utf8_decode(&p, &res, 0); + assert_se(len == 2); ++ assert_se(res != NULL); ++ assert_se(res[0] == 0xCf && res[1] == 0); + } + + static void test_term_utf8_range(void) { + term_utf8 p = { }; +- const uint32_t *res; ++ uint32_t *res; + char u8[4]; + uint32_t i, j; + size_t ulen, len; +@@ -78,8 +79,8 @@ static void test_term_utf8_range(void) { + continue; + + for (j = 0; j < ulen; ++j) { +- res = term_utf8_decode(&p, &len, u8[j]); +- if (!res) { ++ len = term_utf8_decode(&p, &res, u8[j]); ++ if (len < 1) { + assert_se(j + 1 != ulen); + continue; + } +@@ -117,13 +118,13 @@ static void test_term_utf8_mix(void) { + 0x00F0, 0x0080, 0x0080, 0x0001, + }; + term_utf8 p = { }; +- const uint32_t *res; ++ uint32_t *res; + unsigned int i, j; + size_t len; + + for (i = 0, j = 0; i < sizeof(source); ++i) { +- res = term_utf8_decode(&p, &len, source[i]); +- if (!res) ++ len = term_utf8_decode(&p, &res, source[i]); ++ if (len < 1) + continue; + + assert_se(j + len <= ELEMENTSOF(result)); diff --git a/0478-terminal-grdev-simplify-DRM-event-parsing.patch b/0478-terminal-grdev-simplify-DRM-event-parsing.patch new file mode 100644 index 0000000..fa4d05c --- /dev/null +++ b/0478-terminal-grdev-simplify-DRM-event-parsing.patch @@ -0,0 +1,45 @@ +From 6a15ce2b3eb852023d77787f96c6a4a72eb4d60d Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 17:09:05 +0200 +Subject: [PATCH] terminal/grdev: simplify DRM event parsing + +Coverity complained about this code and is partially right. We are not +really protected against integer overflows. Sure, unlikely, but lets just +avoid any overflows and properly protect our parser loop. +--- + src/libsystemd-terminal/grdev-drm.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 7a6e1d993b..6b130116d7 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -2195,7 +2195,8 @@ static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void * + uint32_t id, counter; + grdrm_object *object; + char buf[4096]; +- ssize_t l, i; ++ size_t len; ++ ssize_t l; + + if (revents & (EPOLLHUP | EPOLLERR)) { + /* Immediately close device on HUP; no need to flush pending +@@ -2214,15 +2215,12 @@ static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void * + log_debug("grdrm: %s/%s: read error: %m", card->base.session->name, card->base.name); + grdrm_card_close(card); + return 0; +- } else if ((size_t)l < sizeof(*event)) { +- log_debug("grdrm: %s/%s: short read of %zd bytes", card->base.session->name, card->base.name, l); +- return 0; + } + +- for (i = 0; i < l; i += event->length) { +- event = (void*)&buf[i]; ++ for (len = l; len > 0; len -= event->length) { ++ event = (void*)buf; + +- if (i + (ssize_t)sizeof(*event) > l || i + (ssize_t)event->length > l) { ++ if (len < sizeof(*event) || len < event->length) { + log_debug("grdrm: %s/%s: truncated event", card->base.session->name, card->base.name); + break; + } diff --git a/0479-terminal-drm-provide-pipe-target-callback.patch b/0479-terminal-drm-provide-pipe-target-callback.patch new file mode 100644 index 0000000..a5e4885 --- /dev/null +++ b/0479-terminal-drm-provide-pipe-target-callback.patch @@ -0,0 +1,236 @@ +From aec3f44651998211d559b474bb830aad65680a62 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 17:59:26 +0200 +Subject: [PATCH] terminal/drm: provide pipe->target() callback + +Instead of looking for available back-buffers on each operation, set it to +NULL and wait for the next frame request. It will call back into the pipe +to request the back-buffer via ->target(), where we can do the same and +look for an available backbuffer. + +This simplifies the code and avoids double lookups if we run short of +buffers. +--- + src/libsystemd-terminal/grdev-drm.c | 98 ++++++++++++++++--------------------- + src/libsystemd-terminal/grdev.c | 2 + + 2 files changed, 44 insertions(+), 56 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 6b130116d7..57b930bc0f 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -1095,19 +1095,19 @@ static void grdrm_crtc_expose(grdrm_crtc *crtc) { + grdev_pipe_ready(&crtc->pipe->base, true); + } + +-static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) { ++static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb *basefb) { + struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id }; + grdrm_card *card = crtc->object.card; + grdrm_pipe *pipe = crtc->pipe; +- grdrm_fb *fb = fb_from_base(*slot); +- size_t i; ++ grdrm_fb *fb; + int r; + + assert(crtc); +- assert(slot); +- assert(*slot); ++ assert(basefb); + assert(pipe); + ++ fb = fb_from_base(basefb); ++ + set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->set.connectors); + set_crtc.count_connectors = crtc->set.n_connectors; + set_crtc.fb_id = fb->id; +@@ -1132,7 +1132,7 @@ static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) { + crtc->applied = true; + } + +- *slot = NULL; ++ pipe->base.back = NULL; + pipe->base.front = &fb->base; + fb->flipid = 0; + ++pipe->counter; +@@ -1144,40 +1144,25 @@ static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb **slot) { + * To avoid duplicating that everywhere, we schedule our own + * timer and raise a fake FRAME event when it fires. */ + grdev_pipe_schedule(&pipe->base, 1); +- +- if (!pipe->base.back) { +- for (i = 0; i < pipe->base.max_fbs; ++i) { +- if (!pipe->base.fbs[i]) +- continue; +- +- fb = fb_from_base(pipe->base.fbs[i]); +- if (&fb->base == pipe->base.front) +- continue; +- +- fb->flipid = 0; +- pipe->base.back = &fb->base; +- break; +- } +- } + } + +-static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) { ++static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb *basefb) { + struct drm_mode_crtc_page_flip page_flip = { .crtc_id = crtc->object.id }; + grdrm_card *card = crtc->object.card; + grdrm_pipe *pipe = crtc->pipe; +- grdrm_fb *fb = fb_from_base(*slot); ++ grdrm_fb *fb; + uint32_t cnt; +- size_t i; + int r; + + assert(crtc); +- assert(slot); +- assert(*slot); ++ assert(basefb); + assert(pipe); + + if (!crtc->applied && !grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode)) + return 0; + ++ fb = fb_from_base(basefb); ++ + cnt = ++pipe->counter ? : ++pipe->counter; + page_flip.fb_id = fb->id; + page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT; +@@ -1209,29 +1194,13 @@ static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb **slot) { + pipe->base.flip = false; + pipe->counter = cnt; + fb->flipid = cnt; +- *slot = NULL; ++ pipe->base.back = NULL; + + /* Raise fake FRAME event if it takes longer than 2 + * frames to receive the pageflip event. We assume the + * queue ran over or some other error happened. */ + grdev_pipe_schedule(&pipe->base, 2); + +- if (!pipe->base.back) { +- for (i = 0; i < pipe->base.max_fbs; ++i) { +- if (!pipe->base.fbs[i]) +- continue; +- +- fb = fb_from_base(pipe->base.fbs[i]); +- if (&fb->base == pipe->base.front) +- continue; +- if (fb->flipid) +- continue; +- +- pipe->base.back = &fb->base; +- break; +- } +- } +- + return 1; + } + +@@ -1239,7 +1208,7 @@ static void grdrm_crtc_commit(grdrm_crtc *crtc) { + struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id }; + grdrm_card *card = crtc->object.card; + grdrm_pipe *pipe; +- grdev_fb **slot; ++ grdev_fb *fb; + int r; + + assert(crtc); +@@ -1280,19 +1249,19 @@ static void grdrm_crtc_commit(grdrm_crtc *crtc) { + assert(crtc->set.n_connectors > 0); + + if (pipe->base.flip) +- slot = &pipe->base.back; ++ fb = pipe->base.back; + else if (!crtc->applied) +- slot = &pipe->base.front; ++ fb = pipe->base.front; + else + return; + +- if (!*slot) ++ if (!fb) + return; + +- r = grdrm_crtc_commit_flip(crtc, slot); ++ r = grdrm_crtc_commit_flip(crtc, fb); + if (r == 0) { + /* in case we couldn't page-flip, perform deep modeset */ +- grdrm_crtc_commit_deep(crtc, slot); ++ grdrm_crtc_commit_deep(crtc, fb); + } + } + +@@ -1335,7 +1304,6 @@ static void grdrm_crtc_restore(grdrm_crtc *crtc) { + static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct drm_event_vblank *event) { + bool flipped = false; + grdrm_pipe *pipe; +- grdrm_fb *back = NULL; + size_t i; + + assert(crtc); +@@ -1366,15 +1334,9 @@ static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct + flipped = true; + } else if (counter - fb->flipid < UINT16_MAX) { + fb->flipid = 0; +- back = fb; +- } else if (fb->flipid == 0) { +- back = fb; + } + } + +- if (!pipe->base.back && back) +- pipe->base.back = &back->base; +- + if (flipped) { + crtc->pipe->base.flipping = false; + grdev_pipe_frame(&pipe->base); +@@ -1561,8 +1523,32 @@ static void grdrm_pipe_free(grdev_pipe *basepipe) { + free(pipe); + } + ++static grdev_fb *grdrm_pipe_target(grdev_pipe *basepipe) { ++ grdrm_fb *fb; ++ size_t i; ++ ++ if (!basepipe->back) { ++ for (i = 0; i < basepipe->max_fbs; ++i) { ++ if (!basepipe->fbs[i]) ++ continue; ++ ++ fb = fb_from_base(basepipe->fbs[i]); ++ if (&fb->base == basepipe->front) ++ continue; ++ if (basepipe->flipping && fb->flipid) ++ continue; ++ ++ basepipe->back = &fb->base; ++ break; ++ } ++ } ++ ++ return basepipe->back; ++} ++ + static const grdev_pipe_vtable grdrm_pipe_vtable = { + .free = grdrm_pipe_free, ++ .target = grdrm_pipe_target, + }; + + /* +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index aaac06ec34..bbc45afad4 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -382,6 +382,8 @@ const grdev_display_target *grdev_display_next_target(grdev_display *display, co + if (!(fb = pipe->back)) { + if (!pipe->vtable->target || !(fb = pipe->vtable->target(pipe))) + continue; ++ ++ assert(fb == pipe->back); + } + + /* if back-buffer is up-to-date, schedule flip */ diff --git a/0480-terminal-grdev-provide-front-and-back-buffer-to-rend.patch b/0480-terminal-grdev-provide-front-and-back-buffer-to-rend.patch new file mode 100644 index 0000000..460b8fe --- /dev/null +++ b/0480-terminal-grdev-provide-front-and-back-buffer-to-rend.patch @@ -0,0 +1,152 @@ +From 51cff8bdedbc283b2403ab4a688903d8b1f2fab5 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 18:26:06 +0200 +Subject: [PATCH] terminal/grdev: provide front and back buffer to renderers + +We really want more sophisticated aging than just 64bit integers. So +always provide front *and* back buffers to renderers so they can compare +arbitrary aging information and decide whether to re-render. +--- + src/libsystemd-terminal/grdev.c | 27 ++++++++++----------------- + src/libsystemd-terminal/grdev.h | 13 +++++++------ + src/libsystemd-terminal/modeset.c | 8 ++++---- + 3 files changed, 21 insertions(+), 27 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index bbc45afad4..a700a7316b 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -343,7 +343,7 @@ void grdev_display_disable(grdev_display *display) { + } + } + +-const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev, uint64_t minage) { ++const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev) { + grdev_display_cache *cache; + size_t idx; + +@@ -374,26 +374,19 @@ const grdev_display_target *grdev_display_next_target(grdev_display *display, co + if (!pipe->running || !pipe->enabled) + continue; + +- /* if front-buffer is up-to-date, there's nothing to do */ +- if (minage > 0 && pipe->front && pipe->front->age >= minage) +- continue; +- + /* find suitable back-buffer */ +- if (!(fb = pipe->back)) { +- if (!pipe->vtable->target || !(fb = pipe->vtable->target(pipe))) ++ if (!pipe->back) { ++ if (!pipe->vtable->target) ++ continue; ++ if (!(fb = pipe->vtable->target(pipe))) + continue; + + assert(fb == pipe->back); + } + +- /* if back-buffer is up-to-date, schedule flip */ +- if (minage > 0 && fb->age >= minage) { +- grdev_display_flip_target(display, target, fb->age); +- continue; +- } ++ target->front = pipe->front; ++ target->back = pipe->back; + +- /* we have an out-of-date back-buffer; return for redraw */ +- target->fb = fb; + return target; + } + +@@ -408,7 +401,7 @@ void grdev_display_flip_target(grdev_display *display, const grdev_display_targe + assert(!display->modified); + assert(display->enabled); + assert(target); +- assert(target->fb); ++ assert(target->back); + + cache = container_of(target, grdev_display_cache, target); + +@@ -416,12 +409,12 @@ void grdev_display_flip_target(grdev_display *display, const grdev_display_targe + assert(cache->pipe->tile->display == display); + + /* reset age of all FB on overflow */ +- if (age < target->fb->age) ++ if (age < target->back->age) + for (i = 0; i < cache->pipe->max_fbs; ++i) + if (cache->pipe->fbs[i]) + cache->pipe->fbs[i]->age = 0; + +- ((grdev_fb*)target->fb)->age = age; ++ ((grdev_fb*)target->back)->age = age; + cache->pipe->flip = true; + } + +diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h +index 6ca8a767c4..ca0373ed29 100644 +--- a/src/libsystemd-terminal/grdev.h ++++ b/src/libsystemd-terminal/grdev.h +@@ -105,7 +105,8 @@ struct grdev_display_target { + uint32_t height; + unsigned int rotate; + unsigned int flip; +- const grdev_fb *fb; ++ const grdev_fb *front; ++ const grdev_fb *back; + }; + + void grdev_display_set_userdata(grdev_display *display, void *userdata); +@@ -119,13 +120,13 @@ bool grdev_display_is_enabled(grdev_display *display); + void grdev_display_enable(grdev_display *display); + void grdev_display_disable(grdev_display *display); + +-const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev, uint64_t minage); ++const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev); + void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target, uint64_t age); + +-#define GRDEV_DISPLAY_FOREACH_TARGET(_display, _t, _minage) \ +- for ((_t) = grdev_display_next_target((_display), NULL, (_minage)); \ +- (_t); \ +- (_t) = grdev_display_next_target((_display), (_t), (_minage))) ++#define GRDEV_DISPLAY_FOREACH_TARGET(_display, _t) \ ++ for ((_t) = grdev_display_next_target((_display), NULL); \ ++ (_t); \ ++ (_t) = grdev_display_next_target((_display), (_t))) + + /* + * Events +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +index f564fa0f65..2f8860dd5f 100644 +--- a/src/libsystemd-terminal/modeset.c ++++ b/src/libsystemd-terminal/modeset.c +@@ -234,18 +234,18 @@ static void modeset_draw(Modeset *m, const grdev_display_target *t) { + uint32_t j, k, *b; + uint8_t *l; + +- assert(t->fb->format == DRM_FORMAT_XRGB8888 || t->fb->format == DRM_FORMAT_ARGB8888); ++ assert(t->back->format == DRM_FORMAT_XRGB8888 || t->back->format == DRM_FORMAT_ARGB8888); + assert(!t->rotate); + assert(!t->flip); + +- l = t->fb->maps[0]; ++ l = t->back->maps[0]; + for (j = 0; j < t->height; ++j) { + for (k = 0; k < t->width; ++k) { + b = (uint32_t*)l; + b[k] = (0xff << 24) | (m->r << 16) | (m->g << 8) | m->b; + } + +- l += t->fb->strides[0]; ++ l += t->back->strides[0]; + } + } + +@@ -256,7 +256,7 @@ static void modeset_render(Modeset *m, grdev_display *d) { + m->g = next_color(&m->g_up, m->g, 3); + m->b = next_color(&m->b_up, m->b, 2); + +- GRDEV_DISPLAY_FOREACH_TARGET(d, t, 0) { ++ GRDEV_DISPLAY_FOREACH_TARGET(d, t) { + modeset_draw(m, t); + grdev_display_flip_target(d, t, 1); + } diff --git a/0481-terminal-grdev-allow-arbitrary-fb-age-contexts.patch b/0481-terminal-grdev-allow-arbitrary-fb-age-contexts.patch new file mode 100644 index 0000000..509dc2c --- /dev/null +++ b/0481-terminal-grdev-allow-arbitrary-fb-age-contexts.patch @@ -0,0 +1,117 @@ +From 66695cc343647dcbf654fbb4b3f38bd1ee092a0d Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 18:47:01 +0200 +Subject: [PATCH] terminal/grdev: allow arbitrary fb-age contexts + +Instead of limiting fb-aging to 64bit integers, allow any arbitrary +context together with a release function to free it once the FB is +destroyed. +--- + src/libsystemd-terminal/grdev-drm.c | 3 +++ + src/libsystemd-terminal/grdev.c | 11 +---------- + src/libsystemd-terminal/grdev.h | 14 ++++++++++---- + src/libsystemd-terminal/modeset.c | 2 +- + 4 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index 57b930bc0f..f01df1dae2 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -1442,6 +1442,9 @@ grdrm_fb *grdrm_fb_free(grdrm_fb *fb) { + + assert(fb->card); + ++ if (fb->base.free_fn) ++ fb->base.free_fn(fb->base.data.ptr); ++ + if (fb->id > 0 && fb->card->fd >= 0) { + r = ioctl(fb->card->fd, DRM_IOCTL_MODE_RMFB, fb->id); + if (r < 0) +diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c +index a700a7316b..0c21eac551 100644 +--- a/src/libsystemd-terminal/grdev.c ++++ b/src/libsystemd-terminal/grdev.c +@@ -393,28 +393,19 @@ const grdev_display_target *grdev_display_next_target(grdev_display *display, co + return NULL; + } + +-void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target, uint64_t age) { ++void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target) { + grdev_display_cache *cache; +- size_t i; + + assert(display); + assert(!display->modified); + assert(display->enabled); + assert(target); +- assert(target->back); + + cache = container_of(target, grdev_display_cache, target); + + assert(cache->pipe); + assert(cache->pipe->tile->display == display); + +- /* reset age of all FB on overflow */ +- if (age < target->back->age) +- for (i = 0; i < cache->pipe->max_fbs; ++i) +- if (cache->pipe->fbs[i]) +- cache->pipe->fbs[i]->age = 0; +- +- ((grdev_fb*)target->back)->age = age; + cache->pipe->flip = true; + } + +diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h +index ca0373ed29..35d6eb2abf 100644 +--- a/src/libsystemd-terminal/grdev.h ++++ b/src/libsystemd-terminal/grdev.h +@@ -93,9 +93,15 @@ struct grdev_fb { + uint32_t width; + uint32_t height; + uint32_t format; +- uint64_t age; + int32_t strides[4]; + void *maps[4]; ++ ++ union { ++ void *ptr; ++ uint64_t u64; ++ } data; ++ ++ void (*free_fn) (void *ptr); + }; + + struct grdev_display_target { +@@ -105,8 +111,8 @@ struct grdev_display_target { + uint32_t height; + unsigned int rotate; + unsigned int flip; +- const grdev_fb *front; +- const grdev_fb *back; ++ grdev_fb *front; ++ grdev_fb *back; + }; + + void grdev_display_set_userdata(grdev_display *display, void *userdata); +@@ -121,7 +127,7 @@ void grdev_display_enable(grdev_display *display); + void grdev_display_disable(grdev_display *display); + + const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev); +-void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target, uint64_t age); ++void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target); + + #define GRDEV_DISPLAY_FOREACH_TARGET(_display, _t) \ + for ((_t) = grdev_display_next_target((_display), NULL); \ +diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c +index 2f8860dd5f..f5be38e4fa 100644 +--- a/src/libsystemd-terminal/modeset.c ++++ b/src/libsystemd-terminal/modeset.c +@@ -258,7 +258,7 @@ static void modeset_render(Modeset *m, grdev_display *d) { + + GRDEV_DISPLAY_FOREACH_TARGET(d, t) { + modeset_draw(m, t); +- grdev_display_flip_target(d, t, 1); ++ grdev_display_flip_target(d, t); + } + + grdev_session_commit(m->grdev_session); diff --git a/0482-terminal-drm-clear-applied-flag-when-changing-state.patch b/0482-terminal-drm-clear-applied-flag-when-changing-state.patch new file mode 100644 index 0000000..8977317 --- /dev/null +++ b/0482-terminal-drm-clear-applied-flag-when-changing-state.patch @@ -0,0 +1,40 @@ +From 1bfa594cf26a9880c489cdcb5911bfb3440aa566 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 18:51:29 +0200 +Subject: [PATCH] terminal/drm: clear 'applied' flag when changing state + +If a pipe is enabled/disabled, we have to clear crtc->applied of the +linked CRTC. Otherwise, we will not run a deep modeset, but leave the crtc +in the pre-configured state. +--- + src/libsystemd-terminal/grdev-drm.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c +index f01df1dae2..232321c0e2 100644 +--- a/src/libsystemd-terminal/grdev-drm.c ++++ b/src/libsystemd-terminal/grdev-drm.c +@@ -1549,9 +1549,23 @@ static grdev_fb *grdrm_pipe_target(grdev_pipe *basepipe) { + return basepipe->back; + } + ++static void grdrm_pipe_enable(grdev_pipe *basepipe) { ++ grdrm_pipe *pipe = grdrm_pipe_from_base(basepipe); ++ ++ pipe->crtc->applied = false; ++} ++ ++static void grdrm_pipe_disable(grdev_pipe *basepipe) { ++ grdrm_pipe *pipe = grdrm_pipe_from_base(basepipe); ++ ++ pipe->crtc->applied = false; ++} ++ + static const grdev_pipe_vtable grdrm_pipe_vtable = { + .free = grdrm_pipe_free, + .target = grdrm_pipe_target, ++ .enable = grdrm_pipe_enable, ++ .disable = grdrm_pipe_disable, + }; + + /* diff --git a/0483-terminal-add-screen-renderer.patch b/0483-terminal-add-screen-renderer.patch new file mode 100644 index 0000000..9501c56 --- /dev/null +++ b/0483-terminal-add-screen-renderer.patch @@ -0,0 +1,107 @@ +From be5022138495d2e509735dec7486a040d3e2eb2d Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 19:31:43 +0200 +Subject: [PATCH] terminal: add screen renderer + +We don't want to expose the term_screen internals for rendering. +Therefore, provide an iterator that allows external renderers to draw +terminals. +--- + src/libsystemd-terminal/term-screen.c | 66 +++++++++++++++++++++++++++++++++++ + src/libsystemd-terminal/term.h | 12 +++++++ + 2 files changed, 78 insertions(+) + +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 2f3f6f91cb..b442b96050 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -3892,3 +3892,69 @@ int term_screen_set_answerback(term_screen *screen, const char *answerback) { + + return 0; + } ++ ++int term_screen_draw(term_screen *screen, ++ int (*draw_fn) (term_screen *screen, ++ void *userdata, ++ unsigned int x, ++ unsigned int y, ++ const term_attr *attr, ++ const uint32_t *ch, ++ size_t n_ch, ++ unsigned int ch_width), ++ void *userdata, ++ uint64_t *fb_age) { ++ uint64_t cell_age, line_age, age = 0; ++ term_charbuf_t ch_buf; ++ const uint32_t *ch_str; ++ unsigned int i, j, cw; ++ term_page *page; ++ term_line *line; ++ term_cell *cell; ++ size_t ch_n; ++ int r; ++ ++ assert(screen); ++ assert(draw_fn); ++ ++ if (fb_age) ++ age = *fb_age; ++ ++ page = screen->page; ++ ++ for (j = 0; j < page->height; ++j) { ++ line = page->lines[j]; ++ line_age = MAX(line->age, page->age); ++ ++ for (i = 0; i < page->width; ++i) { ++ cell = &line->cells[i]; ++ cell_age = MAX(cell->age, line_age); ++ ++ if (age != 0 && cell_age <= age) ++ continue; ++ ++ ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf); ++ ++ /* Character-width of 0 is used for cleared cells. ++ * Always treat this as single-cell character, so ++ * renderers can assume ch_width is set properpy. */ ++ cw = MAX(cell->cwidth, 1U); ++ ++ r = draw_fn(screen, ++ userdata, ++ i, ++ j, ++ &cell->attr, ++ ch_str, ++ ch_n, ++ cw); ++ if (r != 0) ++ return r; ++ } ++ } ++ ++ if (fb_age) ++ *fb_age = screen->age++; ++ ++ return 0; ++} +diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h +index d5b934fc59..a3ca252e31 100644 +--- a/src/libsystemd-terminal/term.h ++++ b/src/libsystemd-terminal/term.h +@@ -147,3 +147,15 @@ void term_screen_soft_reset(term_screen *screen); + void term_screen_hard_reset(term_screen *screen); + + int term_screen_set_answerback(term_screen *screen, const char *answerback); ++ ++int term_screen_draw(term_screen *screen, ++ int (*draw_fn) (term_screen *screen, ++ void *userdata, ++ unsigned int x, ++ unsigned int y, ++ const term_attr *attr, ++ const uint32_t *ch, ++ size_t n_ch, ++ unsigned int ch_width), ++ void *userdata, ++ uint64_t *fb_age); diff --git a/0484-terminal-subterm-use-screen-renderer.patch b/0484-terminal-subterm-use-screen-renderer.patch new file mode 100644 index 0000000..036de20 --- /dev/null +++ b/0484-terminal-subterm-use-screen-renderer.patch @@ -0,0 +1,177 @@ +From cb51a41fa632790ea839aa126844dfc2d74eb341 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 19:34:14 +0200 +Subject: [PATCH] terminal/subterm: use screen renderer + +Don't hard-code the screen renderer but use the newly introduced +term_screen_draw() helper. +--- + src/libsystemd-terminal/subterm.c | 148 +++++++++++++++++++------------------- + 1 file changed, 76 insertions(+), 72 deletions(-) + +diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c +index adc4caa42e..563cbf0823 100644 +--- a/src/libsystemd-terminal/subterm.c ++++ b/src/libsystemd-terminal/subterm.c +@@ -392,85 +392,89 @@ static void output_draw_menu(Output *o) { + output_frame_printl(o, " ^C: send ^C to the PTY"); + } + +-static void output_draw_screen(Output *o, term_screen *s) { +- unsigned int i, j; +- bool first = true; +- +- assert(o); +- assert(s); +- +- for (j = 0; j < s->page->height && j < o->in_height; ++j) { +- if (!first) +- output_printf(o, "\e[m\r\n" BORDER_VERT); +- first = false; +- +- for (i = 0; i < s->page->width && i < o->in_width; ++i) { +- term_charbuf_t buf; +- term_cell *cell = &s->page->lines[j]->cells[i]; +- size_t k, len, ulen; +- const uint32_t *str; +- char utf8[4]; +- +- switch (cell->attr.fg.ccode) { +- case TERM_CCODE_DEFAULT: +- output_printf(o, "\e[39m"); +- break; +- case TERM_CCODE_256: +- output_printf(o, "\e[38;5;%um", cell->attr.fg.c256); +- break; +- case TERM_CCODE_RGB: +- output_printf(o, "\e[38;2;%u;%u;%um", cell->attr.fg.red, cell->attr.fg.green, cell->attr.fg.blue); +- break; +- case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: +- if (cell->attr.bold) +- output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 90); +- else +- output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 30); +- break; +- case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: +- output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_LIGHT_BLACK + 90); +- break; +- } ++static int output_draw_cell_fn(term_screen *screen, ++ void *userdata, ++ unsigned int x, ++ unsigned int y, ++ const term_attr *attr, ++ const uint32_t *ch, ++ size_t n_ch, ++ unsigned int ch_width) { ++ Output *o = userdata; ++ size_t k, ulen; ++ char utf8[4]; ++ ++ if (x >= o->in_width || y >= o->in_height) ++ return 0; + +- switch (cell->attr.bg.ccode) { +- case TERM_CCODE_DEFAULT: +- output_printf(o, "\e[49m"); +- break; +- case TERM_CCODE_256: +- output_printf(o, "\e[48;5;%um", cell->attr.bg.c256); +- break; +- case TERM_CCODE_RGB: +- output_printf(o, "\e[48;2;%u;%u;%um", cell->attr.bg.red, cell->attr.bg.green, cell->attr.bg.blue); +- break; +- case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: +- output_printf(o, "\e[%um", cell->attr.bg.ccode - TERM_CCODE_BLACK + 40); +- break; +- case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: +- output_printf(o, "\e[%um", cell->attr.bg.ccode - TERM_CCODE_LIGHT_BLACK + 100); +- break; +- } ++ if (x == 0 && y != 0) ++ output_printf(o, "\e[m\r\n" BORDER_VERT); + +- output_printf(o, "\e[%u;%u;%u;%u;%u;%um", +- cell->attr.bold ? 1 : 22, +- cell->attr.italic ? 3 : 23, +- cell->attr.underline ? 4 : 24, +- cell->attr.inverse ? 7 : 27, +- cell->attr.blink ? 5 : 25, +- cell->attr.hidden ? 8 : 28); ++ switch (attr->fg.ccode) { ++ case TERM_CCODE_DEFAULT: ++ output_printf(o, "\e[39m"); ++ break; ++ case TERM_CCODE_256: ++ output_printf(o, "\e[38;5;%um", attr->fg.c256); ++ break; ++ case TERM_CCODE_RGB: ++ output_printf(o, "\e[38;2;%u;%u;%um", attr->fg.red, attr->fg.green, attr->fg.blue); ++ break; ++ case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: ++ if (attr->bold) ++ output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_BLACK + 90); ++ else ++ output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_BLACK + 30); ++ break; ++ case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: ++ output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_LIGHT_BLACK + 90); ++ break; ++ } + +- str = term_char_resolve(cell->ch, &len, &buf); ++ switch (attr->bg.ccode) { ++ case TERM_CCODE_DEFAULT: ++ output_printf(o, "\e[49m"); ++ break; ++ case TERM_CCODE_256: ++ output_printf(o, "\e[48;5;%um", attr->bg.c256); ++ break; ++ case TERM_CCODE_RGB: ++ output_printf(o, "\e[48;2;%u;%u;%um", attr->bg.red, attr->bg.green, attr->bg.blue); ++ break; ++ case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: ++ output_printf(o, "\e[%um", attr->bg.ccode - TERM_CCODE_BLACK + 40); ++ break; ++ case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: ++ output_printf(o, "\e[%um", attr->bg.ccode - TERM_CCODE_LIGHT_BLACK + 100); ++ break; ++ } + +- if (len < 1) { +- output_printf(o, " "); +- } else { +- for (k = 0; k < len; ++k) { +- ulen = term_utf8_encode(utf8, str[k]); +- output_write(o, utf8, ulen); +- } +- } ++ output_printf(o, "\e[%u;%u;%u;%u;%u;%um", ++ attr->bold ? 1 : 22, ++ attr->italic ? 3 : 23, ++ attr->underline ? 4 : 24, ++ attr->inverse ? 7 : 27, ++ attr->blink ? 5 : 25, ++ attr->hidden ? 8 : 28); ++ ++ if (n_ch < 1) { ++ output_printf(o, " "); ++ } else { ++ for (k = 0; k < n_ch; ++k) { ++ ulen = term_utf8_encode(utf8, ch[k]); ++ output_write(o, utf8, ulen); + } + } + ++ return 0; ++} ++ ++static void output_draw_screen(Output *o, term_screen *s) { ++ assert(o); ++ assert(s); ++ ++ term_screen_draw(s, output_draw_cell_fn, o, NULL); ++ + output_move_to(o, s->cursor_x + 1, s->cursor_y + 3); + output_printf(o, "\e[m"); + } diff --git a/0485-terminal-unifont-add-built-in-fallback-glyph.patch b/0485-terminal-unifont-add-built-in-fallback-glyph.patch new file mode 100644 index 0000000..088f1fc --- /dev/null +++ b/0485-terminal-unifont-add-built-in-fallback-glyph.patch @@ -0,0 +1,49 @@ +From 61d0326a5b1c11a8f2e8e31ec9093e81daa26588 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Thu, 2 Oct 2014 19:47:21 +0200 +Subject: [PATCH] terminal/unifont: add built-in fallback glyph + +In case we cannot render a glyph, we want a fallback we can display +instead. If we rely on the font itself to provide the fallback character, +we have nothing to display if that character is not available. Therefore, +add a static fallback that we can use at any time. +--- + src/libsystemd-terminal/unifont.c | 18 ++++++++++++++++++ + src/libsystemd-terminal/unifont.h | 1 + + 2 files changed, 19 insertions(+) + +diff --git a/src/libsystemd-terminal/unifont.c b/src/libsystemd-terminal/unifont.c +index 7520015988..2acfa9821a 100644 +--- a/src/libsystemd-terminal/unifont.c ++++ b/src/libsystemd-terminal/unifont.c +@@ -221,3 +221,21 @@ int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4) { + memcpy(out, &g, sizeof(g)); + return 0; + } ++ ++void unifont_fallback(unifont_glyph *out) { ++ static const uint8_t fallback_data[] = { ++ /* unifont 0xfffd '�' (unicode replacement character) */ ++ 0x00, 0x00, 0x00, 0x7e, ++ 0x66, 0x5a, 0x5a, 0x7a, ++ 0x76, 0x76, 0x7e, 0x76, ++ 0x76, 0x7e, 0x00, 0x00, ++ }; ++ ++ assert(out); ++ ++ out->width = 8; ++ out->height = 16; ++ out->stride = 1; ++ out->cwidth = 1; ++ out->data = fallback_data; ++} +diff --git a/src/libsystemd-terminal/unifont.h b/src/libsystemd-terminal/unifont.h +index 0ded61472f..30527cb3fa 100644 +--- a/src/libsystemd-terminal/unifont.h ++++ b/src/libsystemd-terminal/unifont.h +@@ -54,3 +54,4 @@ unsigned int unifont_get_width(unifont *u); + unsigned int unifont_get_height(unifont *u); + unsigned int unifont_get_stride(unifont *u); + int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4); ++void unifont_fallback(unifont_glyph *out); diff --git a/0486-terminal-idev-don-t-map-XKB_KEY_NoSymbol-as-ASCII-0.patch b/0486-terminal-idev-don-t-map-XKB_KEY_NoSymbol-as-ASCII-0.patch new file mode 100644 index 0000000..858f115 --- /dev/null +++ b/0486-terminal-idev-don-t-map-XKB_KEY_NoSymbol-as-ASCII-0.patch @@ -0,0 +1,33 @@ +From fe741a85c1912ead26c1a78251e1d490a8a432b3 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 12:48:36 +0200 +Subject: [PATCH] terminal/idev: don't map XKB_KEY_NoSymbol as ASCII 0 + +XKB_KEY_NoSymbol is defined as 0 but does not correspond to a VT key with +ASCII value 0. No such key exists, so don't try to find such a key. +--- + src/libsystemd-terminal/idev-keyboard.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c +index d5936b7d23..8dc1c20b14 100644 +--- a/src/libsystemd-terminal/idev-keyboard.c ++++ b/src/libsystemd-terminal/idev-keyboard.c +@@ -575,7 +575,7 @@ static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_sym + const xkb_keysym_t *s; + int num; + +- if (n_syms == 1 && syms[0] < 128) ++ if (n_syms == 1 && syms[0] < 128 && syms[0] > 0) + return syms[0]; + + keymap = xkb_state_get_keymap(state); +@@ -584,7 +584,7 @@ static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_sym + for (lo = 0; lo < n_lo; ++lo) { + lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo); + num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s); +- if (num == 1 && s[0] < 128) ++ if (num == 1 && s[0] < 128 && s[0] > 0) + return s[0]; + } + diff --git a/0487-terminal-screen-add-keyboard-mapping.patch b/0487-terminal-screen-add-keyboard-mapping.patch new file mode 100644 index 0000000..bcc1858 --- /dev/null +++ b/0487-terminal-screen-add-keyboard-mapping.patch @@ -0,0 +1,400 @@ +From f8958c3495edf6d1563a5309e84bd68931a46213 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 12:50:41 +0200 +Subject: [PATCH] terminal/screen: add keyboard mapping + +Implement the feed_keyboard() handling by mapping XKB keys according to +DEC-VT behavior. + +Public information on terminal key-mappings is pretty scarce. We only +implement the most basic mapping for now. Further improvements welcome! +--- + src/libsystemd-terminal/term-screen.c | 324 +++++++++++++++++++++++++++++++++- + src/libsystemd-terminal/term.h | 22 ++- + 2 files changed, 342 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index b442b96050..5b0562e4c3 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + #include "macro.h" + #include "term-internal.h" + #include "util.h" +@@ -3784,12 +3785,329 @@ int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) { + return 0; + } + +-int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods) { ++static char *screen_map_key(term_screen *screen, ++ char *p, ++ const uint32_t *keysyms, ++ size_t n_syms, ++ uint32_t ascii, ++ const uint32_t *ucs4, ++ unsigned int mods) { ++ char ch, ch2, ch_mods; ++ uint32_t v; ++ size_t i; ++ ++ /* TODO: All these key-mappings need to be verified. Public information ++ * on those mappings is pretty scarce and every emulator seems to do it ++ * slightly differently. ++ * A lot of mappings are also missing. */ ++ ++ if (n_syms < 1) ++ return p; ++ ++ if (n_syms == 1) ++ v = keysyms[0]; ++ else ++ v = XKB_KEY_NoSymbol; ++ ++ /* In some mappings, the modifiers are encoded as CSI parameters. The ++ * encoding is rather arbitrary, but seems to work. */ ++ ch_mods = 0; ++ switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) { ++ case TERM_KBDMOD_SHIFT: ++ ch_mods = '2'; ++ break; ++ case TERM_KBDMOD_ALT: ++ ch_mods = '3'; ++ break; ++ case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT: ++ ch_mods = '4'; ++ break; ++ case TERM_KBDMOD_CTRL: ++ ch_mods = '5'; ++ break; ++ case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT: ++ ch_mods = '6'; ++ break; ++ case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT: ++ ch_mods = '7'; ++ break; ++ case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT: ++ ch_mods = '8'; ++ break; ++ } ++ ++ /* A user might actually use multiple layouts for keyboard ++ * input. @keysyms[0] contains the actual keysym that the user ++ * used. But if this keysym is not in the ascii range, the ++ * input handler does check all other layouts that the user ++ * specified whether one of them maps the key to some ASCII ++ * keysym and provides this via @ascii. We always use the real ++ * keysym except when handling CTRL+ shortcuts we use the ++ * ascii keysym. This is for compatibility to xterm et. al. so ++ * ctrl+c always works regardless of the currently active ++ * keyboard layout. But if no ascii-sym is found, we still use ++ * the real keysym. */ ++ if (ascii == XKB_KEY_NoSymbol) ++ ascii = v; ++ ++ /* map CTRL+ */ ++ if (mods & TERM_KBDMOD_CTRL) { ++ switch (ascii) { ++ case 0x60 ... 0x7e: ++ /* Right hand side is mapped to the left and then ++ * treated equally. Fall through to left-hand side.. */ ++ ascii -= 0x20; ++ case 0x20 ... 0x5f: ++ /* Printable ASCII is mapped 1-1 in XKB and in ++ * combination with CTRL bit 7 is flipped. This ++ * is equivalent to the caret-notation. */ ++ *p++ = ascii ^ 0x40; ++ return p; ++ } ++ } ++ ++ /* map cursor keys */ ++ ch = 0; ++ switch (v) { ++ case XKB_KEY_Up: ++ ch = 'A'; ++ break; ++ case XKB_KEY_Down: ++ ch = 'B'; ++ break; ++ case XKB_KEY_Right: ++ ch = 'C'; ++ break; ++ case XKB_KEY_Left: ++ ch = 'D'; ++ break; ++ case XKB_KEY_Home: ++ ch = 'H'; ++ break; ++ case XKB_KEY_End: ++ ch = 'F'; ++ break; ++ } ++ if (ch) { ++ *p++ = 0x1b; ++ if (screen->flags & TERM_FLAG_CURSOR_KEYS) ++ *p++ = 'O'; ++ else ++ *p++ = '['; ++ if (ch_mods) { ++ *p++ = '1'; ++ *p++ = ';'; ++ *p++ = ch_mods; ++ } ++ *p++ = ch; ++ return p; ++ } ++ ++ /* map action keys */ ++ ch = 0; ++ switch (v) { ++ case XKB_KEY_Find: ++ ch = '1'; ++ break; ++ case XKB_KEY_Insert: ++ ch = '2'; ++ break; ++ case XKB_KEY_Delete: ++ ch = '3'; ++ break; ++ case XKB_KEY_Select: ++ ch = '4'; ++ break; ++ case XKB_KEY_Page_Up: ++ ch = '5'; ++ break; ++ case XKB_KEY_Page_Down: ++ ch = '6'; ++ break; ++ } ++ if (ch) { ++ *p++ = 0x1b; ++ *p++ = '['; ++ *p++ = ch; ++ if (ch_mods) { ++ *p++ = ';'; ++ *p++ = ch_mods; ++ } ++ *p++ = '~'; ++ return p; ++ } ++ ++ /* map lower function keys */ ++ ch = 0; ++ switch (v) { ++ case XKB_KEY_F1: ++ ch = 'P'; ++ break; ++ case XKB_KEY_F2: ++ ch = 'Q'; ++ break; ++ case XKB_KEY_F3: ++ ch = 'R'; ++ break; ++ case XKB_KEY_F4: ++ ch = 'S'; ++ break; ++ } ++ if (ch) { ++ if (ch_mods) { ++ *p++ = 0x1b; ++ *p++ = '['; ++ *p++ = '1'; ++ *p++ = ';'; ++ *p++ = ch_mods; ++ *p++ = ch; ++ } else { ++ *p++ = 0x1b; ++ *p++ = 'O'; ++ *p++ = ch; ++ } ++ ++ return p; ++ } ++ ++ /* map upper function keys */ ++ ch = 0; ++ ch2 = 0; ++ switch (v) { ++ case XKB_KEY_F5: ++ ch = '1'; ++ ch2 = '5'; ++ break; ++ case XKB_KEY_F6: ++ ch = '1'; ++ ch2 = '7'; ++ break; ++ case XKB_KEY_F7: ++ ch = '1'; ++ ch2 = '8'; ++ break; ++ case XKB_KEY_F8: ++ ch = '1'; ++ ch2 = '9'; ++ break; ++ case XKB_KEY_F9: ++ ch = '2'; ++ ch2 = '0'; ++ break; ++ case XKB_KEY_F10: ++ ch = '2'; ++ ch2 = '1'; ++ break; ++ case XKB_KEY_F11: ++ ch = '2'; ++ ch2 = '2'; ++ break; ++ case XKB_KEY_F12: ++ ch = '2'; ++ ch2 = '3'; ++ break; ++ } ++ if (ch) { ++ *p++ = 0x1b; ++ *p++ = '['; ++ *p++ = ch; ++ if (ch2) ++ *p++ = ch2; ++ if (ch_mods) { ++ *p++ = ';'; ++ *p++ = ch_mods; ++ } ++ *p++ = '~'; ++ return p; ++ } ++ ++ /* map special keys */ ++ switch (v) { ++ case 0xff08: /* XKB_KEY_BackSpace */ ++ case 0xff09: /* XKB_KEY_Tab */ ++ case 0xff0a: /* XKB_KEY_Linefeed */ ++ case 0xff0b: /* XKB_KEY_Clear */ ++ case 0xff15: /* XKB_KEY_Sys_Req */ ++ case 0xff1b: /* XKB_KEY_Escape */ ++ case 0xffff: /* XKB_KEY_Delete */ ++ *p++ = v - 0xff00; ++ return p; ++ case 0xff13: /* XKB_KEY_Pause */ ++ /* TODO: What should we do with this key? ++ * Sending XOFF is awful as there is no simple ++ * way on modern keyboards to send XON again. ++ * If someone wants this, we can re-eanble ++ * optionally. */ ++ return p; ++ case 0xff14: /* XKB_KEY_Scroll_Lock */ ++ /* TODO: What should we do on scroll-lock? ++ * Sending 0x14 is what the specs say but it is ++ * not used today the way most users would ++ * expect so we disable it. If someone wants ++ * this, we can re-enable it (optionally). */ ++ return p; ++ case XKB_KEY_Return: ++ *p++ = 0x0d; ++ if (screen->flags & TERM_FLAG_NEWLINE_MODE) ++ *p++ = 0x0a; ++ return p; ++ case XKB_KEY_ISO_Left_Tab: ++ *p++ = 0x09; ++ return p; ++ } ++ ++ /* map unicode keys */ ++ for (i = 0; i < n_syms; ++i) ++ p += term_utf8_encode(p, ucs4[i]); ++ ++ return p; ++} ++ ++int term_screen_feed_keyboard(term_screen *screen, ++ const uint32_t *keysyms, ++ size_t n_syms, ++ uint32_t ascii, ++ const uint32_t *ucs4, ++ unsigned int mods) { ++ _cleanup_free_ char *dyn = NULL; ++ static const size_t padding = 1; ++ char buf[128], *start, *p = buf; ++ + assert_return(screen, -EINVAL); + +- /* TODO */ ++ /* allocate buffer if too small */ ++ start = buf; ++ if (4 * n_syms + padding > sizeof(buf)) { ++ dyn = malloc(4 * n_syms + padding); ++ if (!dyn) ++ return -ENOMEM; + +- return 0; ++ start = dyn; ++ } ++ ++ /* reserve prefix space */ ++ start += padding; ++ p = start; ++ ++ p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods); ++ if (!p || p - start < 1) ++ return 0; ++ ++ /* The ALT modifier causes ESC to be prepended to any key-stroke. We ++ * already accounted for that buffer space above, so simply prepend it ++ * here. ++ * TODO: is altSendsEscape a suitable default? What are the semantics ++ * exactly? Is it used in C0/C1 conversion? Is it prepended if there ++ * already is an escape character? */ ++ if (mods & TERM_KBDMOD_ALT && *start != 0x1b) ++ *--start = 0x1b; ++ ++ /* turn C0 into C1 */ ++ if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2) ++ if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f) ++ *++start ^= 0x40; ++ ++ return screen_write(screen, start, p - start); + } + + int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) { +diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h +index a3ca252e31..5228ce0601 100644 +--- a/src/libsystemd-terminal/term.h ++++ b/src/libsystemd-terminal/term.h +@@ -128,6 +128,21 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(term_parser*, term_parser_free); + * Screens + */ + ++enum { ++ TERM_KBDMOD_IDX_SHIFT, ++ TERM_KBDMOD_IDX_CTRL, ++ TERM_KBDMOD_IDX_ALT, ++ TERM_KBDMOD_IDX_LINUX, ++ TERM_KBDMOD_IDX_CAPS, ++ TERM_KBDMOD_CNT, ++ ++ TERM_KBDMOD_SHIFT = 1 << TERM_KBDMOD_IDX_SHIFT, ++ TERM_KBDMOD_CTRL = 1 << TERM_KBDMOD_IDX_CTRL, ++ TERM_KBDMOD_ALT = 1 << TERM_KBDMOD_IDX_ALT, ++ TERM_KBDMOD_LINUX = 1 << TERM_KBDMOD_IDX_LINUX, ++ TERM_KBDMOD_CAPS = 1 << TERM_KBDMOD_IDX_CAPS, ++}; ++ + typedef int (*term_screen_write_fn) (term_screen *screen, void *userdata, const void *buf, size_t size); + typedef int (*term_screen_cmd_fn) (term_screen *screen, void *userdata, unsigned int cmd, const term_seq *seq); + +@@ -141,7 +156,12 @@ unsigned int term_screen_get_width(term_screen *screen); + unsigned int term_screen_get_height(term_screen *screen); + + int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size); +-int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods); ++int term_screen_feed_keyboard(term_screen *screen, ++ const uint32_t *keysyms, ++ size_t n_syms, ++ uint32_t ascii, ++ const uint32_t *ucs4, ++ unsigned int mods); + int term_screen_resize(term_screen *screen, unsigned int width, unsigned int height); + void term_screen_soft_reset(term_screen *screen); + void term_screen_hard_reset(term_screen *screen); diff --git a/0488-terminal-idev-add-helper-to-match-keyboard-shortcuts.patch b/0488-terminal-idev-add-helper-to-match-keyboard-shortcuts.patch new file mode 100644 index 0000000..6ef6315 --- /dev/null +++ b/0488-terminal-idev-add-helper-to-match-keyboard-shortcuts.patch @@ -0,0 +1,50 @@ +From 884964a9639649422d3613500cdacea48a4ccc91 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 13:11:08 +0200 +Subject: [PATCH] terminal/idev: add helper to match keyboard shortcuts + +Matching keyboard shortcuts on internationalized keyboards is actually +non-trivial. Matching the actual key is easy, but the modifiers can be +used by both, the matching and the translation step. Therefore, XKB +exports "consumed-modifiers" that we use to figure out whether a modifier +was already used by the translation step. + +The new IDEV_KBDMATCH() helper can be used to match on any keyboard +shortcut and it will do the right thing. +--- + src/libsystemd-terminal/idev.h | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h +index 0ae044cfd5..ea79bb6ab6 100644 +--- a/src/libsystemd-terminal/idev.h ++++ b/src/libsystemd-terminal/idev.h +@@ -110,6 +110,28 @@ struct idev_data_keyboard { + uint32_t *codepoints; + }; + ++static inline bool idev_kbdmatch(idev_data_keyboard *kdata, ++ uint32_t mods, uint32_t n_syms, ++ const uint32_t *syms) { ++ const uint32_t significant = IDEV_KBDMOD_SHIFT | ++ IDEV_KBDMOD_CTRL | ++ IDEV_KBDMOD_ALT | ++ IDEV_KBDMOD_LINUX; ++ uint32_t real; ++ ++ if (n_syms != kdata->n_syms) ++ return false; ++ ++ real = kdata->mods & ~kdata->consumed_mods & significant; ++ if (real != (mods & ~kdata->consumed_mods)) ++ return false; ++ ++ return !memcmp(syms, kdata->keysyms, n_syms * sizeof(*syms)); ++} ++ ++#define IDEV_KBDMATCH(_kdata, _mods, _sym) \ ++ idev_kbdmatch((_kdata), (_mods), 1, (const uint32_t[]){ (_sym) }) ++ + /* + * Data Packets + */ diff --git a/0489-terminal-screen-mark-cursor-dirty-on-enabled-disable.patch b/0489-terminal-screen-mark-cursor-dirty-on-enabled-disable.patch new file mode 100644 index 0000000..b124340 --- /dev/null +++ b/0489-terminal-screen-mark-cursor-dirty-on-enabled-disable.patch @@ -0,0 +1,24 @@ +From 2ea8d19b210b62a02ebcb38f035e074dcba66426 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 14:30:37 +0200 +Subject: [PATCH] terminal/screen: mark cursor dirty on enabled/disable + +If we hide or show the cursor, we change visual attributes and have to +mark the underlying cell as dirty. Otherwise, the terminal will not be +redrawn. +--- + src/libsystemd-terminal/term-screen.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 5b0562e4c3..2c881ca8b1 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -419,6 +419,7 @@ static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, + * TODO + */ + set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set); ++ screen_age_cursor(screen); + } + + break; diff --git a/0490-terminal-screen-add-cursor-rendering.patch b/0490-terminal-screen-add-cursor-rendering.patch new file mode 100644 index 0000000..70f9738 --- /dev/null +++ b/0490-terminal-screen-add-cursor-rendering.patch @@ -0,0 +1,83 @@ +From cad8fe9a2b2ac340ef69233dd32e1bb1e45dae48 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 14:42:42 +0200 +Subject: [PATCH] terminal/screen: add cursor rendering + +This is the most simple way to render cursors: flip attr->inverse of the +cursor cell. This causes the background and foreground colors of the +cursor-cell to be inversed. + +Now that we render cursors ourselves, make subterm not call into the +parent terminal to render cursors. +--- + src/libsystemd-terminal/subterm.c | 11 +++++++---- + src/libsystemd-terminal/term-screen.c | 9 ++++++++- + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c +index 563cbf0823..321cd35f52 100644 +--- a/src/libsystemd-terminal/subterm.c ++++ b/src/libsystemd-terminal/subterm.c +@@ -286,6 +286,8 @@ static Output *output_free(Output *o) { + if (!o) + return NULL; + ++ /* re-enable cursor */ ++ output_printf(o, "\e[?25h"); + /* disable alternate screen buffer */ + output_printf(o, "\e[?1049l"); + output_flush(o); +@@ -317,6 +319,11 @@ static int output_new(Output **out, int fd) { + if (r < 0) + goto error; + ++ /* always hide cursor */ ++ r = output_printf(o, "\e[?25l"); ++ if (r < 0) ++ goto error; ++ + r = output_flush(o); + if (r < 0) + goto error; +@@ -539,10 +546,6 @@ static void output_draw(Output *o, bool menu, term_screen *screen) { + else + output_draw_screen(o, screen); + +- /* show cursor */ +- if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) +- output_printf(o, "\e[?25h"); +- + /* + * Hack: sd-term was not written to support TTY as output-objects, thus + * expects callers to use term_screen_feed_keyboard(). However, we +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 2c881ca8b1..ccfb9a450c 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -4246,6 +4246,8 @@ int term_screen_draw(term_screen *screen, + line_age = MAX(line->age, page->age); + + for (i = 0; i < page->width; ++i) { ++ term_attr attr; ++ + cell = &line->cells[i]; + cell_age = MAX(cell->age, line_age); + +@@ -4259,11 +4261,16 @@ int term_screen_draw(term_screen *screen, + * renderers can assume ch_width is set properpy. */ + cw = MAX(cell->cwidth, 1U); + ++ attr = cell->attr; ++ if (i == screen->cursor_x && j == screen->cursor_y && ++ !(screen->flags & TERM_FLAG_HIDE_CURSOR)) ++ attr.inverse ^= 1; ++ + r = draw_fn(screen, + userdata, + i, + j, +- &cell->attr, ++ &attr, + ch_str, + ch_n, + cw); diff --git a/0491-terminal-screen-add-color-converter.patch b/0491-terminal-screen-add-color-converter.patch new file mode 100644 index 0000000..ea45c5c --- /dev/null +++ b/0491-terminal-screen-add-color-converter.patch @@ -0,0 +1,196 @@ +From 56dec05d29098b151421625c68525c2c3961e574 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 14:44:41 +0200 +Subject: [PATCH] terminal/screen: add color converter + +Terminals use pseudo color-codes mixed with 8bit and 24bit colors. Provide +a color-converter so external renderers only have to deal with ARGB32 +colors. + +This requires a color-palette as input as there's no fixed mapping. We +provide a default, but maybe we wanna support external palettes in the +future. +--- + src/libsystemd-terminal/term-parser.c | 116 ++++++++++++++++++++++++++++++++++ + src/libsystemd-terminal/term-screen.c | 26 +------- + src/libsystemd-terminal/term.h | 2 + + 3 files changed, 120 insertions(+), 24 deletions(-) + +diff --git a/src/libsystemd-terminal/term-parser.c b/src/libsystemd-terminal/term-parser.c +index f9326d563a..8ec6345d60 100644 +--- a/src/libsystemd-terminal/term-parser.c ++++ b/src/libsystemd-terminal/term-parser.c +@@ -35,6 +35,122 @@ + #include "term-internal.h" + #include "util.h" + ++static const uint8_t default_palette[18][3] = { ++ { 0, 0, 0 }, /* black */ ++ { 205, 0, 0 }, /* red */ ++ { 0, 205, 0 }, /* green */ ++ { 205, 205, 0 }, /* yellow */ ++ { 0, 0, 238 }, /* blue */ ++ { 205, 0, 205 }, /* magenta */ ++ { 0, 205, 205 }, /* cyan */ ++ { 229, 229, 229 }, /* light grey */ ++ { 127, 127, 127 }, /* dark grey */ ++ { 255, 0, 0 }, /* light red */ ++ { 0, 255, 0 }, /* light green */ ++ { 255, 255, 0 }, /* light yellow */ ++ { 92, 92, 255 }, /* light blue */ ++ { 255, 0, 255 }, /* light magenta */ ++ { 0, 255, 255 }, /* light cyan */ ++ { 255, 255, 255 }, /* white */ ++ ++ { 229, 229, 229 }, /* light grey */ ++ { 0, 0, 0 }, /* black */ ++}; ++ ++static uint32_t term_color_to_argb32(const term_color *color, const term_attr *attr, const uint8_t *palette) { ++ static const uint8_t bval[] = { ++ 0x00, 0x5f, 0x87, ++ 0xaf, 0xd7, 0xff, ++ }; ++ uint8_t r, g, b, t; ++ ++ assert(color); ++ ++ if (!palette) ++ palette = (void*)default_palette; ++ ++ switch (color->ccode) { ++ case TERM_CCODE_RGB: ++ r = color->red; ++ g = color->green; ++ b = color->blue; ++ ++ break; ++ case TERM_CCODE_256: ++ t = color->c256; ++ if (t < 16) { ++ r = palette[t * 3 + 0]; ++ g = palette[t * 3 + 1]; ++ b = palette[t * 3 + 2]; ++ } else if (t < 232) { ++ t -= 16; ++ b = bval[t % 6]; ++ t /= 6; ++ g = bval[t % 6]; ++ t /= 6; ++ r = bval[t % 6]; ++ } else { ++ t = (t - 232) * 10 + 8; ++ r = t; ++ g = t; ++ b = t; ++ } ++ ++ break; ++ case TERM_CCODE_BLACK ... TERM_CCODE_LIGHT_WHITE: ++ t = color->ccode - TERM_CCODE_BLACK; ++ ++ /* bold causes light colors */ ++ if (t < 8 && attr->bold) ++ t += 8; ++ ++ r = palette[t * 3 + 0]; ++ g = palette[t * 3 + 1]; ++ b = palette[t * 3 + 2]; ++ break; ++ case TERM_CCODE_DEFAULT: ++ /* fallthrough */ ++ default: ++ t = 16 + !(color == &attr->fg); ++ r = palette[t * 3 + 0]; ++ g = palette[t * 3 + 1]; ++ b = palette[t * 3 + 2]; ++ break; ++ } ++ ++ return (0xff << 24) | (r << 16) | (g << 8) | b; ++} ++ ++/** ++ * term_attr_to_argb32() - Encode terminal colors as native ARGB32 value ++ * @color: Terminal attributes to work on ++ * @fg: Storage for foreground color (or NULL) ++ * @bg: Storage for background color (or NULL) ++ * @palette: The color palette to use (or NULL for default) ++ * ++ * This encodes the colors attr->fg and attr->bg as native-endian ARGB32 values ++ * and returns them. Any color conversions are automatically applied. ++ */ ++void term_attr_to_argb32(const term_attr *attr, uint32_t *fg, uint32_t *bg, const uint8_t *palette) { ++ uint32_t f, b, t; ++ ++ assert(attr); ++ ++ f = term_color_to_argb32(&attr->fg, attr, palette); ++ b = term_color_to_argb32(&attr->bg, attr, palette); ++ ++ if (attr->inverse) { ++ t = f; ++ f = b; ++ b = t; ++ } ++ ++ if (fg) ++ *fg = f; ++ if (bg) ++ *bg = b; ++} ++ + /** + * term_utf8_encode() - Encode single UCS-4 character as UTF-8 + * @out_utf8: output buffer of at least 4 bytes or NULL +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index ccfb9a450c..3f7ef1cf3c 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -2944,31 +2944,9 @@ static int screen_SGR(term_screen *screen, const term_seq *seq) { + if (i >= seq->n_args || seq->args[i] < 0) + break; + ++ dst->ccode = TERM_CCODE_256; + code = seq->args[i]; +- if (code < 16) { +- dst->ccode = code; +- } else if (code < 232) { +- static const uint8_t bval[] = { +- 0x00, 0x5f, 0x87, +- 0xaf, 0xd7, 0xff, +- }; +- +- dst->ccode = TERM_CCODE_256; +- dst->c256 = code; +- code -= 16; +- dst->blue = bval[code % 6]; +- code /= 6; +- dst->green = bval[code % 6]; +- code /= 6; +- dst->red = bval[code % 6]; +- } else if (code < 256) { +- dst->ccode = TERM_CCODE_256; +- dst->c256 = code; +- code = (code - 232) * 10 + 8; +- dst->red = code; +- dst->green = code; +- dst->blue = code; +- } ++ dst->c256 = code < 256 ? code : 0; + + break; + } +diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h +index 5228ce0601..8efd48b263 100644 +--- a/src/libsystemd-terminal/term.h ++++ b/src/libsystemd-terminal/term.h +@@ -97,6 +97,8 @@ struct term_attr { + unsigned int hidden : 1; /* hidden */ + }; + ++void term_attr_to_argb32(const term_attr *attr, uint32_t *fg, uint32_t *bg, const uint8_t *palette); ++ + /* + * UTF-8 + */ diff --git a/0492-terminal-screen-adjust-screen-age-only-on-update.patch b/0492-terminal-screen-adjust-screen-age-only-on-update.patch new file mode 100644 index 0000000..dc92ce0 --- /dev/null +++ b/0492-terminal-screen-adjust-screen-age-only-on-update.patch @@ -0,0 +1,61 @@ +From ce04e2335ab80eda5674de3399aa16b5aea2657f Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 15:27:25 +0200 +Subject: [PATCH] terminal/screen: adjust screen age only on update + +Instead of increasing the screen-age on redraw, we now increase it only on +real updates. This is effectively the same, but avoids increased age +counters on backbuffer rendering. Therefore, we can now check age counters +against fronbuffers safely, while rendering frames in background. +--- + src/libsystemd-terminal/term-screen.c | 10 +++++++++- + src/libsystemd-terminal/term.h | 1 + + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 3f7ef1cf3c..145dcdaee5 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -3735,6 +3735,12 @@ unsigned int term_screen_get_height(term_screen *screen) { + return screen->page->height; + } + ++uint64_t term_screen_get_age(term_screen *screen) { ++ assert_return(screen, 0); ++ ++ return screen->age; ++} ++ + int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) { + uint32_t *ucs4_str; + size_t i, j, ucs4_len; +@@ -3743,6 +3749,8 @@ int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) { + + assert_return(screen, -EINVAL); + ++ ++screen->age; ++ + /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always + * treat data as UTF-8, but the parser makes sure to fall back to raw + * 8bit mode if the stream is not valid UTF-8. This should be more than +@@ -4258,7 +4266,7 @@ int term_screen_draw(term_screen *screen, + } + + if (fb_age) +- *fb_age = screen->age++; ++ *fb_age = screen->age; + + return 0; + } +diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h +index 8efd48b263..eae6c6352f 100644 +--- a/src/libsystemd-terminal/term.h ++++ b/src/libsystemd-terminal/term.h +@@ -156,6 +156,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(term_screen*, term_screen_unref); + + unsigned int term_screen_get_width(term_screen *screen); + unsigned int term_screen_get_height(term_screen *screen); ++uint64_t term_screen_get_age(term_screen *screen); + + int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size); + int term_screen_feed_keyboard(term_screen *screen, diff --git a/0493-pty-optimize-read-loop.patch b/0493-pty-optimize-read-loop.patch new file mode 100644 index 0000000..6e80dd1 --- /dev/null +++ b/0493-pty-optimize-read-loop.patch @@ -0,0 +1,43 @@ +From 48fed5c55b5183e6d44702dfdccd3b5325d8689c Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 15:54:21 +0200 +Subject: [PATCH] pty: optimize read loop + +As it turns out, I can actually send data to the pty faster than the +terminal can read. Therefore, make sure we read as much data as possible +but bail out early enough to not cause starvation. + +Kernel TTY buffers are 4k, so reduce the overall buffer size, but read +more than once if possible (up to 8 times sounds reasonable). +--- + src/shared/pty.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/shared/pty.c b/src/shared/pty.c +index adcb32d0be..52a426c0e1 100644 +--- a/src/shared/pty.c ++++ b/src/shared/pty.c +@@ -67,7 +67,7 @@ + #include "ring.h" + #include "util.h" + +-#define PTY_BUFSIZE 16384 ++#define PTY_BUFSIZE 4096 + + enum { + PTY_ROLE_UNKNOWN, +@@ -305,11 +305,11 @@ static int pty_dispatch_read(Pty *pty) { + /* + * We're edge-triggered, means we need to read the whole queue. This, + * however, might cause us to stall if the writer is faster than we +- * are. Therefore, we read twice and if the second read still returned +- * data, we reschedule. ++ * are. Therefore, try reading as much as 8 times (32KiB) and only ++ * bail out then. + */ + +- for (i = 0; i < 2; ++i) { ++ for (i = 0; i < 8; ++i) { + len = read(pty->fd, pty->in_buf, sizeof(pty->in_buf) - 1); + if (len < 0) { + if (errno == EINTR) diff --git a/0494-console-add-user-console-daemon.patch b/0494-console-add-user-console-daemon.patch new file mode 100644 index 0000000..a17e71e --- /dev/null +++ b/0494-console-add-user-console-daemon.patch @@ -0,0 +1,1567 @@ +From ce7b9f50c3fadbad22feeb28e4429ad9bee02bcc Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 3 Oct 2014 15:58:44 +0200 +Subject: [PATCH] console: add user console daemon + +This adds a first draft of systemd-consoled. This is still missing a lot +of features and does some rather primitive rendering. However, it shows +the direction this code is going and serves as basis for further testing. + +The systemd-consoled binary should be run as `systemd --user' unit. It +automatically picks up any session marked as Desktop=SYSTEMD-CONSOLE. +Therefore, you can use any login-manager you want (ranging from /bin/login +to gdm) to create sessions for systemd-consoled. However, the sessions +managers must be prepared to set the Desktop= variable properly. + +The user-session is called `systemd-console', only the daemon providing +the terminal environment is called `systemd-consoled' (mind the 'd'). + +So far, only a single terminal session is provided on each opened +user-session. However, we support multiple user-sessions (even across +multiple seats) just fine. In the future, the workspace logic will get +extended so you can have multiple terminal sessions in a single +user-session for easier access. + +Note that this is still experimental! Instructions on how to run it will +follow shortly. +--- + .gitignore | 1 + + Makefile.am | 22 +++ + src/console/Makefile | 1 + + src/console/consoled-display.c | 82 +++++++++ + src/console/consoled-manager.c | 288 +++++++++++++++++++++++++++++++ + src/console/consoled-session.c | 283 ++++++++++++++++++++++++++++++ + src/console/consoled-terminal.c | 360 +++++++++++++++++++++++++++++++++++++++ + src/console/consoled-workspace.c | 168 ++++++++++++++++++ + src/console/consoled.c | 67 ++++++++ + src/console/consoled.h | 170 ++++++++++++++++++ + 10 files changed, 1442 insertions(+) + create mode 120000 src/console/Makefile + create mode 100644 src/console/consoled-display.c + create mode 100644 src/console/consoled-manager.c + create mode 100644 src/console/consoled-session.c + create mode 100644 src/console/consoled-terminal.c + create mode 100644 src/console/consoled-workspace.c + create mode 100644 src/console/consoled.c + create mode 100644 src/console/consoled.h + +diff --git a/.gitignore b/.gitignore +index cb1af8de5b..f119b574c7 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -60,6 +60,7 @@ + /systemd-cgls + /systemd-cgroups-agent + /systemd-cgtop ++/systemd-consoled + /systemd-coredump + /systemd-cryptsetup + /systemd-cryptsetup-generator +diff --git a/Makefile.am b/Makefile.am +index 503302851b..60011b7d98 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3020,6 +3020,9 @@ if ENABLE_TERMINAL + noinst_LTLIBRARIES += \ + libsystemd-terminal.la + ++bin_PROGRAMS += \ ++ systemd-consoled ++ + noinst_PROGRAMS += \ + systemd-evcat \ + systemd-modeset \ +@@ -3068,6 +3071,25 @@ libsystemd_terminal_la_LIBADD = \ + libsystemd-shared.la \ + $(TERMINAL_LIBS) + ++systemd_consoled_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(TERMINAL_CFLAGS) ++ ++systemd_consoled_SOURCES = \ ++ src/console/consoled.h \ ++ src/console/consoled.c \ ++ src/console/consoled-display.c \ ++ src/console/consoled-manager.c \ ++ src/console/consoled-session.c \ ++ src/console/consoled-terminal.c \ ++ src/console/consoled-workspace.c ++ ++systemd_consoled_LDADD = \ ++ libsystemd-terminal.la \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la \ ++ $(TERMINAL_LIBS) ++ + systemd_evcat_CFLAGS = \ + $(AM_CFLAGS) \ + $(TERMINAL_CFLAGS) +diff --git a/src/console/Makefile b/src/console/Makefile +new file mode 120000 +index 0000000000..d0b0e8e008 +--- /dev/null ++++ b/src/console/Makefile +@@ -0,0 +1 @@ ++../Makefile +\ No newline at end of file +diff --git a/src/console/consoled-display.c b/src/console/consoled-display.c +new file mode 100644 +index 0000000000..a30a2f1022 +--- /dev/null ++++ b/src/console/consoled-display.c +@@ -0,0 +1,82 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ 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 ++#include ++#include "consoled.h" ++#include "grdev.h" ++#include "list.h" ++#include "macro.h" ++#include "util.h" ++ ++int display_new(Display **out, Session *s, grdev_display *display) { ++ _cleanup_(display_freep) Display *d = NULL; ++ ++ assert(out); ++ assert(s); ++ assert(display); ++ ++ d = new0(Display, 1); ++ if (!d) ++ return -ENOMEM; ++ ++ d->session = s; ++ d->grdev = display; ++ d->width = grdev_display_get_width(display); ++ d->height = grdev_display_get_height(display); ++ LIST_PREPEND(displays_by_session, d->session->display_list, d); ++ ++ grdev_display_enable(display); ++ ++ *out = d; ++ d = NULL; ++ return 0; ++} ++ ++Display *display_free(Display *d) { ++ if (!d) ++ return NULL; ++ ++ LIST_REMOVE(displays_by_session, d->session->display_list, d); ++ free(d); ++ ++ return NULL; ++} ++ ++void display_refresh(Display *d) { ++ assert(d); ++ ++ d->width = grdev_display_get_width(d->grdev); ++ d->height = grdev_display_get_height(d->grdev); ++} ++ ++void display_render(Display *d, Workspace *w) { ++ const grdev_display_target *target; ++ ++ assert(d); ++ assert(w); ++ ++ GRDEV_DISPLAY_FOREACH_TARGET(d->grdev, target) { ++ if (workspace_draw(w, target)) ++ grdev_display_flip_target(d->grdev, target); ++ } ++} +diff --git a/src/console/consoled-manager.c b/src/console/consoled-manager.c +new file mode 100644 +index 0000000000..8f3823fe46 +--- /dev/null ++++ b/src/console/consoled-manager.c +@@ -0,0 +1,288 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ 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 ++#include ++#include ++#include "consoled.h" ++#include "grdev.h" ++#include "idev.h" ++#include "log.h" ++#include "sd-bus.h" ++#include "sd-daemon.h" ++#include "sd-event.h" ++#include "sd-login.h" ++#include "sysview.h" ++#include "unifont.h" ++#include "util.h" ++ ++int manager_new(Manager **out) { ++ _cleanup_(manager_freep) Manager *m = NULL; ++ int r; ++ ++ assert(out); ++ ++ m = new0(Manager, 1); ++ if (!m) ++ return -ENOMEM; ++ ++ r = sd_event_default(&m->event); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_set_watchdog(m->event, true); ++ if (r < 0) ++ return r; ++ ++ r = sigprocmask_many(SIG_BLOCK, SIGTERM, SIGQUIT, SIGINT, SIGWINCH, SIGCHLD, -1); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_signal(m->event, NULL, SIGQUIT, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_open_system(&m->sysbus); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_attach_event(m->sysbus, m->event, SD_EVENT_PRIORITY_NORMAL); ++ if (r < 0) ++ return r; ++ ++ r = unifont_new(&m->uf); ++ if (r < 0) ++ return r; ++ ++ r = sysview_context_new(&m->sysview, ++ SYSVIEW_CONTEXT_SCAN_LOGIND | ++ SYSVIEW_CONTEXT_SCAN_EVDEV | ++ SYSVIEW_CONTEXT_SCAN_DRM, ++ m->event, ++ m->sysbus, ++ NULL); ++ if (r < 0) ++ return r; ++ ++ r = grdev_context_new(&m->grdev, m->event, m->sysbus); ++ if (r < 0) ++ return r; ++ ++ r = idev_context_new(&m->idev, m->event, m->sysbus); ++ if (r < 0) ++ return r; ++ ++ *out = m; ++ m = NULL; ++ return 0; ++} ++ ++Manager *manager_free(Manager *m) { ++ if (!m) ++ return NULL; ++ ++ assert(!m->workspace_list); ++ ++ m->idev = idev_context_unref(m->idev); ++ m->grdev = grdev_context_unref(m->grdev); ++ m->sysview = sysview_context_free(m->sysview); ++ m->uf = unifont_unref(m->uf); ++ m->sysbus = sd_bus_unref(m->sysbus); ++ m->event = sd_event_unref(m->event); ++ free(m); ++ ++ return NULL; ++} ++ ++static int manager_sysview_session_filter(Manager *m, sysview_event *event) { ++ const char *sid = event->session_filter.id; ++ _cleanup_free_ char *desktop = NULL; ++ int r; ++ ++ assert(sid); ++ ++ r = sd_session_get_desktop(sid, &desktop); ++ if (r < 0) ++ return 0; ++ ++ return streq(desktop, "SYSTEMD-CONSOLE"); ++} ++ ++static int manager_sysview_session_add(Manager *m, sysview_event *event) { ++ sysview_session *session = event->session_add.session; ++ Session *s; ++ int r; ++ ++ r = sysview_session_take_control(session); ++ if (r < 0) { ++ log_error("Cannot request session control on '%s': %s", ++ sysview_session_get_name(session), strerror(-r)); ++ return r; ++ } ++ ++ r = session_new(&s, m, session); ++ if (r < 0) { ++ log_error("Cannot create session on '%s': %s", ++ sysview_session_get_name(session), strerror(-r)); ++ sysview_session_release_control(session); ++ return r; ++ } ++ ++ sysview_session_set_userdata(session, s); ++ ++ return 0; ++} ++ ++static int manager_sysview_session_remove(Manager *m, sysview_event *event) { ++ sysview_session *session = event->session_remove.session; ++ Session *s; ++ ++ s = sysview_session_get_userdata(session); ++ if (!s) ++ return 0; ++ ++ session_free(s); ++ ++ return 0; ++} ++ ++static int manager_sysview_session_attach(Manager *m, sysview_event *event) { ++ sysview_session *session = event->session_attach.session; ++ sysview_device *device = event->session_attach.device; ++ Session *s; ++ ++ s = sysview_session_get_userdata(session); ++ if (!s) ++ return 0; ++ ++ session_add_device(s, device); ++ ++ return 0; ++} ++ ++static int manager_sysview_session_detach(Manager *m, sysview_event *event) { ++ sysview_session *session = event->session_detach.session; ++ sysview_device *device = event->session_detach.device; ++ Session *s; ++ ++ s = sysview_session_get_userdata(session); ++ if (!s) ++ return 0; ++ ++ session_remove_device(s, device); ++ ++ return 0; ++} ++ ++static int manager_sysview_session_refresh(Manager *m, sysview_event *event) { ++ sysview_session *session = event->session_refresh.session; ++ sysview_device *device = event->session_refresh.device; ++ struct udev_device *ud = event->session_refresh.ud; ++ Session *s; ++ ++ s = sysview_session_get_userdata(session); ++ if (!s) ++ return 0; ++ ++ session_refresh_device(s, device, ud); ++ ++ return 0; ++} ++ ++static int manager_sysview_session_control(Manager *m, sysview_event *event) { ++ sysview_session *session = event->session_control.session; ++ int error = event->session_control.error; ++ Session *s; ++ ++ s = sysview_session_get_userdata(session); ++ if (!s) ++ return 0; ++ ++ if (error < 0) { ++ log_error("Cannot take session control on '%s': %s", ++ sysview_session_get_name(session), strerror(-error)); ++ session_free(s); ++ sysview_session_set_userdata(session, NULL); ++ return -error; ++ } ++ ++ return 0; ++} ++ ++static int manager_sysview_fn(sysview_context *sysview, void *userdata, sysview_event *event) { ++ Manager *m = userdata; ++ int r; ++ ++ assert(m); ++ ++ switch (event->type) { ++ case SYSVIEW_EVENT_SESSION_FILTER: ++ r = manager_sysview_session_filter(m, event); ++ break; ++ case SYSVIEW_EVENT_SESSION_ADD: ++ r = manager_sysview_session_add(m, event); ++ break; ++ case SYSVIEW_EVENT_SESSION_REMOVE: ++ r = manager_sysview_session_remove(m, event); ++ break; ++ case SYSVIEW_EVENT_SESSION_ATTACH: ++ r = manager_sysview_session_attach(m, event); ++ break; ++ case SYSVIEW_EVENT_SESSION_DETACH: ++ r = manager_sysview_session_detach(m, event); ++ break; ++ case SYSVIEW_EVENT_SESSION_REFRESH: ++ r = manager_sysview_session_refresh(m, event); ++ break; ++ case SYSVIEW_EVENT_SESSION_CONTROL: ++ r = manager_sysview_session_control(m, event); ++ break; ++ default: ++ r = 0; ++ break; ++ } ++ ++ return r; ++} ++ ++int manager_run(Manager *m) { ++ int r; ++ ++ assert(m); ++ ++ r = sysview_context_start(m->sysview, manager_sysview_fn, m); ++ if (r < 0) ++ return r; ++ ++ r = sd_event_loop(m->event); ++ ++ sysview_context_stop(m->sysview); ++ return r; ++} +diff --git a/src/console/consoled-session.c b/src/console/consoled-session.c +new file mode 100644 +index 0000000000..8bacacab35 +--- /dev/null ++++ b/src/console/consoled-session.c +@@ -0,0 +1,283 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ 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 ++#include ++#include ++#include "consoled.h" ++#include "grdev.h" ++#include "hashmap.h" ++#include "idev.h" ++#include "list.h" ++#include "macro.h" ++#include "sd-bus.h" ++#include "sd-event.h" ++#include "sysview.h" ++#include "util.h" ++ ++static bool session_feed_keyboard(Session *s, idev_data *data) { ++ idev_data_keyboard *kdata = &data->keyboard; ++ ++ if (!data->resync && kdata->value == 1 && kdata->n_syms == 1) { ++ uint32_t nr; ++ sysview_seat *seat; ++ ++ /* handle VT-switch requests */ ++ nr = 0; ++ ++ switch (kdata->keysyms[0]) { ++ case XKB_KEY_F1 ... XKB_KEY_F12: ++ if (IDEV_KBDMATCH(kdata, ++ IDEV_KBDMOD_CTRL | IDEV_KBDMOD_ALT, ++ kdata->keysyms[0])) ++ nr = kdata->keysyms[0] - XKB_KEY_F1 + 1; ++ break; ++ case XKB_KEY_XF86Switch_VT_1 ... XKB_KEY_XF86Switch_VT_12: ++ nr = kdata->keysyms[0] - XKB_KEY_XF86Switch_VT_1 + 1; ++ break; ++ } ++ ++ if (nr != 0) { ++ seat = sysview_session_get_seat(s->sysview); ++ sysview_seat_switch_to(seat, nr); ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static bool session_feed(Session *s, idev_data *data) { ++ switch (data->type) { ++ case IDEV_DATA_KEYBOARD: ++ return session_feed_keyboard(s, data); ++ default: ++ return false; ++ } ++} ++ ++static int session_idev_fn(idev_session *idev, void *userdata, idev_event *event) { ++ Session *s = userdata; ++ ++ switch (event->type) { ++ case IDEV_EVENT_DEVICE_ADD: ++ idev_device_enable(event->device_add.device); ++ break; ++ case IDEV_EVENT_DEVICE_REMOVE: ++ idev_device_disable(event->device_remove.device); ++ break; ++ case IDEV_EVENT_DEVICE_DATA: ++ if (!session_feed(s, &event->device_data.data)) ++ workspace_feed(s->active_ws, &event->device_data.data); ++ break; ++ } ++ ++ return 0; ++} ++ ++static void session_grdev_fn(grdev_session *grdev, void *userdata, grdev_event *event) { ++ grdev_display *display; ++ Session *s = userdata; ++ Display *d; ++ int r; ++ ++ switch (event->type) { ++ case GRDEV_EVENT_DISPLAY_ADD: ++ display = event->display_add.display; ++ ++ r = display_new(&d, s, display); ++ if (r < 0) { ++ log_error("Cannot create display '%s' on '%s': %s", ++ grdev_display_get_name(display), sysview_session_get_name(s->sysview), strerror(-r)); ++ break; ++ } ++ ++ grdev_display_set_userdata(display, d); ++ workspace_refresh(s->active_ws); ++ break; ++ case GRDEV_EVENT_DISPLAY_REMOVE: ++ display = event->display_remove.display; ++ d = grdev_display_get_userdata(display); ++ if (!d) ++ break; ++ ++ display_free(d); ++ workspace_refresh(s->active_ws); ++ break; ++ case GRDEV_EVENT_DISPLAY_CHANGE: ++ display = event->display_remove.display; ++ d = grdev_display_get_userdata(display); ++ if (!d) ++ break; ++ ++ display_refresh(d); ++ workspace_refresh(s->active_ws); ++ break; ++ case GRDEV_EVENT_DISPLAY_FRAME: ++ display = event->display_remove.display; ++ d = grdev_display_get_userdata(display); ++ if (!d) ++ break; ++ ++ session_dirty(s); ++ break; ++ } ++} ++ ++static int session_redraw_fn(sd_event_source *src, void *userdata) { ++ Session *s = userdata; ++ Display *d; ++ ++ LIST_FOREACH(displays_by_session, d, s->display_list) ++ display_render(d, s->active_ws); ++ ++ grdev_session_commit(s->grdev); ++ ++ return 0; ++} ++ ++int session_new(Session **out, Manager *m, sysview_session *session) { ++ _cleanup_(session_freep) Session *s = NULL; ++ int r; ++ ++ assert(out); ++ assert(m); ++ assert(session); ++ ++ s = new0(Session, 1); ++ if (!s) ++ return -ENOMEM; ++ ++ s->manager = m; ++ s->sysview = session; ++ ++ r = grdev_session_new(&s->grdev, ++ m->grdev, ++ GRDEV_SESSION_MANAGED, ++ sysview_session_get_name(session), ++ session_grdev_fn, ++ s); ++ if (r < 0) ++ return r; ++ ++ r = idev_session_new(&s->idev, ++ m->idev, ++ IDEV_SESSION_MANAGED, ++ sysview_session_get_name(session), ++ session_idev_fn, ++ s); ++ if (r < 0) ++ return r; ++ ++ r = workspace_new(&s->my_ws, m); ++ if (r < 0) ++ return r; ++ ++ s->active_ws = workspace_attach(s->my_ws, s); ++ ++ r = sd_event_add_defer(m->event, &s->redraw_src, session_redraw_fn, s); ++ if (r < 0) ++ return r; ++ ++ grdev_session_enable(s->grdev); ++ idev_session_enable(s->idev); ++ ++ *out = s; ++ s = NULL; ++ return 0; ++} ++ ++Session *session_free(Session *s) { ++ if (!s) ++ return NULL; ++ ++ assert(!s->display_list); ++ ++ sd_event_source_unref(s->redraw_src); ++ ++ workspace_detach(s->active_ws, s); ++ workspace_unref(s->my_ws); ++ ++ idev_session_free(s->idev); ++ grdev_session_free(s->grdev); ++ free(s); ++ ++ return NULL; ++} ++ ++void session_dirty(Session *s) { ++ int r; ++ ++ assert(s); ++ ++ r = sd_event_source_set_enabled(s->redraw_src, SD_EVENT_ONESHOT); ++ if (r < 0) ++ log_error("Cannot enable redraw-source: %s", strerror(-r)); ++} ++ ++void session_add_device(Session *s, sysview_device *device) { ++ unsigned int type; ++ ++ assert(s); ++ assert(device); ++ ++ type = sysview_device_get_type(device); ++ switch (type) { ++ case SYSVIEW_DEVICE_DRM: ++ grdev_session_add_drm(s->grdev, sysview_device_get_ud(device)); ++ break; ++ case SYSVIEW_DEVICE_EVDEV: ++ idev_session_add_evdev(s->idev, sysview_device_get_ud(device)); ++ break; ++ } ++} ++ ++void session_remove_device(Session *s, sysview_device *device) { ++ unsigned int type; ++ ++ assert(s); ++ assert(device); ++ ++ type = sysview_device_get_type(device); ++ switch (type) { ++ case SYSVIEW_DEVICE_DRM: ++ grdev_session_remove_drm(s->grdev, sysview_device_get_ud(device)); ++ break; ++ case SYSVIEW_DEVICE_EVDEV: ++ idev_session_remove_evdev(s->idev, sysview_device_get_ud(device)); ++ break; ++ } ++} ++ ++void session_refresh_device(Session *s, sysview_device *device, struct udev_device *ud) { ++ unsigned int type; ++ ++ assert(s); ++ assert(device); ++ ++ type = sysview_device_get_type(device); ++ switch (type) { ++ case SYSVIEW_DEVICE_DRM: ++ grdev_session_hotplug_drm(s->grdev, sysview_device_get_ud(device)); ++ break; ++ } ++} +diff --git a/src/console/consoled-terminal.c b/src/console/consoled-terminal.c +new file mode 100644 +index 0000000000..d091579aa5 +--- /dev/null ++++ b/src/console/consoled-terminal.c +@@ -0,0 +1,360 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ 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 ++#include ++#include "consoled.h" ++#include "list.h" ++#include "macro.h" ++#include "util.h" ++ ++static int terminal_write_fn(term_screen *screen, void *userdata, const void *buf, size_t size) { ++ Terminal *t = userdata; ++ int r; ++ ++ if (t->pty) { ++ r = pty_write(t->pty, buf, size); ++ if (r < 0) ++ return log_oom(); ++ } ++ ++ return 0; ++} ++ ++static int terminal_pty_fn(Pty *pty, void *userdata, unsigned int event, const void *ptr, size_t size) { ++ Terminal *t = userdata; ++ int r; ++ ++ switch (event) { ++ case PTY_CHILD: ++ log_debug("PTY child exited"); ++ t->pty = pty_unref(t->pty); ++ break; ++ case PTY_DATA: ++ r = term_screen_feed_text(t->screen, ptr, size); ++ if (r < 0) ++ log_error("Cannot update screen state: %s", strerror(-r)); ++ ++ workspace_dirty(t->workspace); ++ break; ++ } ++ ++ return 0; ++} ++ ++int terminal_new(Terminal **out, Workspace *w) { ++ _cleanup_(terminal_freep) Terminal *t = NULL; ++ int r; ++ ++ assert(w); ++ ++ t = new0(Terminal, 1); ++ if (!t) ++ return -ENOMEM; ++ ++ t->workspace = w; ++ LIST_PREPEND(terminals_by_workspace, w->terminal_list, t); ++ ++ r = term_parser_new(&t->parser, true); ++ if (r < 0) ++ return r; ++ ++ r = term_screen_new(&t->screen, terminal_write_fn, t, NULL, NULL); ++ if (r < 0) ++ return r; ++ ++ r = term_screen_set_answerback(t->screen, "systemd-console"); ++ if (r < 0) ++ return r; ++ ++ if (out) ++ *out = t; ++ t = NULL; ++ return 0; ++} ++ ++Terminal *terminal_free(Terminal *t) { ++ if (!t) ++ return NULL; ++ ++ assert(t->workspace); ++ ++ if (t->pty) { ++ (void)pty_signal(t->pty, SIGHUP); ++ pty_close(t->pty); ++ pty_unref(t->pty); ++ } ++ term_screen_unref(t->screen); ++ term_parser_free(t->parser); ++ LIST_REMOVE(terminals_by_workspace, t->workspace->terminal_list, t); ++ free(t); ++ ++ return NULL; ++} ++ ++void terminal_resize(Terminal *t) { ++ uint32_t width, height, fw, fh; ++ int r; ++ ++ assert(t); ++ ++ width = t->workspace->width; ++ height = t->workspace->height; ++ fw = unifont_get_width(t->workspace->manager->uf); ++ fh = unifont_get_height(t->workspace->manager->uf); ++ ++ width = (fw > 0) ? width / fw : 0; ++ height = (fh > 0) ? height / fh : 0; ++ ++ if (t->pty) { ++ r = pty_resize(t->pty, width, height); ++ if (r < 0) ++ log_error("Cannot resize pty: %s", strerror(-r)); ++ } ++ ++ r = term_screen_resize(t->screen, width, height); ++ if (r < 0) ++ log_error("Cannot resize screen: %s", strerror(-r)); ++} ++ ++void terminal_run(Terminal *t) { ++ pid_t pid; ++ ++ assert(t); ++ ++ if (t->pty) ++ return; ++ ++ pid = pty_fork(&t->pty, ++ t->workspace->manager->event, ++ terminal_pty_fn, ++ t, ++ term_screen_get_width(t->screen), ++ term_screen_get_height(t->screen)); ++ if (pid < 0) { ++ log_error("Cannot fork PTY: %s", strerror(-pid)); ++ return; ++ } else if (pid == 0) { ++ /* child */ ++ ++ char **argv = (char*[]){ ++ (char*)getenv("SHELL") ? : (char*)_PATH_BSHELL, ++ NULL ++ }; ++ ++ setenv("TERM", "xterm-256color", 1); ++ setenv("COLORTERM", "systemd-console", 1); ++ ++ execve(argv[0], argv, environ); ++ log_error("Cannot exec %s (%d): %m", argv[0], -errno); ++ _exit(1); ++ } ++} ++ ++static void terminal_feed_keyboard(Terminal *t, idev_data *data) { ++ idev_data_keyboard *kdata = &data->keyboard; ++ int r; ++ ++ if (!data->resync && (kdata->value == 1 || kdata->value == 2)) { ++ assert_cc(TERM_KBDMOD_CNT == (int)IDEV_KBDMOD_CNT); ++ assert_cc(TERM_KBDMOD_IDX_SHIFT == (int)IDEV_KBDMOD_IDX_SHIFT && ++ TERM_KBDMOD_IDX_CTRL == (int)IDEV_KBDMOD_IDX_CTRL && ++ TERM_KBDMOD_IDX_ALT == (int)IDEV_KBDMOD_IDX_ALT && ++ TERM_KBDMOD_IDX_LINUX == (int)IDEV_KBDMOD_IDX_LINUX && ++ TERM_KBDMOD_IDX_CAPS == (int)IDEV_KBDMOD_IDX_CAPS); ++ ++ r = term_screen_feed_keyboard(t->screen, ++ kdata->keysyms, ++ kdata->n_syms, ++ kdata->ascii, ++ kdata->codepoints, ++ kdata->mods); ++ if (r < 0) ++ log_error("Cannot feed keyboard data to screen: %s", ++ strerror(-r)); ++ } ++} ++ ++void terminal_feed(Terminal *t, idev_data *data) { ++ switch (data->type) { ++ case IDEV_DATA_KEYBOARD: ++ terminal_feed_keyboard(t, data); ++ break; ++ } ++} ++ ++static void terminal_fill(uint8_t *dst, ++ uint32_t width, ++ uint32_t height, ++ uint32_t stride, ++ uint32_t value) { ++ uint32_t i, j, *px; ++ ++ for (j = 0; j < height; ++j) { ++ px = (uint32_t*)dst; ++ ++ for (i = 0; i < width; ++i) ++ *px++ = value; ++ ++ dst += stride; ++ } ++} ++ ++static void terminal_blend(uint8_t *dst, ++ uint32_t width, ++ uint32_t height, ++ uint32_t dst_stride, ++ const uint8_t *src, ++ uint32_t src_stride, ++ uint32_t fg, ++ uint32_t bg) { ++ uint32_t i, j, *px; ++ ++ for (j = 0; j < height; ++j) { ++ px = (uint32_t*)dst; ++ ++ for (i = 0; i < width; ++i) { ++ if (!src || src[i / 8] & (1 << (7 - i % 8))) ++ *px = fg; ++ else ++ *px = bg; ++ ++ ++px; ++ } ++ ++ src += src_stride; ++ dst += dst_stride; ++ } ++} ++ ++typedef struct { ++ const grdev_display_target *target; ++ unifont *uf; ++ uint32_t cell_width; ++ uint32_t cell_height; ++ bool dirty; ++} TerminalDrawContext; ++ ++static int terminal_draw_cell(term_screen *screen, ++ void *userdata, ++ unsigned int x, ++ unsigned int y, ++ const term_attr *attr, ++ const uint32_t *ch, ++ size_t n_ch, ++ unsigned int ch_width) { ++ TerminalDrawContext *ctx = userdata; ++ const grdev_display_target *target = ctx->target; ++ grdev_fb *fb = target->back; ++ uint32_t xpos, ypos, width, height; ++ uint32_t fg, bg; ++ unifont_glyph g; ++ uint8_t *dst; ++ int r; ++ ++ if (n_ch > 0) { ++ r = unifont_lookup(ctx->uf, &g, *ch); ++ if (r < 0) ++ r = unifont_lookup(ctx->uf, &g, 0xfffd); ++ if (r < 0) ++ unifont_fallback(&g); ++ } ++ ++ xpos = x * ctx->cell_width; ++ ypos = y * ctx->cell_height; ++ ++ if (xpos >= fb->width || ypos >= fb->height) ++ return 0; ++ ++ width = MIN(fb->width - xpos, ctx->cell_width * ch_width); ++ height = MIN(fb->height - ypos, ctx->cell_height); ++ ++ term_attr_to_argb32(attr, &fg, &bg, NULL); ++ ++ ctx->dirty = true; ++ ++ dst = fb->maps[0]; ++ dst += fb->strides[0] * ypos + sizeof(uint32_t) * xpos; ++ ++ if (n_ch < 1) { ++ terminal_fill(dst, ++ width, ++ height, ++ fb->strides[0], ++ bg); ++ } else { ++ if (width > g.width) ++ terminal_fill(dst + sizeof(uint32_t) * g.width, ++ width - g.width, ++ height, ++ fb->strides[0], ++ bg); ++ if (height > g.height) ++ terminal_fill(dst + fb->strides[0] * g.height, ++ width, ++ height - g.height, ++ fb->strides[0], ++ bg); ++ ++ terminal_blend(dst, ++ width, ++ height, ++ fb->strides[0], ++ g.data, ++ g.stride, ++ fg, ++ bg); ++ } ++ ++ return 0; ++} ++ ++bool terminal_draw(Terminal *t, const grdev_display_target *target) { ++ TerminalDrawContext ctx = { }; ++ uint64_t age; ++ ++ assert(t); ++ assert(target); ++ ++ /* start up terminal on first frame */ ++ terminal_run(t); ++ ++ ctx.target = target; ++ ctx.uf = t->workspace->manager->uf; ++ ctx.cell_width = unifont_get_width(ctx.uf); ++ ctx.cell_height = unifont_get_height(ctx.uf); ++ ctx.dirty = false; ++ ++ if (target->front) { ++ /* if the frontbuffer is new enough, no reason to redraw */ ++ age = term_screen_get_age(t->screen); ++ if (age != 0 && age <= target->front->data.u64) ++ return false; ++ } else { ++ /* force flip if no frontbuffer is set, yet */ ++ ctx.dirty = true; ++ } ++ ++ term_screen_draw(t->screen, terminal_draw_cell, &ctx, &target->back->data.u64); ++ ++ return ctx.dirty; ++} +diff --git a/src/console/consoled-workspace.c b/src/console/consoled-workspace.c +new file mode 100644 +index 0000000000..56344ef2cf +--- /dev/null ++++ b/src/console/consoled-workspace.c +@@ -0,0 +1,168 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ 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 ++#include ++#include "consoled.h" ++#include "grdev.h" ++#include "idev.h" ++#include "list.h" ++#include "macro.h" ++#include "util.h" ++ ++int workspace_new(Workspace **out, Manager *m) { ++ _cleanup_(workspace_unrefp) Workspace *w = NULL; ++ int r; ++ ++ assert(out); ++ ++ w = new0(Workspace, 1); ++ if (!w) ++ return -ENOMEM; ++ ++ w->ref = 1; ++ w->manager = m; ++ LIST_PREPEND(workspaces_by_manager, m->workspace_list, w); ++ ++ r = terminal_new(&w->current, w); ++ if (r < 0) ++ return r; ++ ++ *out = w; ++ w = NULL; ++ return 0; ++} ++ ++static void workspace_cleanup(Workspace *w) { ++ Terminal *t; ++ ++ assert(w); ++ assert(w->ref == 0); ++ assert(w->manager); ++ assert(!w->session_list); ++ ++ w->current = NULL; ++ while ((t = w->terminal_list)) ++ terminal_free(t); ++ ++ LIST_REMOVE(workspaces_by_manager, w->manager->workspace_list, w); ++ free(w); ++} ++ ++Workspace *workspace_ref(Workspace *w) { ++ assert(w); ++ ++ ++w->ref; ++ return w; ++} ++ ++Workspace *workspace_unref(Workspace *w) { ++ if (!w) ++ return NULL; ++ ++ assert(w->ref > 0); ++ ++ if (--w->ref == 0) ++ workspace_cleanup(w); ++ ++ return NULL; ++} ++ ++Workspace *workspace_attach(Workspace *w, Session *s) { ++ assert(w); ++ assert(s); ++ ++ LIST_PREPEND(sessions_by_workspace, w->session_list, s); ++ workspace_refresh(w); ++ return workspace_ref(w); ++} ++ ++Workspace *workspace_detach(Workspace *w, Session *s) { ++ assert(w); ++ assert(s); ++ assert(s->active_ws == w); ++ ++ LIST_REMOVE(sessions_by_workspace, w->session_list, s); ++ workspace_refresh(w); ++ return workspace_unref(w); ++} ++ ++void workspace_refresh(Workspace *w) { ++ uint32_t width, height; ++ Terminal *t; ++ Session *s; ++ Display *d; ++ ++ assert(w); ++ ++ width = 0; ++ height = 0; ++ ++ /* find out minimum dimension of all attached displays */ ++ LIST_FOREACH(sessions_by_workspace, s, w->session_list) { ++ LIST_FOREACH(displays_by_session, d, s->display_list) { ++ assert(d->width > 0 && d->height > 0); ++ ++ if (width == 0 || d->width < width) ++ width = d->width; ++ if (height == 0 || d->height < height) ++ height = d->height; ++ } ++ } ++ ++ /* either both are zero, or none is zero */ ++ assert(!(!width ^ !height)); ++ ++ /* update terminal-sizes if dimensions changed */ ++ if (w->width != width || w->height != height) { ++ w->width = width; ++ w->height = height; ++ ++ LIST_FOREACH(terminals_by_workspace, t, w->terminal_list) ++ terminal_resize(t); ++ ++ workspace_dirty(w); ++ } ++} ++ ++void workspace_dirty(Workspace *w) { ++ Session *s; ++ ++ assert(w); ++ ++ LIST_FOREACH(sessions_by_workspace, s, w->session_list) ++ session_dirty(s); ++} ++ ++void workspace_feed(Workspace *w, idev_data *data) { ++ assert(w); ++ assert(data); ++ ++ terminal_feed(w->current, data); ++} ++ ++bool workspace_draw(Workspace *w, const grdev_display_target *target) { ++ assert(w); ++ assert(target); ++ ++ return terminal_draw(w->current, target); ++} +diff --git a/src/console/consoled.c b/src/console/consoled.c +new file mode 100644 +index 0000000000..b0c9eda1ac +--- /dev/null ++++ b/src/console/consoled.c +@@ -0,0 +1,67 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ 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 ++#include ++#include "consoled.h" ++#include "log.h" ++#include "sd-daemon.h" ++#include "util.h" ++ ++int main(int argc, char *argv[]) { ++ _cleanup_(manager_freep) Manager *m = NULL; ++ int r; ++ ++ log_set_target(LOG_TARGET_AUTO); ++ log_parse_environment(); ++ log_open(); ++ ++ umask(0022); ++ ++ if (argc != 1) { ++ log_error("This program takes no arguments."); ++ r = -EINVAL; ++ goto out; ++ } ++ ++ r = manager_new(&m); ++ if (r < 0) { ++ log_error("Could not create manager: %s", strerror(-r)); ++ goto out; ++ } ++ ++ sd_notify(false, ++ "READY=1\n" ++ "STATUS=Processing requests..."); ++ ++ r = manager_run(m); ++ if (r < 0) { ++ log_error("Cannot run manager: %s", strerror(-r)); ++ goto out; ++ } ++ ++out: ++ sd_notify(false, ++ "STATUS=Shutting down..."); ++ ++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} +diff --git a/src/console/consoled.h b/src/console/consoled.h +new file mode 100644 +index 0000000000..f8a3df4487 +--- /dev/null ++++ b/src/console/consoled.h +@@ -0,0 +1,170 @@ ++/*-*- 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 ++#include ++#include ++#include "grdev.h" ++#include "hashmap.h" ++#include "idev.h" ++#include "list.h" ++#include "macro.h" ++#include "pty.h" ++#include "sd-bus.h" ++#include "sd-event.h" ++#include "sysview.h" ++#include "term.h" ++#include "unifont.h" ++#include "util.h" ++ ++typedef struct Manager Manager; ++typedef struct Session Session; ++typedef struct Display Display; ++typedef struct Workspace Workspace; ++typedef struct Terminal Terminal; ++ ++/* ++ * Terminals ++ */ ++ ++struct Terminal { ++ Workspace *workspace; ++ LIST_FIELDS(Terminal, terminals_by_workspace); ++ ++ term_utf8 utf8; ++ term_parser *parser; ++ term_screen *screen; ++ Pty *pty; ++}; ++ ++int terminal_new(Terminal **out, Workspace *w); ++Terminal *terminal_free(Terminal *t); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Terminal*, terminal_free); ++ ++void terminal_resize(Terminal *t); ++void terminal_run(Terminal *t); ++void terminal_feed(Terminal *t, idev_data *data); ++bool terminal_draw(Terminal *t, const grdev_display_target *target); ++ ++/* ++ * Workspaces ++ */ ++ ++struct Workspace { ++ unsigned long ref; ++ Manager *manager; ++ LIST_FIELDS(Workspace, workspaces_by_manager); ++ ++ LIST_HEAD(Terminal, terminal_list); ++ Terminal *current; ++ ++ LIST_HEAD(Session, session_list); ++ uint32_t width; ++ uint32_t height; ++}; ++ ++int workspace_new(Workspace **out, Manager *m); ++Workspace *workspace_ref(Workspace *w); ++Workspace *workspace_unref(Workspace *w); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Workspace*, workspace_unref); ++ ++Workspace *workspace_attach(Workspace *w, Session *s); ++Workspace *workspace_detach(Workspace *w, Session *s); ++void workspace_refresh(Workspace *w); ++ ++void workspace_dirty(Workspace *w); ++void workspace_feed(Workspace *w, idev_data *data); ++bool workspace_draw(Workspace *w, const grdev_display_target *target); ++ ++/* ++ * Displays ++ */ ++ ++struct Display { ++ Session *session; ++ LIST_FIELDS(Display, displays_by_session); ++ grdev_display *grdev; ++ uint32_t width; ++ uint32_t height; ++}; ++ ++int display_new(Display **out, Session *s, grdev_display *grdev); ++Display *display_free(Display *d); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Display*, display_free); ++ ++void display_refresh(Display *d); ++void display_render(Display *d, Workspace *w); ++ ++/* ++ * Sessions ++ */ ++ ++struct Session { ++ Manager *manager; ++ sysview_session *sysview; ++ grdev_session *grdev; ++ idev_session *idev; ++ ++ LIST_FIELDS(Session, sessions_by_workspace); ++ Workspace *my_ws; ++ Workspace *active_ws; ++ ++ LIST_HEAD(Display, display_list); ++ sd_event_source *redraw_src; ++}; ++ ++int session_new(Session **out, Manager *m, sysview_session *session); ++Session *session_free(Session *s); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Session*, session_free); ++ ++void session_dirty(Session *s); ++ ++void session_add_device(Session *s, sysview_device *device); ++void session_remove_device(Session *s, sysview_device *device); ++void session_refresh_device(Session *s, sysview_device *device, struct udev_device *ud); ++ ++/* ++ * Managers ++ */ ++ ++struct Manager { ++ sd_event *event; ++ sd_bus *sysbus; ++ unifont *uf; ++ sysview_context *sysview; ++ grdev_context *grdev; ++ idev_context *idev; ++ LIST_HEAD(Workspace, workspace_list); ++}; ++ ++int manager_new(Manager **out); ++Manager *manager_free(Manager *m); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); ++ ++int manager_run(Manager *m); diff --git a/0495-man-use-more-markup-in-daemon-7.patch b/0495-man-use-more-markup-in-daemon-7.patch new file mode 100644 index 0000000..69884b3 --- /dev/null +++ b/0495-man-use-more-markup-in-daemon-7.patch @@ -0,0 +1,48 @@ +From 610158048a03f25be88a36cb7c81d11177a2c559 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 17:44:23 -0400 +Subject: [PATCH] man: use more markup in daemon(7) + +--- + man/daemon.xml | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/man/daemon.xml b/man/daemon.xml +index a23a04794b..99c75a7a18 100644 +--- a/man/daemon.xml ++++ b/man/daemon.xml +@@ -85,13 +85,14 @@ + with a fallback of iterating from file + descriptor 3 to the value returned by + getrlimit() for +- RLIMIT_NOFILE. ++ RLIMIT_NOFILE. ++ + + Reset all signal + handlers to their default. This is + best done by iterating through the + available signals up to the limit of +- _NSIG and resetting them to ++ _NSIG and resetting them to + SIG_DFL. + + Reset the signal mask +@@ -330,7 +331,7 @@ + init system. If log priorities are + necessary, these can be encoded by + prefixing individual log lines with +- strings like "<4>" (for log ++ strings like <4> (for log + priority 4 "WARNING" in the syslog + priority scheme), following a similar + style as the Linux kernel's +@@ -610,7 +611,7 @@ + on a network interface, because network + sockets shall be bound to the + address. However, an alternative to implement +- this is by utilizing the Linux IP_FREEBIND ++ this is by utilizing the Linux IP_FREEBIND + socket option, as accessible via + FreeBind=yes in systemd + socket files (see diff --git a/0496-sd-event-check-the-value-of-received-signal.patch b/0496-sd-event-check-the-value-of-received-signal.patch new file mode 100644 index 0000000..32b4897 --- /dev/null +++ b/0496-sd-event-check-the-value-of-received-signal.patch @@ -0,0 +1,43 @@ +From 7057bd993110c1eff0cd3a8776902ca66417634e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 18:49:45 -0400 +Subject: [PATCH] sd-event: check the value of received signal + +Appease coverity report #1237775. + +Also rename ss to n, to make it visually different from ss. +--- + src/libsystemd/sd-event/sd-event.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index b56182dda7..4c67ee87e1 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -1973,20 +1973,22 @@ static int process_signal(sd_event *e, uint32_t events) { + + for (;;) { + struct signalfd_siginfo si; +- ssize_t ss; ++ ssize_t n; + sd_event_source *s = NULL; + +- ss = read(e->signal_fd, &si, sizeof(si)); +- if (ss < 0) { ++ n = read(e->signal_fd, &si, sizeof(si)); ++ if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + return read_one; + + return -errno; + } + +- if (_unlikely_(ss != sizeof(si))) ++ if (_unlikely_(n != sizeof(si))) + return -EIO; + ++ assert(si.ssi_signo < _NSIG); ++ + read_one = true; + + if (si.ssi_signo == SIGCHLD) { diff --git a/0497-core-namespace-remove-invalid-check.patch b/0497-core-namespace-remove-invalid-check.patch new file mode 100644 index 0000000..19c56a7 --- /dev/null +++ b/0497-core-namespace-remove-invalid-check.patch @@ -0,0 +1,30 @@ +From 1775f1ebc4a8e9e0e2e4a9af3e97e1408c9cb335 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 19:16:11 -0400 +Subject: [PATCH] core/namespace: remove invalid check + +root cannot be NULL here, because it was allocated with alloca. + +CID #1237769. +--- + src/core/namespace.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/core/namespace.c b/src/core/namespace.c +index f76d3891c3..f86092f6b1 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -341,11 +341,8 @@ fail: + unlink(busnode); + } + +- if (root) { +- umount(root); +- rmdir(root); +- } +- ++ umount(root); ++ rmdir(root); + rmdir(temporary_mount); + + return r; diff --git a/0498-core-namespace-remove-invalid-check.patch b/0498-core-namespace-remove-invalid-check.patch new file mode 100644 index 0000000..0b6ea39 --- /dev/null +++ b/0498-core-namespace-remove-invalid-check.patch @@ -0,0 +1,30 @@ +From d267c5aa3d0fe4960165a1e1c00a840eef8b7d00 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 19:17:56 -0400 +Subject: [PATCH] core/namespace: remove invalid check + +dir cannot be NULL here, because it was allocated with alloca. + +CID #1237768. +--- + src/core/namespace.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/core/namespace.c b/src/core/namespace.c +index f86092f6b1..c2215090a9 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -263,11 +263,8 @@ fail: + if (devmqueue) + umount(devmqueue); + +- if (dev) { +- umount(dev); +- rmdir(dev); +- } +- ++ umount(dev); ++ rmdir(dev); + rmdir(temporary_mount); + + return r; diff --git a/0499-sd-bus-split-out-cleanup-into-separate-function.patch b/0499-sd-bus-split-out-cleanup-into-separate-function.patch new file mode 100644 index 0000000..3daad45 --- /dev/null +++ b/0499-sd-bus-split-out-cleanup-into-separate-function.patch @@ -0,0 +1,53 @@ +From 125dd07483b6836106ff9ad3ce1737d8a6c56c59 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 19:47:47 -0400 +Subject: [PATCH] sd-bus: split out cleanup into separate function + +m is always non-null at this point. This function is too long anyway. +--- + src/libsystemd/sd-bus/bus-kernel.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 0c39e22ed7..09ff25fe71 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -332,6 +332,18 @@ fail: + return r; + } + ++static void unset_memfds(struct sd_bus_message *m) { ++ struct bus_body_part *part; ++ unsigned i; ++ ++ assert(m); ++ ++ /* Make sure the memfds are not freed twice */ ++ MESSAGE_FOREACH_PART(part, i, m) ++ if (part->memfd >= 0) ++ part->memfd = -1; ++} ++ + static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { + sd_bus_message *m = NULL; + struct kdbus_item *d; +@@ -627,17 +639,8 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { + return 1; + + fail: +- if (m) { +- struct bus_body_part *part; +- unsigned i; +- +- /* Make sure the memfds are not freed twice */ +- MESSAGE_FOREACH_PART(part, i, m) +- if (part->memfd >= 0) +- part->memfd = -1; +- +- sd_bus_message_unref(m); +- } ++ unset_memfds(m); ++ sd_bus_message_unref(m); + + return r; + } diff --git a/0500-fstab-generator-Small-cleanup.patch b/0500-fstab-generator-Small-cleanup.patch new file mode 100644 index 0000000..4da1f6e --- /dev/null +++ b/0500-fstab-generator-Small-cleanup.patch @@ -0,0 +1,32 @@ +From f88dc3edeb9c49622fcc773cb6153238fe9efbe2 Mon Sep 17 00:00:00 2001 +From: Tobias Hunger +Date: Fri, 3 Oct 2014 20:41:43 -0400 +Subject: [PATCH] fstab-generator: Small cleanup + +--- + src/fstab-generator/fstab-generator.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c +index 5dafcba3c0..b75bbb7998 100644 +--- a/src/fstab-generator/fstab-generator.c ++++ b/src/fstab-generator/fstab-generator.c +@@ -511,16 +511,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { + + } else if (streq(key, "root") && value) { + +- free(arg_root_what); +- arg_root_what = strdup(value); +- if (!arg_root_what) ++ if (free_and_strdup(&arg_root_what, value) < 0) + return log_oom(); + + } else if (streq(key, "rootfstype") && value) { + +- free(arg_root_fstype); +- arg_root_fstype = strdup(value); +- if (!arg_root_fstype) ++ if (free_and_strdup(&arg_root_fstype, value) < 0) + return log_oom(); + + } else if (streq(key, "rootflags") && value) { diff --git a/0501-sd-id128-do-stricter-checking-of-random-boot-id.patch b/0501-sd-id128-do-stricter-checking-of-random-boot-id.patch new file mode 100644 index 0000000..7339f71 --- /dev/null +++ b/0501-sd-id128-do-stricter-checking-of-random-boot-id.patch @@ -0,0 +1,34 @@ +From cef3566998fcae6936d781e678c309950a8a5787 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 20:57:30 -0400 +Subject: [PATCH] sd-id128: do stricter checking of random boot id + +If we are bothering to check whether the kernel is not feeding us +bad data, we might as well do it properly. + +CID #1237692. +--- + src/libsystemd/sd-id128/sd-id128.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c +index a1e44e6d19..233ffa070b 100644 +--- a/src/libsystemd/sd-id128/sd-id128.c ++++ b/src/libsystemd/sd-id128/sd-id128.c +@@ -183,11 +183,14 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) { + for (j = 0, p = buf; j < 16; j++) { + int a, b; + +- if (p >= buf + k) ++ if (p >= buf + k - 1) + return -EIO; + +- if (*p == '-') ++ if (*p == '-') { + p++; ++ if (p >= buf + k - 1) ++ return -EIO; ++ } + + a = unhexchar(p[0]); + b = unhexchar(p[1]); diff --git a/0502-man-say-that-SecureBits-are-space-separated.patch b/0502-man-say-that-SecureBits-are-space-separated.patch new file mode 100644 index 0000000..a9e2b11 --- /dev/null +++ b/0502-man-say-that-SecureBits-are-space-separated.patch @@ -0,0 +1,53 @@ +From e060073a8f05cfdfad621b1bb59abe944b17d5f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 21:06:52 -0400 +Subject: [PATCH] man: say that SecureBits= are space separated + +--- + man/systemd.exec.xml | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 6d0113f5cc..939983fb7e 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -776,20 +776,22 @@ + + SecureBits= + Controls the secure +- bits set for the executed process. See +- capabilities7 +- for details. Takes a list of strings: ++ bits set for the executed process. ++ Takes a space-separated combination of ++ options from the following list: + , + , + , + , +- and/or ++ , and + . This + option may appear more than once in +- which case the secure bits are +- ORed. If the empty string is assigned +- to this option, the bits are reset to +- 0. ++ which case the secure bits are ORed. ++ If the empty string is assigned to ++ this option, the bits are reset to 0. ++ See capabilities7 ++ for details. + + + +@@ -806,7 +808,7 @@ + attached to the executed file. Due to + that + CapabilityBoundingSet= +- is probably the much more useful ++ is probably a much more useful + setting. + + diff --git a/0503-build-sys-fix-make-distcheck.patch b/0503-build-sys-fix-make-distcheck.patch new file mode 100644 index 0000000..461b2a5 --- /dev/null +++ b/0503-build-sys-fix-make-distcheck.patch @@ -0,0 +1,23 @@ +From f45d32872cb65530b6c7b4818c40e917b44b2633 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 3 Oct 2014 22:08:23 -0400 +Subject: [PATCH] build-sys: fix make distcheck + +--- + Makefile.am | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 60011b7d98..cca949feff 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -712,7 +712,8 @@ man/systemd.directives.xml: $(top_srcdir)/tools/make-directive-index.py $(SOURCE + EXTRA_DIST += \ + man/systemd.index.xml \ + man/index.html \ +- man/systemd.directives.xml ++ man/systemd.directives.xml \ ++ man/glib-event-glue.c + + CLEANFILES += \ + man/systemd.index.xml \ diff --git a/0504-systemd-bus-proxyd-distribute-the-.in-file-also-for-.patch b/0504-systemd-bus-proxyd-distribute-the-.in-file-also-for-.patch new file mode 100644 index 0000000..4734f55 --- /dev/null +++ b/0504-systemd-bus-proxyd-distribute-the-.in-file-also-for-.patch @@ -0,0 +1,34 @@ +From c71202228f31176eee2aa7c798c9f3ff681cf957 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 4 Oct 2014 13:11:40 +0200 +Subject: [PATCH] systemd-bus-proxyd: distribute the .in file also for the user + version + +--- + Makefile.am | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index cca949feff..d2a1767265 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2477,13 +2477,16 @@ nodist_systemunit_DATA += \ + dist_systemunit_DATA += \ + units/systemd-bus-proxyd.socket + +-dist_userunit_DATA += \ +- units/user/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.in ++ units/systemd-bus-proxyd@.service.in \ ++ units/user/systemd-bus-proxyd@.service.in + + # ------------------------------------------------------------------------------ + systemd_tty_ask_password_agent_SOURCES = \ diff --git a/0505-consoled-move-from-bin-to-lib-systemd.patch b/0505-consoled-move-from-bin-to-lib-systemd.patch new file mode 100644 index 0000000..f866d69 --- /dev/null +++ b/0505-consoled-move-from-bin-to-lib-systemd.patch @@ -0,0 +1,23 @@ +From 10595afb4c007a764b91d28ede5faa00bcb28428 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 4 Oct 2014 13:12:49 +0200 +Subject: [PATCH] consoled: move from /bin to /lib/systemd + +This should not normally be run manually, but rather through systemd. +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index d2a1767265..3119a95dad 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3024,7 +3024,7 @@ if ENABLE_TERMINAL + noinst_LTLIBRARIES += \ + libsystemd-terminal.la + +-bin_PROGRAMS += \ ++rootlibexec_PROGRAMS += \ + systemd-consoled + + noinst_PROGRAMS += \ diff --git a/0506-consoled-add-a-unit-file.patch b/0506-consoled-add-a-unit-file.patch new file mode 100644 index 0000000..9e20f73 --- /dev/null +++ b/0506-consoled-add-a-unit-file.patch @@ -0,0 +1,79 @@ +From 2355af60dc0c0ec2b7fbe69f15a77d980b017b3f Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 4 Oct 2014 13:10:41 +0200 +Subject: [PATCH] consoled: add a unit file + +The unit file is statically enabled, but still requires --enable-terminal +to actually get installed. +--- + Makefile.am | 11 +++++++++++ + units/user/.gitignore | 1 + + units/user/systemd-consoled.service.in | 15 +++++++++++++++ + 3 files changed, 27 insertions(+) + create mode 100644 units/user/systemd-consoled.service.in + +diff --git a/Makefile.am b/Makefile.am +index 3119a95dad..e52db1793b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -250,6 +250,7 @@ SOCKETS_TARGET_WANTS = + BUSNAMES_TARGET_WANTS = + TIMERS_TARGET_WANTS = + USER_SOCKETS_TARGET_WANTS = ++USER_DEFAULT_TARGET_WANTS = + USER_BUSNAMES_TARGET_WANTS = + + SYSTEM_UNIT_ALIASES = +@@ -270,6 +271,7 @@ install-target-wants-hook: + what="$(TIMERS_TARGET_WANTS)" && wants=timers.target && dir=$(systemunitdir) && $(add-wants) + what="$(SLICES_TARGET_WANTS)" && wants=slices.target && dir=$(systemunitdir) && $(add-wants) + what="$(USER_SOCKETS_TARGET_WANTS)" && wants=sockets.target && dir=$(userunitdir) && $(add-wants) ++ what="$(USER_DEFAULT_TARGET_WANTS)" && wants=default.target && dir=$(userunitdir) && $(add-wants) + + install-busnames-target-wants-hook: + what="$(BUSNAMES_TARGET_WANTS)" && wants=busnames.target && dir=$(systemunitdir) && $(add-wants) +@@ -3035,6 +3037,15 @@ noinst_PROGRAMS += \ + dist_pkgdata_DATA += \ + src/libsystemd-terminal/unifont-glyph-array.bin + ++nodist_userunit_DATA += \ ++ units/user/systemd-consoled.service ++ ++USER_DEFAULT_TARGET_WANTS += \ ++ systemd-consoled.service ++ ++EXTRA_DIST += \ ++ units/user/systemd-consoled.service.in ++ + tests += \ + test-term-page \ + test-term-parser \ +diff --git a/units/user/.gitignore b/units/user/.gitignore +index 6aa54754cb..c91ed626c8 100644 +--- a/units/user/.gitignore ++++ b/units/user/.gitignore +@@ -1,2 +1,3 @@ + /systemd-exit.service + /systemd-bus-proxyd@.service ++/systemd-consoled.service +diff --git a/units/user/systemd-consoled.service.in b/units/user/systemd-consoled.service.in +new file mode 100644 +index 0000000000..fd7938aa8b +--- /dev/null ++++ b/units/user/systemd-consoled.service.in +@@ -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=Console Manager and Terminal Emulator ++ ++[Service] ++Type=notify ++Restart=always ++RestartSec=0 ++ExecStart=@rootlibexecdir@/systemd-consoled diff --git a/0507-test-only-use-assert_se.patch b/0507-test-only-use-assert_se.patch new file mode 100644 index 0000000..471d667 --- /dev/null +++ b/0507-test-only-use-assert_se.patch @@ -0,0 +1,845 @@ +From bdf7026e9557349cd3eeb291c01655d5f2a55db8 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sat, 4 Oct 2014 23:51:45 +0200 +Subject: [PATCH] test: only use assert_se + +The asserts used in the tests should never be allowed to be +optimized away +--- + src/test/test-cgroup-mask.c | 68 ++++++++++++++++++++++----------------------- + src/test/test-cgroup.c | 12 ++++---- + src/test/test-engine.c | 4 +-- + src/test/test-fileio.c | 14 +++++----- + src/test/test-hashmap.c | 2 +- + src/test/test-install.c | 2 +- + src/test/test-job-type.c | 22 +++++++-------- + src/test/test-libudev.c | 2 +- + src/test/test-sched-prio.c | 2 +- + src/test/test-set.c | 2 +- + src/test/test-socket-util.c | 8 +++--- + src/test/test-strbuf.c | 54 +++++++++++++++++------------------ + src/test/test-strv.c | 10 +++---- + src/test/test-strxcpyx.c | 20 ++++++------- + src/test/test-tmpfiles.c | 4 +-- + src/test/test-unit-file.c | 52 +++++++++++++++++----------------- + src/test/test-unit-name.c | 12 ++++---- + src/test/test-util.c | 48 ++++++++++++++++---------------- + 18 files changed, 169 insertions(+), 169 deletions(-) + +diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c +index f98e1bb174..9e9de23e0e 100644 +--- a/src/test/test-cgroup-mask.c ++++ b/src/test/test-cgroup-mask.c +@@ -45,7 +45,7 @@ static int test_cgroup_mask(void) { + puts("manager_new: Permission denied. Skipping test."); + return EXIT_TEST_SKIP; + } +- assert(r >= 0); ++ assert_se(r >= 0); + assert_se(manager_startup(m, serial, fdset) >= 0); + + /* Load units and verify hierarchy. */ +@@ -54,48 +54,48 @@ static int test_cgroup_mask(void) { + assert_se(manager_load_unit(m, "daughter.service", NULL, NULL, &daughter) >= 0); + assert_se(manager_load_unit(m, "grandchild.service", NULL, NULL, &grandchild) >= 0); + assert_se(manager_load_unit(m, "parent-deep.slice", NULL, NULL, &parent_deep) >= 0); +- assert(parent->load_state == UNIT_LOADED); +- assert(son->load_state == UNIT_LOADED); +- assert(daughter->load_state == UNIT_LOADED); +- assert(grandchild->load_state == UNIT_LOADED); +- assert(parent_deep->load_state == UNIT_LOADED); +- assert(UNIT_DEREF(son->slice) == parent); +- assert(UNIT_DEREF(daughter->slice) == parent); +- assert(UNIT_DEREF(parent_deep->slice) == parent); +- assert(UNIT_DEREF(grandchild->slice) == parent_deep); ++ assert_se(parent->load_state == UNIT_LOADED); ++ assert_se(son->load_state == UNIT_LOADED); ++ assert_se(daughter->load_state == UNIT_LOADED); ++ assert_se(grandchild->load_state == UNIT_LOADED); ++ assert_se(parent_deep->load_state == UNIT_LOADED); ++ assert_se(UNIT_DEREF(son->slice) == parent); ++ assert_se(UNIT_DEREF(daughter->slice) == parent); ++ assert_se(UNIT_DEREF(parent_deep->slice) == parent); ++ assert_se(UNIT_DEREF(grandchild->slice) == parent_deep); + root = UNIT_DEREF(parent->slice); + + /* Verify per-unit cgroups settings. */ +- assert(unit_get_cgroup_mask(son) == (CGROUP_CPU | CGROUP_CPUACCT)); +- assert(unit_get_cgroup_mask(daughter) == 0); +- assert(unit_get_cgroup_mask(grandchild) == 0); +- assert(unit_get_cgroup_mask(parent_deep) == CGROUP_MEMORY); +- assert(unit_get_cgroup_mask(parent) == CGROUP_BLKIO); +- assert(unit_get_cgroup_mask(root) == 0); ++ assert_se(unit_get_cgroup_mask(son) == (CGROUP_CPU | CGROUP_CPUACCT)); ++ assert_se(unit_get_cgroup_mask(daughter) == 0); ++ assert_se(unit_get_cgroup_mask(grandchild) == 0); ++ assert_se(unit_get_cgroup_mask(parent_deep) == CGROUP_MEMORY); ++ assert_se(unit_get_cgroup_mask(parent) == CGROUP_BLKIO); ++ assert_se(unit_get_cgroup_mask(root) == 0); + + /* Verify aggregation of member masks */ +- assert(unit_get_members_mask(son) == 0); +- assert(unit_get_members_mask(daughter) == 0); +- assert(unit_get_members_mask(grandchild) == 0); +- assert(unit_get_members_mask(parent_deep) == 0); +- assert(unit_get_members_mask(parent) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); +- assert(unit_get_members_mask(root) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); ++ assert_se(unit_get_members_mask(son) == 0); ++ assert_se(unit_get_members_mask(daughter) == 0); ++ assert_se(unit_get_members_mask(grandchild) == 0); ++ assert_se(unit_get_members_mask(parent_deep) == 0); ++ assert_se(unit_get_members_mask(parent) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); ++ assert_se(unit_get_members_mask(root) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); + + /* Verify aggregation of sibling masks. */ +- assert(unit_get_siblings_mask(son) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_siblings_mask(daughter) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_siblings_mask(grandchild) == 0); +- assert(unit_get_siblings_mask(parent_deep) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_siblings_mask(parent) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_siblings_mask(root) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_siblings_mask(son) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_siblings_mask(daughter) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_siblings_mask(grandchild) == 0); ++ assert_se(unit_get_siblings_mask(parent_deep) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_siblings_mask(parent) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_siblings_mask(root) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); + + /* Verify aggregation of target masks. */ +- assert(unit_get_target_mask(son) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_target_mask(daughter) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_target_mask(grandchild) == 0); +- assert(unit_get_target_mask(parent_deep) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_target_mask(parent) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); +- assert(unit_get_target_mask(root) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_target_mask(son) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_target_mask(daughter) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_target_mask(grandchild) == 0); ++ assert_se(unit_get_target_mask(parent_deep) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_target_mask(parent) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); ++ assert_se(unit_get_target_mask(root) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); + + manager_free(m); + +diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c +index 2a0ce27206..46642f92fe 100644 +--- a/src/test/test-cgroup.c ++++ b/src/test/test-cgroup.c +@@ -79,8 +79,8 @@ int main(int argc, char*argv[]) { + assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-a") >= 0); + + assert_se(cg_split_spec("foobar:/", &c, &p) == 0); +- assert(streq(c, "foobar")); +- assert(streq(p, "/")); ++ assert_se(streq(c, "foobar")); ++ assert_se(streq(p, "/")); + free(c); + free(p); + +@@ -92,13 +92,13 @@ int main(int argc, char*argv[]) { + assert_se(cg_split_spec("fo/obar:/", &c, &p) < 0); + + assert_se(cg_split_spec("/", &c, &p) >= 0); +- assert(c == NULL); +- assert(streq(p, "/")); ++ assert_se(c == NULL); ++ assert_se(streq(p, "/")); + free(p); + + assert_se(cg_split_spec("foo", &c, &p) >= 0); +- assert(streq(c, "foo")); +- assert(p == NULL); ++ assert_se(streq(c, "foo")); ++ assert_se(p == NULL); + free(c); + + return 0; +diff --git a/src/test/test-engine.c b/src/test/test-engine.c +index 6e39a586c0..1b71416a04 100644 +--- a/src/test/test-engine.c ++++ b/src/test/test-engine.c +@@ -43,7 +43,7 @@ int main(int argc, char *argv[]) { + printf("Skipping test: manager_new: %s", strerror(-r)); + return EXIT_TEST_SKIP; + } +- assert(r >= 0); ++ assert_se(r >= 0); + assert_se(manager_startup(m, serial, fdset) >= 0); + + printf("Load1:\n"); +@@ -56,7 +56,7 @@ int main(int argc, char *argv[]) { + r = manager_add_job(m, JOB_START, c, JOB_REPLACE, false, &err, &j); + if (sd_bus_error_is_set(&err)) + log_error("error: %s: %s", err.name, err.message); +- assert(r == 0); ++ assert_se(r == 0); + manager_dump_jobs(m, stdout, "\t"); + + printf("Load2:\n"); +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index ad65abf426..76a9e8e9c9 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -246,25 +246,25 @@ static void test_status_field(void) { + + r = get_status_field("/proc/meminfo", "MemTotal:", &p); + if (r != -ENOENT) { +- assert(r == 0); ++ assert_se(r == 0); + puts(p); + assert_se(safe_atollu(p, &total) == 0); + } + + r = get_status_field("/proc/meminfo", "\nBuffers:", &s); + if (r != -ENOENT) { +- assert(r == 0); ++ assert_se(r == 0); + puts(s); + assert_se(safe_atollu(s, &buffers) == 0); + } + + if (p) +- assert(buffers < total); ++ assert_se(buffers < total); + + /* Seccomp should be a good test for field full of zeros. */ + r = get_status_field("/proc/meminfo", "\nSeccomp:", &z); + if (r != -ENOENT) { +- assert(r == 0); ++ assert_se(r == 0); + puts(z); + assert_se(safe_atollu(z, &buffers) == 0); + } +@@ -283,10 +283,10 @@ static void test_capeff(void) { + if (r == -ENOENT || r == -EPERM) + return; + +- assert(r == 0); +- assert(*capeff); ++ assert_se(r == 0); ++ assert_se(*capeff); + p = capeff[strspn(capeff, DIGITS "abcdefABCDEF")]; +- assert(!p || isspace(p)); ++ assert_se(!p || isspace(p)); + } + } + +diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c +index f4afbb8e9d..f9072061dd 100644 +--- a/src/test/test-hashmap.c ++++ b/src/test/test-hashmap.c +@@ -522,7 +522,7 @@ static void test_hashmap_steal_first(void) { + while ((val = hashmap_steal_first(m))) + seen[strlen(val) - 1]++; + +- assert(seen[0] == 1 && seen[1] == 1 && seen[2] == 1); ++ assert_se(seen[0] == 1 && seen[1] == 1 && seen[2] == 1); + + assert_se(hashmap_isempty(m)); + } +diff --git a/src/test/test-install.c b/src/test/test-install.c +index b0f77a18f3..467970b007 100644 +--- a/src/test/test-install.c ++++ b/src/test/test-install.c +@@ -31,7 +31,7 @@ + static void dump_changes(UnitFileChange *c, unsigned n) { + unsigned i; + +- assert(n == 0 || c); ++ assert_se(n == 0 || c); + + for (i = 0; i < n; i++) { + if (c[i].type == UNIT_FILE_UNLINK) +diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c +index 1066374436..1d9d49b228 100644 +--- a/src/test/test-job-type.c ++++ b/src/test/test-job-type.c +@@ -52,29 +52,29 @@ int main(int argc, char*argv[]) { + merged_ab = (job_type_merge_and_collapse(&ab, b, u) >= 0); + + if (!job_type_is_mergeable(a, b)) { +- assert(!merged_ab); ++ assert_se(!merged_ab); + printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b)); + continue; + } + +- assert(merged_ab); ++ assert_se(merged_ab); + printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(ab)); + + for (c = 0; c < _JOB_TYPE_MAX_MERGING; c++) { + + /* Verify transitivity of mergeability of job types */ +- assert(!job_type_is_mergeable(a, b) || ++ assert_se(!job_type_is_mergeable(a, b) || + !job_type_is_mergeable(b, c) || + job_type_is_mergeable(a, c)); + + /* Verify that merged entries can be merged with the same entries + * they can be merged with separately */ +- assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(ab, c)); +- assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(ab, c)); ++ assert_se(!job_type_is_mergeable(a, c) || job_type_is_mergeable(ab, c)); ++ assert_se(!job_type_is_mergeable(b, c) || job_type_is_mergeable(ab, c)); + + /* Verify that if a merged with b is not mergeable with c, then + * either a or b is not mergeable with c either. */ +- assert(job_type_is_mergeable(ab, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c)); ++ assert_se(job_type_is_mergeable(ab, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c)); + + bc = b; + if (job_type_merge_and_collapse(&bc, c, u) >= 0) { +@@ -82,16 +82,16 @@ int main(int argc, char*argv[]) { + /* Verify associativity */ + + ab_c = ab; +- assert(job_type_merge_and_collapse(&ab_c, c, u) == 0); ++ assert_se(job_type_merge_and_collapse(&ab_c, c, u) == 0); + + bc_a = bc; +- assert(job_type_merge_and_collapse(&bc_a, a, u) == 0); ++ assert_se(job_type_merge_and_collapse(&bc_a, a, u) == 0); + + a_bc = a; +- assert(job_type_merge_and_collapse(&a_bc, bc, u) == 0); ++ assert_se(job_type_merge_and_collapse(&a_bc, bc, u) == 0); + +- assert(ab_c == bc_a); +- assert(ab_c == a_bc); ++ assert_se(ab_c == bc_a); ++ assert_se(ab_c == a_bc); + + printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(ab_c)); + } +diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c +index ea190990eb..a51814df95 100644 +--- a/src/test/test-libudev.c ++++ b/src/test/test-libudev.c +@@ -407,7 +407,7 @@ static void test_hwdb(struct udev *udev, const char *modalias) { + printf("\n"); + + hwdb = udev_hwdb_unref(hwdb); +- assert(hwdb == NULL); ++ assert_se(hwdb == NULL); + } + + int main(int argc, char *argv[]) { +diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c +index 8fdca0ea23..2f559b0413 100644 +--- a/src/test/test-sched-prio.c ++++ b/src/test/test-sched-prio.c +@@ -39,7 +39,7 @@ int main(int argc, char *argv[]) { + printf("Skipping test: manager_new: %s", strerror(-r)); + return EXIT_TEST_SKIP; + } +- assert(r >= 0); ++ assert_se(r >= 0); + assert_se(manager_startup(m, serial, fdset) >= 0); + + /* load idle ok */ +diff --git a/src/test/test-set.c b/src/test/test-set.c +index 060dba42df..e280c8952d 100644 +--- a/src/test/test-set.c ++++ b/src/test/test-set.c +@@ -35,7 +35,7 @@ static void test_set_steal_first(void) { + while ((val = set_steal_first(m))) + seen[strlen(val) - 1]++; + +- assert(seen[0] == 1 && seen[1] == 1 && seen[2] == 1); ++ assert_se(seen[0] == 1 && seen[1] == 1 && seen[2] == 1); + + assert_se(set_isempty(m)); + } +diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c +index 17180db652..c2c728bcde 100644 +--- a/src/test/test-socket-util.c ++++ b/src/test/test-socket-util.c +@@ -236,7 +236,7 @@ static void *connect_thread(void *arg) { + _cleanup_close_ int fd = -1; + + fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); +- assert(fd >= 0); ++ assert_se(fd >= 0); + + assert_se(connect(fd, &sa->sa, sizeof(sa->in)) == 0); + +@@ -263,7 +263,7 @@ static void test_nameinfo_pretty(void) { + assert_se(r < 0); + + sfd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0); +- assert(sfd >= 0); ++ assert_se(sfd >= 0); + + assert_se(bind(sfd, &s.sa, sizeof(s.in)) == 0); + +@@ -276,11 +276,11 @@ static void test_nameinfo_pretty(void) { + + log_debug("Accepting new connection on fd:%d", sfd); + cfd = accept4(sfd, &c.sa, &clen, SOCK_CLOEXEC); +- assert(cfd >= 0); ++ assert_se(cfd >= 0); + + r = getnameinfo_pretty(cfd, &localhost); + log_info("Connection from %s", localhost); +- assert(r == 0); ++ assert_se(r == 0); + } + + static void test_sockaddr_equal(void) { +diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c +index 3334e0bf6c..43cb92b74b 100644 +--- a/src/test/test-strbuf.c ++++ b/src/test/test-strbuf.c +@@ -48,39 +48,39 @@ static void test_strbuf(void) { + /* check the content of the buffer directly */ + l = strv_parse_nulstr(sb->buf, sb->len); + +- assert(streq(l[0], "")); /* root*/ +- assert(streq(l[1], "waldo")); +- assert(streq(l[2], "foo")); +- assert(streq(l[3], "bar")); +- assert(streq(l[4], "waldorf")); ++ assert_se(streq(l[0], "")); /* root*/ ++ assert_se(streq(l[1], "waldo")); ++ assert_se(streq(l[2], "foo")); ++ assert_se(streq(l[3], "bar")); ++ assert_se(streq(l[4], "waldorf")); + +- assert(sb->nodes_count == 5); /* root + 4 non-duplicates */ +- assert(sb->dedup_count == 3); +- assert(sb->in_count == 7); ++ assert_se(sb->nodes_count == 5); /* root + 4 non-duplicates */ ++ assert_se(sb->dedup_count == 3); ++ assert_se(sb->in_count == 7); + +- assert(sb->in_len == 29); /* length of all strings added */ +- assert(sb->dedup_len == 11); /* length of all strings duplicated */ +- assert(sb->len == 23); /* buffer length: in - dedup + \0 for each node */ ++ assert_se(sb->in_len == 29); /* length of all strings added */ ++ assert_se(sb->dedup_len == 11); /* length of all strings duplicated */ ++ assert_se(sb->len == 23); /* buffer length: in - dedup + \0 for each node */ + + /* check the returned offsets and the respective content in the buffer */ +- assert(a == 1); +- assert(b == 7); +- assert(c == 11); +- assert(d == 1); +- assert(e == 2); +- assert(f == 4); +- assert(g == 15); +- +- assert(streq(sb->buf + a, "waldo")); +- assert(streq(sb->buf + b, "foo")); +- assert(streq(sb->buf + c, "bar")); +- assert(streq(sb->buf + d, "waldo")); +- assert(streq(sb->buf + e, "aldo")); +- assert(streq(sb->buf + f, "do")); +- assert(streq(sb->buf + g, "waldorf")); ++ assert_se(a == 1); ++ assert_se(b == 7); ++ assert_se(c == 11); ++ assert_se(d == 1); ++ assert_se(e == 2); ++ assert_se(f == 4); ++ assert_se(g == 15); ++ ++ assert_se(streq(sb->buf + a, "waldo")); ++ assert_se(streq(sb->buf + b, "foo")); ++ assert_se(streq(sb->buf + c, "bar")); ++ assert_se(streq(sb->buf + d, "waldo")); ++ assert_se(streq(sb->buf + e, "aldo")); ++ assert_se(streq(sb->buf + f, "do")); ++ assert_se(streq(sb->buf + g, "waldorf")); + + strbuf_complete(sb); +- assert(sb->root == NULL); ++ assert_se(sb->root == NULL); + + strbuf_cleanup(sb); + } +diff --git a/src/test/test-strv.c b/src/test/test-strv.c +index 7ba4c366ac..bbfe306d7d 100644 +--- a/src/test/test-strv.c ++++ b/src/test/test-strv.c +@@ -170,7 +170,7 @@ static void test_strv_unquote(const char *quoted, const char **list) { + assert_se(r == 0); + assert_se(s); + j = strv_join(s, " | "); +- assert(j); ++ assert_se(j); + puts(j); + + STRV_FOREACH(t, s) +@@ -184,8 +184,8 @@ static void test_invalid_unquote(const char *quoted) { + int r; + + r = strv_split_quoted(&s, quoted); +- assert(s == NULL); +- assert(r == -EINVAL); ++ assert_se(s == NULL); ++ assert_se(r == -EINVAL); + } + + static void test_strv_split(void) { +@@ -196,7 +196,7 @@ static void test_strv_split(void) { + + l = strv_split(str, ","); + +- assert(l); ++ assert_se(l); + + STRV_FOREACH(s, l) { + assert_se(streq(*s, input_table_multiple[i++])); +@@ -211,7 +211,7 @@ static void test_strv_split_newlines(void) { + + l = strv_split_newlines(str); + +- assert(l); ++ assert_se(l); + + STRV_FOREACH(s, l) { + assert_se(streq(*s, input_table_multiple[i++])); +diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c +index b7b70d4c15..cb2309210f 100644 +--- a/src/test/test-strxcpyx.c ++++ b/src/test/test-strxcpyx.c +@@ -38,8 +38,8 @@ static void test_strpcpy(void) { + space_left = strpcpy(&s, space_left, "r"); + space_left = strpcpy(&s, space_left, "foo"); + +- assert(streq(target, "12345hey hey heywaldobar")); +- assert(space_left == 0); ++ assert_se(streq(target, "12345hey hey heywaldobar")); ++ assert_se(space_left == 0); + } + + static void test_strpcpyf(void) { +@@ -51,8 +51,8 @@ static void test_strpcpyf(void) { + space_left = strpcpyf(&s, space_left, "space left: %zd. ", space_left); + space_left = strpcpyf(&s, space_left, "foo%s", "bar"); + +- assert(streq(target, "space left: 25. foobar")); +- assert(space_left == 3); ++ assert_se(streq(target, "space left: 25. foobar")); ++ assert_se(space_left == 3); + } + + static void test_strpcpyl(void) { +@@ -64,8 +64,8 @@ static void test_strpcpyl(void) { + space_left = strpcpyl(&s, space_left, "waldo", " test", " waldo. ", NULL); + space_left = strpcpyl(&s, space_left, "Banana", NULL); + +- assert(streq(target, "waldo test waldo. Banana")); +- assert(space_left == 1); ++ assert_se(streq(target, "waldo test waldo. Banana")); ++ assert_se(space_left == 1); + } + + static void test_strscpy(void) { +@@ -75,8 +75,8 @@ static void test_strscpy(void) { + space_left = sizeof(target); + space_left = strscpy(target, space_left, "12345"); + +- assert(streq(target, "12345")); +- assert(space_left == 20); ++ assert_se(streq(target, "12345")); ++ assert_se(space_left == 20); + } + + static void test_strscpyl(void) { +@@ -86,8 +86,8 @@ static void test_strscpyl(void) { + space_left = sizeof(target); + space_left = strscpyl(target, space_left, "12345", "waldo", "waldo", NULL); + +- assert(streq(target, "12345waldowaldo")); +- assert(space_left == 10); ++ assert_se(streq(target, "12345waldowaldo")); ++ assert_se(space_left == 10); + } + + int main(int argc, char *argv[]) { +diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c +index 565f0f8b40..84050c6fa4 100644 +--- a/src/test/test-tmpfiles.c ++++ b/src/test/test-tmpfiles.c +@@ -35,13 +35,13 @@ int main(int argc, char** argv) { + _cleanup_free_ char *cmd, *cmd2; + + fd = open_tmpfile(p, O_RDWR|O_CLOEXEC); +- assert(fd >= 0); ++ assert_se(fd >= 0); + + assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0); + system(cmd); + + fd2 = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC); +- assert(fd >= 0); ++ assert_se(fd >= 0); + assert_se(unlink(pattern) == 0); + + assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 89f5bdd4ed..03b3e25939 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -45,7 +45,7 @@ static int test_unit_file_get_set(void) { + UnitFileList *p; + + h = hashmap_new(&string_hash_ops); +- assert(h); ++ assert_se(h); + + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + +@@ -231,18 +231,18 @@ static void test_load_env_file_1(void) { + _cleanup_close_ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); +- assert(fd >= 0); ++ assert_se(fd >= 0); + assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1)); + + r = load_env_file(NULL, name, NULL, &data); +- assert(r == 0); +- assert(streq(data[0], "a=a")); +- assert(streq(data[1], "b=bc")); +- assert(streq(data[2], "d=def")); +- assert(streq(data[3], "g=g ")); +- assert(streq(data[4], "h=h")); +- assert(streq(data[5], "i=i")); +- assert(data[6] == NULL); ++ assert_se(r == 0); ++ assert_se(streq(data[0], "a=a")); ++ assert_se(streq(data[1], "b=bc")); ++ assert_se(streq(data[2], "d=def")); ++ assert_se(streq(data[3], "g=g ")); ++ assert_se(streq(data[4], "h=h")); ++ assert_se(streq(data[5], "i=i")); ++ assert_se(data[6] == NULL); + unlink(name); + } + +@@ -254,13 +254,13 @@ static void test_load_env_file_2(void) { + _cleanup_close_ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); +- assert(fd >= 0); ++ assert_se(fd >= 0); + assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2)); + + r = load_env_file(NULL, name, NULL, &data); +- assert(r == 0); +- assert(streq(data[0], "a=a")); +- assert(data[1] == NULL); ++ assert_se(r == 0); ++ assert_se(streq(data[0], "a=a")); ++ assert_se(data[1] == NULL); + unlink(name); + } + +@@ -272,12 +272,12 @@ static void test_load_env_file_3(void) { + _cleanup_close_ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); +- assert(fd >= 0); ++ assert_se(fd >= 0); + assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3)); + + r = load_env_file(NULL, name, NULL, &data); +- assert(r == 0); +- assert(data == NULL); ++ assert_se(r == 0); ++ assert_se(data == NULL); + unlink(name); + } + +@@ -288,15 +288,15 @@ static void test_load_env_file_4(void) { + int r; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); +- assert(fd >= 0); ++ assert_se(fd >= 0); + assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4)); + + r = load_env_file(NULL, name, NULL, &data); +- assert(r == 0); +- assert(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); +- assert(streq(data[1], "MODULE_0=coretemp")); +- assert(streq(data[2], "MODULE_1=f71882fg")); +- assert(data[3] == NULL); ++ assert_se(r == 0); ++ assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); ++ assert_se(streq(data[1], "MODULE_0=coretemp")); ++ assert_se(streq(data[2], "MODULE_1=f71882fg")); ++ assert_se(data[3] == NULL); + unlink(name); + } + +@@ -329,11 +329,11 @@ static void test_install_printf(void) { + memzero(i.name, strlen(i.name)); \ + memzero(i.path, strlen(i.path)); \ + memzero(i.user, strlen(i.user)); \ +- assert(d1 && d2 && d3); \ ++ assert_se(d1 && d2 && d3); \ + if (result) { \ + printf("%s\n", t); \ +- assert(streq(t, result)); \ +- } else assert(t == NULL); \ ++ assert_se(streq(t, result)); \ ++ } else assert_se(t == NULL); \ + strcpy(i.name, d1); \ + strcpy(i.path, d2); \ + strcpy(i.user, d3); \ +diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c +index b733173742..256e820c22 100644 +--- a/src/test/test-unit-name.c ++++ b/src/test/test-unit-name.c +@@ -43,7 +43,7 @@ static void test_replacements(void) { + _cleanup_free_ char *t = \ + unit_name_replace_instance(pattern, repl); \ + puts(t); \ +- assert(streq(t, expected)); \ ++ assert_se(streq(t, expected)); \ + } + + expect("foo@.service", "waldo", "foo@waldo.service"); +@@ -64,7 +64,7 @@ static void test_replacements(void) { + puts(t); \ + k = unit_name_to_path(t); \ + puts(k); \ +- assert(streq(k, expected ? expected : path)); \ ++ assert_se(streq(k, expected ? expected : path)); \ + } + + expect("/waldo", ".mount", NULL); +@@ -80,7 +80,7 @@ static void test_replacements(void) { + _cleanup_free_ char *t = \ + unit_name_from_path_instance(pattern, path, suffix); \ + puts(t); \ +- assert(streq(t, expected)); \ ++ assert_se(streq(t, expected)); \ + } + + expect("waldo", "/waldo", ".mount", "waldo@waldo.mount"); +@@ -130,7 +130,7 @@ static int test_unit_printf(void) { + puts("manager_new: Permission denied. Skipping test."); + return EXIT_TEST_SKIP; + } +- assert(r == 0); ++ assert_se(r == 0); + + #define expect(unit, pattern, expected) \ + { \ +@@ -139,9 +139,9 @@ static int test_unit_printf(void) { + assert_se(unit_full_printf(unit, pattern, &t) >= 0); \ + printf("result: %s\nexpect: %s\n", t, expected); \ + if ((e = endswith(expected, "*"))) \ +- assert(strncmp(t, e, e-expected)); \ ++ assert_se(strncmp(t, e, e-expected)); \ + else \ +- assert(streq(t, expected)); \ ++ assert_se(streq(t, expected)); \ + } + + assert_se(setenv("USER", "root", 1) == 0); +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 1311184815..de6a2a0d89 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -231,7 +231,7 @@ static void test_parse_pid(void) { + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); +- assert(r == -ERANGE); ++ assert_se(r == -ERANGE); + assert_se(pid == 65); + } + +@@ -434,7 +434,7 @@ static void test_foreach_word_quoted(void) { + assert_se(strneq(expected[i++], word, l)); + printf("<%s>\n", t); + } +- assert(isempty(state)); ++ assert_se(isempty(state)); + } + + static void test_default_term_for_tty(void) { +@@ -466,26 +466,26 @@ static void test_memdup_multiply(void) { + } + + static void test_hostname_is_valid(void) { +- assert(hostname_is_valid("foobar")); +- assert(hostname_is_valid("foobar.com")); +- assert(!hostname_is_valid("fööbar")); +- assert(!hostname_is_valid("")); +- assert(!hostname_is_valid(".")); +- assert(!hostname_is_valid("..")); +- assert(!hostname_is_valid("foobar.")); +- assert(!hostname_is_valid(".foobar")); +- assert(!hostname_is_valid("foo..bar")); +- assert(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); ++ assert_se(hostname_is_valid("foobar")); ++ assert_se(hostname_is_valid("foobar.com")); ++ assert_se(!hostname_is_valid("fööbar")); ++ assert_se(!hostname_is_valid("")); ++ assert_se(!hostname_is_valid(".")); ++ assert_se(!hostname_is_valid("..")); ++ assert_se(!hostname_is_valid("foobar.")); ++ assert_se(!hostname_is_valid(".foobar")); ++ assert_se(!hostname_is_valid("foo..bar")); ++ assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); + } + + static void test_u64log2(void) { +- assert(u64log2(0) == 0); +- assert(u64log2(8) == 3); +- assert(u64log2(9) == 3); +- assert(u64log2(15) == 3); +- assert(u64log2(16) == 4); +- assert(u64log2(1024*1024) == 20); +- assert(u64log2(1024*1024+5) == 20); ++ assert_se(u64log2(0) == 0); ++ assert_se(u64log2(8) == 3); ++ assert_se(u64log2(9) == 3); ++ assert_se(u64log2(15) == 3); ++ assert_se(u64log2(16) == 4); ++ assert_se(u64log2(1024*1024) == 20); ++ assert_se(u64log2(1024*1024+5) == 20); + } + + static void test_get_process_comm(void) { +@@ -532,7 +532,7 @@ static void test_get_process_comm(void) { + log_info("pid1 gid: "GID_FMT, g); + assert_se(g == 0); + +- assert(get_ctty_devnr(1, &h) == -ENOENT); ++ assert_se(get_ctty_devnr(1, &h) == -ENOENT); + + getenv_for_pid(1, "PATH", &i); + log_info("pid1 $PATH: '%s'", strna(i)); +@@ -544,7 +544,7 @@ static void test_protect_errno(void) { + PROTECT_ERRNO; + errno = 11; + } +- assert(errno == 12); ++ assert_se(errno == 12); + } + + static void test_parse_size(void) { +@@ -729,12 +729,12 @@ static void test_writing_tmpfile(void) { + printf("tmpfile: %s", name); + + r = writev(fd, iov, 3); +- assert(r >= 0); ++ assert_se(r >= 0); + + r = read_full_file(name, &contents, &size); +- assert(r == 0); ++ assert_se(r == 0); + printf("contents: %s", contents); +- assert(streq(contents, "abc\n" ALPHANUMERICAL "\n")); ++ assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n")); + + unlink(name); + } diff --git a/0508-terminal-fix-restoring-of-screen-flags.patch b/0508-terminal-fix-restoring-of-screen-flags.patch new file mode 100644 index 0000000..dc0a8bd --- /dev/null +++ b/0508-terminal-fix-restoring-of-screen-flags.patch @@ -0,0 +1,24 @@ +From b7af2c8740e91a73348457fade97609b93e70a8d Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sat, 4 Oct 2014 23:03:15 +0200 +Subject: [PATCH] terminal: fix restoring of screen flags + +--- + src/libsystemd-terminal/term-screen.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 145dcdaee5..9026c25efe 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -1259,8 +1259,8 @@ static int screen_DECRC(term_screen *screen, const term_seq *seq) { + screen->gr = screen->saved.gr; + screen->glt = screen->saved.glt; + screen->grt = screen->saved.grt; +- set_reset(screen, TERM_FLAG_AUTO_WRAP, screen->flags & TERM_FLAG_AUTO_WRAP); +- set_reset(screen, TERM_FLAG_ORIGIN_MODE, screen->flags & TERM_FLAG_ORIGIN_MODE); ++ set_reset(screen, TERM_FLAG_AUTO_WRAP, screen->saved.flags & TERM_FLAG_AUTO_WRAP); ++ set_reset(screen, TERM_FLAG_ORIGIN_MODE, screen->saved.flags & TERM_FLAG_ORIGIN_MODE); + screen_cursor_set(screen, screen->saved.cursor_x, screen->saved.cursor_y); + + return 0; diff --git a/0509-terminal-fix-TERM_FLAG_-comment.patch b/0509-terminal-fix-TERM_FLAG_-comment.patch new file mode 100644 index 0000000..88ac4e8 --- /dev/null +++ b/0509-terminal-fix-TERM_FLAG_-comment.patch @@ -0,0 +1,23 @@ +From 621dbb0569ec318e78cfa7c71646b78eee46e8a5 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sun, 5 Oct 2014 14:45:33 +0200 +Subject: [PATCH] terminal: fix TERM_FLAG_* comment + +7BIT mode is enabled by default. Fix the comment to state this correctly. +--- + src/libsystemd-terminal/term-internal.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/term-internal.h b/src/libsystemd-terminal/term-internal.h +index f0f4432c80..a023498b53 100644 +--- a/src/libsystemd-terminal/term-internal.h ++++ b/src/libsystemd-terminal/term-internal.h +@@ -582,7 +582,7 @@ struct term_parser { + */ + + enum { +- TERM_FLAG_7BIT_MODE = (1U << 0), /* 7bit mode (default: off) */ ++ TERM_FLAG_7BIT_MODE = (1U << 0), /* 7bit mode (default: on) */ + TERM_FLAG_HIDE_CURSOR = (1U << 1), /* hide cursor caret (default: off) */ + TERM_FLAG_INHIBIT_TPARM = (1U << 2), /* do not send TPARM unrequested (default: off) */ + TERM_FLAG_NEWLINE_MODE = (1U << 3), /* perform carriage-return on line-feeds (default: off) */ diff --git a/0510-terminal-subterm-skip-setting-parent-s-cursor.patch b/0510-terminal-subterm-skip-setting-parent-s-cursor.patch new file mode 100644 index 0000000..bbf1cdd --- /dev/null +++ b/0510-terminal-subterm-skip-setting-parent-s-cursor.patch @@ -0,0 +1,24 @@ +From 9ed6e68e52f399c10d7e4d7f29bb0212c422e9e9 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sun, 5 Oct 2014 14:47:57 +0200 +Subject: [PATCH] terminal/subterm: skip setting parent's cursor + +We draw our own cursor in subterm now, so there's no reason to update the +cursor-position of the parent terminal on each frame. The parent's cursor +is hidden, anyway. +--- + src/libsystemd-terminal/subterm.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c +index 321cd35f52..dda6759709 100644 +--- a/src/libsystemd-terminal/subterm.c ++++ b/src/libsystemd-terminal/subterm.c +@@ -482,7 +482,6 @@ static void output_draw_screen(Output *o, term_screen *s) { + + term_screen_draw(s, output_draw_cell_fn, o, NULL); + +- output_move_to(o, s->cursor_x + 1, s->cursor_y + 3); + output_printf(o, "\e[m"); + } + diff --git a/0511-terminal-screen-save-state-in-separate-object.patch b/0511-terminal-screen-save-state-in-separate-object.patch new file mode 100644 index 0000000..8509f7b --- /dev/null +++ b/0511-terminal-screen-save-state-in-separate-object.patch @@ -0,0 +1,943 @@ +From 3ae49a8fdb7d21c065fcf2b1f7459a32f963c087 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sun, 5 Oct 2014 14:53:18 +0200 +Subject: [PATCH] terminal/screen: save state in separate object + +Terminal state can be saved/restored by applications. To simplify our +internal handling, put all affected state into a separate object. +Especially with alternate screen buffers, this will simplify our code +significantly. +--- + src/libsystemd-terminal/term-internal.h | 41 ++-- + src/libsystemd-terminal/term-screen.c | 326 +++++++++++++++----------------- + 2 files changed, 175 insertions(+), 192 deletions(-) + +diff --git a/src/libsystemd-terminal/term-internal.h b/src/libsystemd-terminal/term-internal.h +index a023498b53..c78b9aa70a 100644 +--- a/src/libsystemd-terminal/term-internal.h ++++ b/src/libsystemd-terminal/term-internal.h +@@ -37,6 +37,7 @@ typedef struct term_page term_page; + typedef struct term_history term_history; + + typedef uint32_t term_charset[96]; ++typedef struct term_state term_state; + + /* + * Miscellaneous +@@ -586,11 +587,9 @@ enum { + TERM_FLAG_HIDE_CURSOR = (1U << 1), /* hide cursor caret (default: off) */ + TERM_FLAG_INHIBIT_TPARM = (1U << 2), /* do not send TPARM unrequested (default: off) */ + TERM_FLAG_NEWLINE_MODE = (1U << 3), /* perform carriage-return on line-feeds (default: off) */ +- TERM_FLAG_ORIGIN_MODE = (1U << 4), /* in origin mode, the cursor is bound by the margins (default: off) */ +- TERM_FLAG_PENDING_WRAP = (1U << 5), /* wrap-around is pending */ +- TERM_FLAG_AUTO_WRAP = (1U << 6), /* auto-wrap mode causes line-wraps at line-ends (default: off) */ +- TERM_FLAG_KEYPAD_MODE = (1U << 7), /* application-keypad mode (default: off) */ +- TERM_FLAG_CURSOR_KEYS = (1U << 8), /* enable application cursor-keys (default: off) */ ++ TERM_FLAG_PENDING_WRAP = (1U << 4), /* wrap-around is pending */ ++ TERM_FLAG_KEYPAD_MODE = (1U << 5), /* application-keypad mode (default: off) */ ++ TERM_FLAG_CURSOR_KEYS = (1U << 6), /* enable application cursor-keys (default: off) */ + }; + + enum { +@@ -600,6 +599,19 @@ enum { + TERM_CONFORMANCE_LEVEL_CNT, + }; + ++struct term_state { ++ unsigned int cursor_x; ++ unsigned int cursor_y; ++ term_attr attr; ++ term_charset **gl; ++ term_charset **gr; ++ term_charset **glt; ++ term_charset **grt; ++ ++ bool auto_wrap : 1; ++ bool origin_mode : 1; ++}; ++ + struct term_screen { + unsigned long ref; + term_age_t age; +@@ -623,15 +635,8 @@ struct term_screen { + + unsigned int flags; + unsigned int conformance_level; +- unsigned int cursor_x; +- unsigned int cursor_y; +- term_attr attr; + term_attr default_attr; + +- term_charset **gl; +- term_charset **gr; +- term_charset **glt; +- term_charset **grt; + term_charset *g0; + term_charset *g1; + term_charset *g2; +@@ -639,14 +644,6 @@ struct term_screen { + + char *answerback; + +- struct { +- unsigned int cursor_x; +- unsigned int cursor_y; +- term_attr attr; +- term_charset **gl; +- term_charset **gr; +- term_charset **glt; +- term_charset **grt; +- unsigned int flags; +- } saved; ++ term_state state; ++ term_state saved; + }; +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 9026c25efe..c8a81658cb 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -70,18 +70,13 @@ int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *writ + screen->cmd_fn_data = cmd_fn_data; + screen->flags = TERM_FLAG_7BIT_MODE; + screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400; +- screen->gl = &screen->g0; +- screen->gr = &screen->g1; + screen->g0 = &term_unicode_lower; + screen->g1 = &term_unicode_upper; + screen->g2 = &term_unicode_lower; + screen->g3 = &term_unicode_upper; +- +- screen->saved.cursor_x = 0; +- screen->saved.cursor_y = 0; +- screen->saved.attr = screen->attr; +- screen->saved.gl = screen->gl; +- screen->saved.gr = screen->gr; ++ screen->state.gl = &screen->g0; ++ screen->state.gr = &screen->g1; ++ screen->saved = screen->state; + + r = term_page_new(&screen->page_main); + if (r < 0) +@@ -224,7 +219,7 @@ static bool screen_tab_is_set(term_screen *screen, unsigned int pos) { + static inline void screen_age_cursor(term_screen *screen) { + term_cell *cell; + +- cell = term_page_get_cell(screen->page, screen->cursor_x, screen->cursor_y); ++ cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y); + if (cell) + cell->age = screen->age; + } +@@ -237,21 +232,21 @@ static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int + x = screen_clamp_x(screen, x); + y = screen_clamp_y(screen, y); + +- if (x == screen->cursor_x && y == screen->cursor_y) ++ if (x == screen->state.cursor_x && y == screen->state.cursor_y) + return; + + if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) + screen_age_cursor(screen); + +- screen->cursor_x = x; +- screen->cursor_y = y; ++ screen->state.cursor_x = x; ++ screen->state.cursor_y = y; + + if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) + screen_age_cursor(screen); + } + + static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) { +- if (screen->flags & TERM_FLAG_ORIGIN_MODE) { ++ if (screen->state.origin_mode) { + x = screen_clamp_x(screen, x); + y = screen_clamp_x(screen, y) + screen->page->scroll_idx; + +@@ -266,53 +261,53 @@ static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned + } + + static void screen_cursor_left(term_screen *screen, unsigned int num) { +- if (num > screen->cursor_x) +- num = screen->cursor_x; ++ if (num > screen->state.cursor_x) ++ num = screen->state.cursor_x; + +- screen_cursor_set(screen, screen->cursor_x - num, screen->cursor_y); ++ screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y); + } + + static void screen_cursor_left_tab(term_screen *screen, unsigned int num) { + unsigned int i; + +- i = screen->cursor_x; ++ i = screen->state.cursor_x; + while (i > 0 && num > 0) { + if (screen_tab_is_set(screen, --i)) + --num; + } + +- screen_cursor_set(screen, i, screen->cursor_y); ++ screen_cursor_set(screen, i, screen->state.cursor_y); + } + + static void screen_cursor_right(term_screen *screen, unsigned int num) { + if (num > screen->page->width) + num = screen->page->width; + +- screen_cursor_set(screen, screen->cursor_x + num, screen->cursor_y); ++ screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y); + } + + static void screen_cursor_right_tab(term_screen *screen, unsigned int num) { + unsigned int i; + +- i = screen->cursor_x; ++ i = screen->state.cursor_x; + while (i + 1 < screen->page->width && num > 0) { + if (screen_tab_is_set(screen, ++i)) + --num; + } + +- screen_cursor_set(screen, i, screen->cursor_y); ++ screen_cursor_set(screen, i, screen->state.cursor_y); + } + + static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) { + unsigned int max; + +- if (screen->cursor_y < screen->page->scroll_idx) { +- if (num > screen->cursor_y) +- num = screen->cursor_y; ++ if (screen->state.cursor_y < screen->page->scroll_idx) { ++ if (num > screen->state.cursor_y) ++ num = screen->state.cursor_y; + +- screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num); ++ screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num); + } else { +- max = screen->cursor_y - screen->page->scroll_idx; ++ max = screen->state.cursor_y - screen->page->scroll_idx; + if (num > max) { + if (num < 1) + return; +@@ -321,14 +316,14 @@ static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) + screen_age_cursor(screen); + + if (scroll) +- term_page_scroll_down(screen->page, num - max, &screen->attr, screen->age, NULL); ++ term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL); + +- screen->cursor_y = screen->page->scroll_idx; ++ screen->state.cursor_y = screen->page->scroll_idx; + + if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) + screen_age_cursor(screen); + } else { +- screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num); ++ screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num); + } + } + } +@@ -336,13 +331,13 @@ static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) + static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) { + unsigned int max; + +- if (screen->cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) { ++ if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) { + if (num > screen->page->height) + num = screen->page->height; + +- screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num); ++ screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num); + } else { +- max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->cursor_y; ++ max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y; + if (num > max) { + if (num < 1) + return; +@@ -351,18 +346,27 @@ static void screen_cursor_down(term_screen *screen, unsigned int num, bool scrol + screen_age_cursor(screen); + + if (scroll) +- term_page_scroll_up(screen->page, num - max, &screen->attr, screen->age, screen->history); ++ term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history); + +- screen->cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1; ++ screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1; + + if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) + screen_age_cursor(screen); + } else { +- screen_cursor_set(screen, screen->cursor_x, screen->cursor_y + num); ++ screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num); + } + } + } + ++static void screen_save_state(term_screen *screen, term_state *where) { ++ *where = screen->state; ++} ++ ++static void screen_restore_state(term_screen *screen, term_state *from) { ++ screen_cursor_set(screen, from->cursor_x, from->cursor_y); ++ screen->state = *from; ++} ++ + static inline void set_reset(term_screen *screen, unsigned int flag, bool set) { + if (set) + screen->flags |= flag; +@@ -388,7 +392,7 @@ static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, + * DECOM: origin-mode + * TODO + */ +- set_reset(screen, TERM_FLAG_ORIGIN_MODE, set); ++ screen->state.origin_mode = set; + } + + break; +@@ -398,7 +402,7 @@ static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, + * DECAWN: auto-wrap mode + * TODO + */ +- set_reset(screen, TERM_FLAG_AUTO_WRAP, set); ++ screen->state.auto_wrap = set; + } + + break; +@@ -435,19 +439,19 @@ static uint32_t screen_map(term_screen *screen, uint32_t val) { + * identity. */ + switch (val) { + case 33 ... 126: +- if (screen->glt) { +- nval = (**screen->glt)[val - 32]; +- screen->glt = NULL; ++ if (screen->state.glt) { ++ nval = (**screen->state.glt)[val - 32]; ++ screen->state.glt = NULL; + } else { +- nval = (**screen->gl)[val - 32]; ++ nval = (**screen->state.gl)[val - 32]; + } + break; + case 160 ... 255: +- if (screen->grt) { +- nval = (**screen->grt)[val - 160]; +- screen->grt = NULL; ++ if (screen->state.grt) { ++ nval = (**screen->state.grt)[val - 160]; ++ screen->state.grt = NULL; + } else { +- nval = (**screen->gr)[val - 160]; ++ nval = (**screen->state.gr)[val - 160]; + } + break; + } +@@ -471,20 +475,20 @@ static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) { + term_char_t ch = TERM_CHAR_NULL; + uint32_t c; + +- if (screen->cursor_x + 1 == screen->page->width ++ if (screen->state.cursor_x + 1 == screen->page->width + && screen->flags & TERM_FLAG_PENDING_WRAP +- && screen->flags & TERM_FLAG_AUTO_WRAP) { ++ && screen->state.auto_wrap) { + screen_cursor_down(screen, 1, true); +- screen_cursor_set(screen, 0, screen->cursor_y); ++ screen_cursor_set(screen, 0, screen->state.cursor_y); + } + + screen_cursor_clear_wrap(screen); + + c = screen_map(screen, seq->terminator); + ch = term_char_merge(ch, screen_map(screen, c)); +- term_page_write(screen->page, screen->cursor_x, screen->cursor_y, ch, 1, &screen->attr, screen->age, false); ++ term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false); + +- if (screen->cursor_x + 1 == screen->page->width) ++ if (screen->state.cursor_x + 1 == screen->page->width) + screen->flags |= TERM_FLAG_PENDING_WRAP; + else + screen_cursor_right(screen, 1); +@@ -556,7 +560,7 @@ static int screen_CHA(term_screen *screen, const term_seq *seq) { + pos = seq->args[0]; + + screen_cursor_clear_wrap(screen); +- screen_cursor_set(screen, pos - 1, screen->cursor_y); ++ screen_cursor_set(screen, pos - 1, screen->state.cursor_y); + + return 0; + } +@@ -635,7 +639,7 @@ static int screen_CR(term_screen *screen, const term_seq *seq) { + */ + + screen_cursor_clear_wrap(screen); +- screen_cursor_set(screen, 0, screen->cursor_y); ++ screen_cursor_set(screen, 0, screen->state.cursor_y); + + return 0; + } +@@ -901,7 +905,7 @@ static int screen_DCH(term_screen *screen, const term_seq *seq) { + num = seq->args[0]; + + screen_cursor_clear_wrap(screen); +- term_page_delete_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age); ++ term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age); + + return 0; + } +@@ -1254,14 +1258,7 @@ static int screen_DECRC(term_screen *screen, const term_seq *seq) { + * state for the main display and the status line. + */ + +- screen->attr = screen->saved.attr; +- screen->gl = screen->saved.gl; +- screen->gr = screen->saved.gr; +- screen->glt = screen->saved.glt; +- screen->grt = screen->saved.grt; +- set_reset(screen, TERM_FLAG_AUTO_WRAP, screen->saved.flags & TERM_FLAG_AUTO_WRAP); +- set_reset(screen, TERM_FLAG_ORIGIN_MODE, screen->saved.flags & TERM_FLAG_ORIGIN_MODE); +- screen_cursor_set(screen, screen->saved.cursor_x, screen->saved.cursor_y); ++ screen_restore_state(screen, &screen->saved); + + return 0; + } +@@ -1468,15 +1465,7 @@ static int screen_DECSC(term_screen *screen, const term_seq *seq) { + * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent + */ + +- screen->saved.cursor_x = screen->cursor_x; +- screen->saved.cursor_y = screen->cursor_y; +- screen->saved.attr = screen->attr; +- screen->saved.gl = screen->gl; +- screen->saved.gr = screen->gr; +- screen->saved.glt = screen->glt; +- screen->saved.grt = screen->grt; +- screen->saved.flags = screen->flags & (TERM_FLAG_AUTO_WRAP +- | TERM_FLAG_ORIGIN_MODE); ++ screen_save_state(screen, &screen->saved); + + return 0; + } +@@ -1503,10 +1492,10 @@ static int screen_DECSCA(term_screen *screen, const term_seq *seq) { + switch (mode) { + case 0: + case 2: +- screen->attr.protect = 0; ++ screen->state.attr.protect = 0; + break; + case 1: +- screen->attr.protect = 1; ++ screen->state.attr.protect = 1; + break; + } + +@@ -1671,21 +1660,21 @@ static int screen_DECSED(term_screen *screen, const term_seq *seq) { + switch (mode) { + case 0: + term_page_erase(screen->page, +- screen->cursor_x, screen->cursor_y, ++ screen->state.cursor_x, screen->state.cursor_y, + screen->page->width, screen->page->height, +- &screen->attr, screen->age, true); ++ &screen->state.attr, screen->age, true); + break; + case 1: + term_page_erase(screen->page, + 0, 0, +- screen->cursor_x, screen->cursor_y, +- &screen->attr, screen->age, true); ++ screen->state.cursor_x, screen->state.cursor_y, ++ &screen->state.attr, screen->age, true); + break; + case 2: + term_page_erase(screen->page, + 0, 0, + screen->page->width, screen->page->height, +- &screen->attr, screen->age, true); ++ &screen->state.attr, screen->age, true); + break; + } + +@@ -1717,21 +1706,21 @@ static int screen_DECSEL(term_screen *screen, const term_seq *seq) { + switch (mode) { + case 0: + term_page_erase(screen->page, +- screen->cursor_x, screen->cursor_y, +- screen->page->width, screen->cursor_y, +- &screen->attr, screen->age, true); ++ screen->state.cursor_x, screen->state.cursor_y, ++ screen->page->width, screen->state.cursor_y, ++ &screen->state.attr, screen->age, true); + break; + case 1: + term_page_erase(screen->page, +- 0, screen->cursor_y, +- screen->cursor_x, screen->cursor_y, +- &screen->attr, screen->age, true); ++ 0, screen->state.cursor_y, ++ screen->state.cursor_x, screen->state.cursor_y, ++ &screen->state.attr, screen->age, true); + break; + case 2: + term_page_erase(screen->page, +- 0, screen->cursor_y, +- screen->page->width, screen->cursor_y, +- &screen->attr, screen->age, true); ++ 0, screen->state.cursor_y, ++ screen->page->width, screen->state.cursor_y, ++ &screen->state.attr, screen->age, true); + break; + } + +@@ -2078,7 +2067,7 @@ static int screen_DL(term_screen *screen, const term_seq *seq) { + if (seq->args[0] > 0) + num = seq->args[0]; + +- term_page_delete_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age); ++ term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age); + + return 0; + } +@@ -2123,9 +2112,9 @@ static int screen_ECH(term_screen *screen, const term_seq *seq) { + num = seq->args[0]; + + term_page_erase(screen->page, +- screen->cursor_x, screen->cursor_y, +- screen->cursor_x + num, screen->cursor_y, +- &screen->attr, screen->age, false); ++ screen->state.cursor_x, screen->state.cursor_y, ++ screen->state.cursor_x + num, screen->state.cursor_y, ++ &screen->state.attr, screen->age, false); + + return 0; + } +@@ -2154,21 +2143,21 @@ static int screen_ED(term_screen *screen, const term_seq *seq) { + switch (mode) { + case 0: + term_page_erase(screen->page, +- screen->cursor_x, screen->cursor_y, ++ screen->state.cursor_x, screen->state.cursor_y, + screen->page->width, screen->page->height, +- &screen->attr, screen->age, false); ++ &screen->state.attr, screen->age, false); + break; + case 1: + term_page_erase(screen->page, + 0, 0, +- screen->cursor_x, screen->cursor_y, +- &screen->attr, screen->age, false); ++ screen->state.cursor_x, screen->state.cursor_y, ++ &screen->state.attr, screen->age, false); + break; + case 2: + term_page_erase(screen->page, + 0, 0, + screen->page->width, screen->page->height, +- &screen->attr, screen->age, false); ++ &screen->state.attr, screen->age, false); + break; + } + +@@ -2198,21 +2187,21 @@ static int screen_EL(term_screen *screen, const term_seq *seq) { + switch (mode) { + case 0: + term_page_erase(screen->page, +- screen->cursor_x, screen->cursor_y, +- screen->page->width, screen->cursor_y, +- &screen->attr, screen->age, false); ++ screen->state.cursor_x, screen->state.cursor_y, ++ screen->page->width, screen->state.cursor_y, ++ &screen->state.attr, screen->age, false); + break; + case 1: + term_page_erase(screen->page, +- 0, screen->cursor_y, +- screen->cursor_x, screen->cursor_y, +- &screen->attr, screen->age, false); ++ 0, screen->state.cursor_y, ++ screen->state.cursor_x, screen->state.cursor_y, ++ &screen->state.attr, screen->age, false); + break; + case 2: + term_page_erase(screen->page, +- 0, screen->cursor_y, +- screen->page->width, screen->cursor_y, +- &screen->attr, screen->age, false); ++ 0, screen->state.cursor_y, ++ screen->page->width, screen->state.cursor_y, ++ &screen->state.attr, screen->age, false); + break; + } + +@@ -2271,7 +2260,7 @@ static int screen_HPA(term_screen *screen, const term_seq *seq) { + num = seq->args[0]; + + screen_cursor_clear_wrap(screen); +- screen_cursor_set(screen, num - 1, screen->cursor_y); ++ screen_cursor_set(screen, num - 1, screen->state.cursor_y); + + return 0; + } +@@ -2327,7 +2316,7 @@ static int screen_HTS(term_screen *screen, const term_seq *seq) { + + unsigned int pos; + +- pos = screen->cursor_x; ++ pos = screen->state.cursor_x; + if (screen->page->width > 0) + screen->tabs[pos / 8] |= 1U << (pos % 8); + +@@ -2372,7 +2361,7 @@ static int screen_ICH(term_screen *screen, const term_seq *seq) { + num = seq->args[0]; + + screen_cursor_clear_wrap(screen); +- term_page_insert_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age); ++ term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age); + + return 0; + } +@@ -2398,7 +2387,7 @@ static int screen_IL(term_screen *screen, const term_seq *seq) { + num = seq->args[0]; + + screen_cursor_clear_wrap(screen); +- term_page_insert_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age); ++ term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age); + + return 0; + } +@@ -2424,7 +2413,7 @@ static int screen_LF(term_screen *screen, const term_seq *seq) { + + screen_cursor_down(screen, 1, true); + if (screen->flags & TERM_FLAG_NEWLINE_MODE) +- screen_cursor_left(screen, screen->cursor_x); ++ screen_cursor_left(screen, screen->state.cursor_x); + + return 0; + } +@@ -2435,7 +2424,7 @@ static int screen_LS1R(term_screen *screen, const term_seq *seq) { + * Map G1 into GR. + */ + +- screen->gr = &screen->g1; ++ screen->state.gr = &screen->g1; + + return 0; + } +@@ -2446,7 +2435,7 @@ static int screen_LS2(term_screen *screen, const term_seq *seq) { + * Map G2 into GL. + */ + +- screen->gl = &screen->g2; ++ screen->state.gl = &screen->g2; + + return 0; + } +@@ -2457,7 +2446,7 @@ static int screen_LS2R(term_screen *screen, const term_seq *seq) { + * Map G2 into GR. + */ + +- screen->gr = &screen->g2; ++ screen->state.gr = &screen->g2; + + return 0; + } +@@ -2468,7 +2457,7 @@ static int screen_LS3(term_screen *screen, const term_seq *seq) { + * Map G3 into GL. + */ + +- screen->gl = &screen->g3; ++ screen->state.gl = &screen->g3; + + return 0; + } +@@ -2479,7 +2468,7 @@ static int screen_LS3R(term_screen *screen, const term_seq *seq) { + * Map G3 into GR. + */ + +- screen->gr = &screen->g3; ++ screen->state.gr = &screen->g3; + + return 0; + } +@@ -2513,7 +2502,7 @@ static int screen_NEL(term_screen *screen, const term_seq *seq) { + + screen_cursor_clear_wrap(screen); + screen_cursor_down(screen, 1, true); +- screen_cursor_set(screen, 0, screen->cursor_y); ++ screen_cursor_set(screen, 0, screen->state.cursor_y); + + return 0; + } +@@ -2834,7 +2823,7 @@ static int screen_SD(term_screen *screen, const term_seq *seq) { + if (seq->args[0] > 0) + num = seq->args[0]; + +- term_page_scroll_down(screen->page, num, &screen->attr, screen->age, NULL); ++ term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL); + + return 0; + } +@@ -2849,7 +2838,7 @@ static int screen_SGR(term_screen *screen, const term_seq *seq) { + int v; + + if (seq->n_args < 1) { +- zero(screen->attr); ++ zero(screen->state.attr); + return 0; + } + +@@ -2857,67 +2846,67 @@ static int screen_SGR(term_screen *screen, const term_seq *seq) { + v = seq->args[i]; + switch (v) { + case 1: +- screen->attr.bold = 1; ++ screen->state.attr.bold = 1; + break; + case 3: +- screen->attr.italic = 1; ++ screen->state.attr.italic = 1; + break; + case 4: +- screen->attr.underline = 1; ++ screen->state.attr.underline = 1; + break; + case 5: +- screen->attr.blink = 1; ++ screen->state.attr.blink = 1; + break; + case 7: +- screen->attr.inverse = 1; ++ screen->state.attr.inverse = 1; + break; + case 8: +- screen->attr.hidden = 1; ++ screen->state.attr.hidden = 1; + break; + case 22: +- screen->attr.bold = 0; ++ screen->state.attr.bold = 0; + break; + case 23: +- screen->attr.italic = 0; ++ screen->state.attr.italic = 0; + break; + case 24: +- screen->attr.underline = 0; ++ screen->state.attr.underline = 0; + break; + case 25: +- screen->attr.blink = 0; ++ screen->state.attr.blink = 0; + break; + case 27: +- screen->attr.inverse = 0; ++ screen->state.attr.inverse = 0; + break; + case 28: +- screen->attr.hidden = 0; ++ screen->state.attr.hidden = 0; + break; + case 30 ... 37: +- screen->attr.fg.ccode = v - 30 + TERM_CCODE_BLACK; ++ screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK; + break; + case 39: +- screen->attr.fg.ccode = 0; ++ screen->state.attr.fg.ccode = 0; + break; + case 40 ... 47: +- screen->attr.bg.ccode = v - 40 + TERM_CCODE_BLACK; ++ screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK; + break; + case 49: +- screen->attr.bg.ccode = 0; ++ screen->state.attr.bg.ccode = 0; + break; + case 90 ... 97: +- screen->attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK; ++ screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK; + break; + case 100 ... 107: +- screen->attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK; ++ screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK; + break; + case 38: + /* fallthrough */ + case 48: + + if (v == 38) +- dst = &screen->attr.fg; ++ dst = &screen->state.attr.fg; + else +- dst = &screen->attr.bg; ++ dst = &screen->state.attr.bg; + + ++i; + if (i >= seq->n_args) +@@ -2955,7 +2944,7 @@ static int screen_SGR(term_screen *screen, const term_seq *seq) { + case -1: + /* fallthrough */ + case 0: +- zero(screen->attr); ++ zero(screen->state.attr); + break; + } + } +@@ -2969,7 +2958,7 @@ static int screen_SI(term_screen *screen, const term_seq *seq) { + * Map G0 into GL. + */ + +- screen->gl = &screen->g0; ++ screen->state.gl = &screen->g0; + + return 0; + } +@@ -3009,7 +2998,7 @@ static int screen_SO(term_screen *screen, const term_seq *seq) { + * Map G1 into GL. + */ + +- screen->gl = &screen->g1; ++ screen->state.gl = &screen->g1; + + return 0; + } +@@ -3030,7 +3019,7 @@ static int screen_SS2(term_screen *screen, const term_seq *seq) { + * Temporarily map G2 into GL for the next graphics character. + */ + +- screen->glt = &screen->g2; ++ screen->state.glt = &screen->g2; + + return 0; + } +@@ -3041,7 +3030,7 @@ static int screen_SS3(term_screen *screen, const term_seq *seq) { + * Temporarily map G3 into GL for the next graphics character + */ + +- screen->glt = &screen->g3; ++ screen->state.glt = &screen->g3; + + return 0; + } +@@ -3077,7 +3066,7 @@ static int screen_SU(term_screen *screen, const term_seq *seq) { + if (seq->args[0] > 0) + num = seq->args[0]; + +- term_page_scroll_up(screen->page, num, &screen->attr, screen->age, screen->history); ++ term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history); + + return 0; + } +@@ -3116,7 +3105,7 @@ static int screen_TBC(term_screen *screen, const term_seq *seq) { + + switch (mode) { + case 0: +- pos = screen->cursor_x; ++ pos = screen->state.cursor_x; + if (screen->page->width > 0) + screen->tabs[pos / 8] &= ~(1U << (pos % 8)); + break; +@@ -3147,7 +3136,7 @@ static int screen_VPA(term_screen *screen, const term_seq *seq) { + pos = seq->args[0]; + + screen_cursor_clear_wrap(screen); +- screen_cursor_set_rel(screen, screen->cursor_x, pos - 1); ++ screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1); + + return 0; + } +@@ -4104,11 +4093,11 @@ int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) { + + assert_return(screen, -EINVAL); + +- r = term_page_reserve(screen->page_main, x, y, &screen->attr, screen->age); ++ r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age); + if (r < 0) + return r; + +- r = term_page_reserve(screen->page_alt, x, y, &screen->attr, screen->age); ++ r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age); + if (r < 0) + return r; + +@@ -4124,11 +4113,11 @@ int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) { + for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8) + screen->tabs[i / 8] = 0x1; + +- term_page_resize(screen->page_main, x, y, &screen->attr, screen->age, screen->history); +- term_page_resize(screen->page_alt, x, y, &screen->attr, screen->age, NULL); ++ term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history); ++ term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL); + +- screen->cursor_x = screen_clamp_x(screen, screen->cursor_x); +- screen->cursor_y = screen_clamp_x(screen, screen->cursor_y); ++ screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x); ++ screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y); + screen_cursor_clear_wrap(screen); + + return 0; +@@ -4139,29 +4128,26 @@ void term_screen_soft_reset(term_screen *screen) { + + assert(screen); + +- screen->gl = &screen->g0; +- screen->gr = &screen->g1; +- screen->glt = NULL; +- screen->grt = NULL; + screen->g0 = &term_unicode_lower; + screen->g1 = &term_unicode_upper; + screen->g2 = &term_unicode_lower; + screen->g3 = &term_unicode_upper; ++ screen->state.attr = screen->default_attr; ++ screen->state.gl = &screen->g0; ++ screen->state.gr = &screen->g1; ++ screen->state.glt = NULL; ++ screen->state.grt = NULL; ++ screen->state.auto_wrap = 0; ++ screen->state.origin_mode = 0; ++ ++ screen->saved = screen->state; ++ screen->saved.cursor_x = 0; ++ screen->saved.cursor_y = 0; + + screen->page = screen->page_main; + screen->history = screen->history_main; + screen->flags = TERM_FLAG_7BIT_MODE; + screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400; +- screen->attr = screen->default_attr; +- +- screen->saved.cursor_x = 0; +- screen->saved.cursor_y = 0; +- screen->saved.attr = screen->attr; +- screen->saved.gl = screen->gl; +- screen->saved.gr = screen->gr; +- screen->saved.glt = NULL; +- screen->saved.grt = NULL; +- screen->flags = 0; + + for (i = 0; i < screen->page->width; i += 8) + screen->tabs[i / 8] = 0x1; +@@ -4175,10 +4161,10 @@ void term_screen_hard_reset(term_screen *screen) { + + term_screen_soft_reset(screen); + zero(screen->utf8); +- screen->cursor_x = 0; +- screen->cursor_y = 0; +- term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false); +- term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false); ++ screen->state.cursor_x = 0; ++ screen->state.cursor_y = 0; ++ term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false); ++ term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false); + } + + int term_screen_set_answerback(term_screen *screen, const char *answerback) { +@@ -4248,7 +4234,7 @@ int term_screen_draw(term_screen *screen, + cw = MAX(cell->cwidth, 1U); + + attr = cell->attr; +- if (i == screen->cursor_x && j == screen->cursor_y && ++ if (i == screen->state.cursor_x && j == screen->state.cursor_y && + !(screen->flags & TERM_FLAG_HIDE_CURSOR)) + attr.inverse ^= 1; + diff --git a/0512-terminal-screen-add-support-for-alternate-screen-buf.patch b/0512-terminal-screen-add-support-for-alternate-screen-buf.patch new file mode 100644 index 0000000..5a0a0fb --- /dev/null +++ b/0512-terminal-screen-add-support-for-alternate-screen-buf.patch @@ -0,0 +1,152 @@ +From c7afe4f3d74f0487c913ce49abc58fe59aaeac12 Mon Sep 17 00:00:00 2001 +From: Tom Gundersen +Date: Sun, 5 Oct 2014 15:26:54 +0200 +Subject: [PATCH] terminal/screen: add support for alternate screen buffers + +Hook up SM/RM 47/1047-1049 and enable alternate screen buffers for term +applications. + +(David: rebased on top of -git, renamed helpers and added docs) +--- + src/libsystemd-terminal/term-internal.h | 1 + + src/libsystemd-terminal/term-screen.c | 89 ++++++++++++++++++++++++++++++++- + 2 files changed, 88 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-terminal/term-internal.h b/src/libsystemd-terminal/term-internal.h +index c78b9aa70a..53713dd64d 100644 +--- a/src/libsystemd-terminal/term-internal.h ++++ b/src/libsystemd-terminal/term-internal.h +@@ -646,4 +646,5 @@ struct term_screen { + + term_state state; + term_state saved; ++ term_state saved_alt; + }; +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index c8a81658cb..54bb04752c 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -77,6 +77,7 @@ int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *writ + screen->state.gl = &screen->g0; + screen->state.gr = &screen->g1; + screen->saved = screen->state; ++ screen->saved_alt = screen->saved; + + r = term_page_new(&screen->page_main); + if (r < 0) +@@ -367,6 +368,23 @@ static void screen_restore_state(term_screen *screen, term_state *from) { + screen->state = *from; + } + ++static void screen_reset_page(term_screen *screen, term_page *page) { ++ term_page_set_scroll_region(page, 0, page->height); ++ term_page_erase(page, 0, 0, page->width, page->height, &screen->state.attr, screen->age, false); ++} ++ ++static void screen_change_alt(term_screen *screen, bool set) { ++ if (set) { ++ screen->page = screen->page_alt; ++ screen->history = NULL; ++ } else { ++ screen->page = screen->page_main; ++ screen->history = screen->history_main; ++ } ++ ++ screen->page->age = screen->age; ++} ++ + static inline void set_reset(term_screen *screen, unsigned int flag, bool set) { + if (set) + screen->flags |= flag; +@@ -427,6 +445,73 @@ static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, + } + + break; ++ case 47: ++ if (dec) { ++ /* ++ * XTERM-ASB: alternate-screen-buffer ++ * This enables/disables the alternate screen-buffer. ++ * It effectively saves the current page content and ++ * allows you to restore it when changing to the ++ * original screen-buffer again. ++ */ ++ screen_change_alt(screen, set); ++ } ++ ++ break; ++ case 1047: ++ if (dec) { ++ /* ++ * XTERM-ASBPE: alternate-screen-buffer-post-erase ++ * This is the same as XTERM-ASB but erases the ++ * alternate screen-buffer before switching back to the ++ * original buffer. Use it to discard any data on the ++ * alternate screen buffer when done. ++ */ ++ if (!set) ++ screen_reset_page(screen, screen->page_alt); ++ ++ screen_change_alt(screen, set); ++ } ++ ++ break; ++ case 1048: ++ if (dec) { ++ /* ++ * XTERM-ASBCS: alternate-screen-buffer-cursor-state ++ * This has the same effect as DECSC/DECRC, but uses a ++ * separate state buffer. It is usually used in ++ * combination with alternate screen buffers to provide ++ * stacked state storage. ++ */ ++ if (set) ++ screen_save_state(screen, &screen->saved_alt); ++ else ++ screen_restore_state(screen, &screen->saved_alt); ++ } ++ ++ break; ++ case 1049: ++ if (dec) { ++ /* ++ * XTERM-ASBX: alternate-screen-buffer-extended ++ * This combines XTERM-ASBPE and XTERM-ASBCS somewhat. ++ * When enabling, state is saved, alternate screen ++ * buffer is activated and cleared. ++ * When disabled, alternate screen buffer is cleared, ++ * then normal screen buffer is enabled and state is ++ * restored. ++ */ ++ if (set) ++ screen_save_state(screen, &screen->saved_alt); ++ ++ screen_reset_page(screen, screen->page_alt); ++ screen_change_alt(screen, set); ++ ++ if (!set) ++ screen_restore_state(screen, &screen->saved_alt); ++ } ++ ++ break; + } + } + +@@ -1966,8 +2051,7 @@ static int screen_DECSTBM(term_screen *screen, const term_seq *seq) { + bottom = screen->page->height; + } + +- term_page_set_scroll_region(screen->page_main, top - 1, bottom - top + 1); +- term_page_set_scroll_region(screen->page_alt, top - 1, bottom - top + 1); ++ term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1); + screen_cursor_clear_wrap(screen); + screen_cursor_set(screen, 0, 0); + +@@ -4143,6 +4227,7 @@ void term_screen_soft_reset(term_screen *screen) { + screen->saved = screen->state; + screen->saved.cursor_x = 0; + screen->saved.cursor_y = 0; ++ screen->saved_alt = screen->saved; + + screen->page = screen->page_main; + screen->history = screen->history_main; diff --git a/0513-terminal-subterm-leave-bold-light-conversion-to-pare.patch b/0513-terminal-subterm-leave-bold-light-conversion-to-pare.patch new file mode 100644 index 0000000..75e4af1 --- /dev/null +++ b/0513-terminal-subterm-leave-bold-light-conversion-to-pare.patch @@ -0,0 +1,28 @@ +From 378c4eed029eb37eec31e56bd82ca5df2dee1e73 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sun, 5 Oct 2014 15:48:32 +0200 +Subject: [PATCH] terminal/subterm: leave bold-light conversion to parent + +We rely on the parent terminal to do color conversion, so also leave +bold->light conversion to the parent. Otherwise, it will be performed +twice and we might apply it on the wrong color. +--- + src/libsystemd-terminal/subterm.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c +index dda6759709..93c06bea83 100644 +--- a/src/libsystemd-terminal/subterm.c ++++ b/src/libsystemd-terminal/subterm.c +@@ -428,10 +428,7 @@ static int output_draw_cell_fn(term_screen *screen, + output_printf(o, "\e[38;2;%u;%u;%um", attr->fg.red, attr->fg.green, attr->fg.blue); + break; + case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: +- if (attr->bold) +- output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_BLACK + 90); +- else +- output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_BLACK + 30); ++ output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_BLACK + 30); + break; + case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: + output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_LIGHT_BLACK + 90); diff --git a/0514-terminal-screen-perform-bold-light-conversion-only-o.patch b/0514-terminal-screen-perform-bold-light-conversion-only-o.patch new file mode 100644 index 0000000..13c9a40 --- /dev/null +++ b/0514-terminal-screen-perform-bold-light-conversion-only-o.patch @@ -0,0 +1,27 @@ +From 34dbefceb1377ccd7871e183d7791f76fe879e73 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sun, 5 Oct 2014 15:49:26 +0200 +Subject: [PATCH] terminal/screen: perform bold->light conversion only on + foreground + +Bold glyphs always use light colors. However, this color conversion is +limited to the foreground color, so skip it for backgrounds. +--- + src/libsystemd-terminal/term-parser.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd-terminal/term-parser.c b/src/libsystemd-terminal/term-parser.c +index 8ec6345d60..d8206a46ba 100644 +--- a/src/libsystemd-terminal/term-parser.c ++++ b/src/libsystemd-terminal/term-parser.c +@@ -100,8 +100,8 @@ static uint32_t term_color_to_argb32(const term_color *color, const term_attr *a + case TERM_CCODE_BLACK ... TERM_CCODE_LIGHT_WHITE: + t = color->ccode - TERM_CCODE_BLACK; + +- /* bold causes light colors */ +- if (t < 8 && attr->bold) ++ /* bold causes light colors (only for foreground colors) */ ++ if (t < 8 && attr->bold && color == &attr->fg) + t += 8; + + r = palette[t * 3 + 0]; diff --git a/0515-terminal-idev-don-t-remove-consumed-mods-from-kbd-ma.patch b/0515-terminal-idev-don-t-remove-consumed-mods-from-kbd-ma.patch new file mode 100644 index 0000000..709e000 --- /dev/null +++ b/0515-terminal-idev-don-t-remove-consumed-mods-from-kbd-ma.patch @@ -0,0 +1,49 @@ +From 62d5068d631fd655efe3ae4ad51fffe28e13e27a Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Sun, 5 Oct 2014 17:44:09 +0200 +Subject: [PATCH] terminal/idev: don't remove consumed-mods from kbd-matches + +XKB consumed mods include modifiers that *didn't* affect the translation, +but might affect it if used. This is very misleading, given that we are +usually not interested in that information. Therefore, keep them in real +mods to behave like X11 does. Maybe at some point, XKB introduces proper +shortcut matching... + +Also make evcat display consumed modifiers so we can better debug those +situations. +--- + src/libsystemd-terminal/evcat.c | 7 +++++++ + src/libsystemd-terminal/idev.h | 2 +- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c +index 62556f6a2b..9e8a262b79 100644 +--- a/src/libsystemd-terminal/evcat.c ++++ b/src/libsystemd-terminal/evcat.c +@@ -219,6 +219,13 @@ static void kdata_print(idev_data *data) { + printf(" %-5s", (k->mods & IDEV_KBDMOD_LINUX) ? "LINUX" : ""); + printf(" %-4s", (k->mods & IDEV_KBDMOD_CAPS) ? "CAPS" : ""); + ++ /* Consumed modifiers */ ++ printf(" | %-5s", (k->consumed_mods & IDEV_KBDMOD_SHIFT) ? "SHIFT" : ""); ++ printf(" %-4s", (k->consumed_mods & IDEV_KBDMOD_CTRL) ? "CTRL" : ""); ++ printf(" %-3s", (k->consumed_mods & IDEV_KBDMOD_ALT) ? "ALT" : ""); ++ printf(" %-5s", (k->consumed_mods & IDEV_KBDMOD_LINUX) ? "LINUX" : ""); ++ printf(" %-4s", (k->consumed_mods & IDEV_KBDMOD_CAPS) ? "CAPS" : ""); ++ + /* Resolved symbols */ + printf(" |"); + for (i = 0; i < k->n_syms; ++i) { +diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h +index ea79bb6ab6..c8c03f3d41 100644 +--- a/src/libsystemd-terminal/idev.h ++++ b/src/libsystemd-terminal/idev.h +@@ -123,7 +123,7 @@ static inline bool idev_kbdmatch(idev_data_keyboard *kdata, + return false; + + real = kdata->mods & ~kdata->consumed_mods & significant; +- if (real != (mods & ~kdata->consumed_mods)) ++ if (real != mods) + return false; + + return !memcmp(syms, kdata->keysyms, n_syms * sizeof(*syms)); diff --git a/0516-bus-add-assert-to-check-that-we-re-not-freeing-a-sta.patch b/0516-bus-add-assert-to-check-that-we-re-not-freeing-a-sta.patch new file mode 100644 index 0000000..3bab1c0 --- /dev/null +++ b/0516-bus-add-assert-to-check-that-we-re-not-freeing-a-sta.patch @@ -0,0 +1,23 @@ +From 75a0da952f603006d6b3535ecaf8ebe2bded30e7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 5 Oct 2014 14:04:02 -0400 +Subject: [PATCH] bus: add assert to check that we're not freeing a static + structure + +CID #996315. +--- + src/libsystemd/sd-bus/sd-bus.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 28b993b7ba..bc4376fb51 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -142,6 +142,7 @@ static void bus_free(sd_bus *b) { + hashmap_free_free(b->reply_callbacks); + prioq_free(b->reply_callbacks_prioq); + ++ assert(b->match_callbacks.type == BUS_MATCH_ROOT); + bus_match_free(&b->match_callbacks); + + hashmap_free_free(b->vtable_methods); diff --git a/0517-ask-password-Add-echo-to-enable-echoing-the-user-inp.patch b/0517-ask-password-Add-echo-to-enable-echoing-the-user-inp.patch new file mode 100644 index 0000000..1cdae72 --- /dev/null +++ b/0517-ask-password-Add-echo-to-enable-echoing-the-user-inp.patch @@ -0,0 +1,241 @@ +From 64845bdc829d6a6179d0762b7e97ef23828562a3 Mon Sep 17 00:00:00 2001 +From: David Sommerseth +Date: Fri, 3 Oct 2014 15:53:45 +0200 +Subject: [PATCH] ask-password: Add --echo to enable echoing the user input + +Programs such as OpenVPN may use ask-password for not only retrieving +passwords, but also usernames. Masking usernames with * seems just silly. + + v2 - Don't mess with termios flags, instead print the input + instead of an asterix. Resolves issues with backspace + and TAB input. + + v3 - Renamed 'do_echo' variables and argument to 'echo'. Also + modified the ask_password_{tty,agent,auto} API instead of + additional wrapper functions. + +[zj: undo changes to ask_password_auto, since no callers were using + the new argument.] +--- + man/systemd-ask-password.xml | 11 +++++++++++ + src/ask-password/ask-password.c | 12 ++++++++++-- + src/firstboot/firstboot.c | 4 ++-- + src/shared/ask-password-api.c | 10 +++++++--- + src/shared/ask-password-api.h | 4 ++-- + src/tty-ask-password-agent/tty-ask-password-agent.c | 5 +++-- + 6 files changed, 35 insertions(+), 11 deletions(-) + +diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml +index ce0ac3d1a2..448df62100 100644 +--- a/man/systemd-ask-password.xml ++++ b/man/systemd-ask-password.xml +@@ -127,6 +127,17 @@ + + + ++ ++ ++ Echo the user input ++ instead of masking it. This is useful ++ when using ++ systemd-ask-password ++ to query for usernames. ++ ++ ++ ++ + + + Never ask for password +diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c +index 5c37cffc22..1ce8776d8a 100644 +--- a/src/ask-password/ask-password.c ++++ b/src/ask-password/ask-password.c +@@ -45,6 +45,7 @@ + static const char *arg_icon = NULL; + static const char *arg_id = NULL; + static const char *arg_message = NULL; ++static bool arg_echo = false; + static bool arg_use_tty = true; + static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; + static bool arg_accept_cached = false; +@@ -56,6 +57,7 @@ static void help(void) { + " -h --help Show this help\n" + " --icon=NAME Icon name\n" + " --timeout=SEC Timeout in sec\n" ++ " --echo Do not mask input (useful for usernames)\n" + " --no-tty Ask question via agent even on TTY\n" + " --accept-cached Accept cached passwords\n" + " --multiple List multiple passwords if available\n" +@@ -68,6 +70,7 @@ static int parse_argv(int argc, char *argv[]) { + enum { + ARG_ICON = 0x100, + ARG_TIMEOUT, ++ ARG_ECHO, + ARG_NO_TTY, + ARG_ACCEPT_CACHED, + ARG_MULTIPLE, +@@ -78,6 +81,7 @@ static int parse_argv(int argc, char *argv[]) { + { "help", no_argument, NULL, 'h' }, + { "icon", required_argument, NULL, ARG_ICON }, + { "timeout", required_argument, NULL, ARG_TIMEOUT }, ++ { "echo", no_argument, NULL, ARG_ECHO }, + { "no-tty", no_argument, NULL, ARG_NO_TTY }, + { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED }, + { "multiple", no_argument, NULL, ARG_MULTIPLE }, +@@ -109,6 +113,10 @@ static int parse_argv(int argc, char *argv[]) { + } + break; + ++ case ARG_ECHO: ++ arg_echo = true; ++ break; ++ + case ARG_NO_TTY: + arg_use_tty = false; + break; +@@ -160,7 +168,7 @@ int main(int argc, char *argv[]) { + if (arg_use_tty && isatty(STDIN_FILENO)) { + char *password = NULL; + +- if ((r = ask_password_tty(arg_message, timeout, NULL, &password)) >= 0) { ++ if ((r = ask_password_tty(arg_message, timeout, arg_echo, NULL, &password)) >= 0) { + puts(password); + free(password); + } +@@ -168,7 +176,7 @@ int main(int argc, char *argv[]) { + } else { + char **l; + +- if ((r = ask_password_agent(arg_message, arg_icon, arg_id, timeout, arg_accept_cached, &l)) >= 0) { ++ if ((r = ask_password_agent(arg_message, arg_icon, arg_id, timeout, arg_echo, arg_accept_cached, &l)) >= 0) { + char **p; + + STRV_FOREACH(p, l) { +diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c +index f586c2ef7f..6b0d2fc86a 100644 +--- a/src/firstboot/firstboot.c ++++ b/src/firstboot/firstboot.c +@@ -491,7 +491,7 @@ static int prompt_root_password(void) { + for (;;) { + _cleanup_free_ char *a = NULL, *b = NULL; + +- r = ask_password_tty(msg1, 0, NULL, &a); ++ r = ask_password_tty(msg1, 0, false, NULL, &a); + if (r < 0) { + log_error("Failed to query root password: %s", strerror(-r)); + return r; +@@ -502,7 +502,7 @@ static int prompt_root_password(void) { + break; + } + +- r = ask_password_tty(msg2, 0, NULL, &b); ++ r = ask_password_tty(msg2, 0, false, NULL, &b); + if (r < 0) { + log_error("Failed to query root password: %s", strerror(-r)); + clear_string(a); +diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c +index 8d03f4ad09..94a27f9010 100644 +--- a/src/shared/ask-password-api.c ++++ b/src/shared/ask-password-api.c +@@ -52,6 +52,7 @@ static void backspace_chars(int ttyfd, size_t p) { + int ask_password_tty( + const char *message, + usec_t until, ++ bool echo, + const char *flag_file, + char **_passphrase) { + +@@ -218,7 +219,7 @@ int ask_password_tty( + passphrase[p++] = c; + + if (!silent_mode && ttyfd >= 0) +- loop_write(ttyfd, "*", 1, false); ++ loop_write(ttyfd, echo ? &c : "*", 1, false); + + dirty = true; + } +@@ -300,6 +301,7 @@ int ask_password_agent( + const char *icon, + const char *id, + usec_t until, ++ bool echo, + bool accept_cached, + char ***_passphrases) { + +@@ -362,10 +364,12 @@ int ask_password_agent( + "PID="PID_FMT"\n" + "Socket=%s\n" + "AcceptCached=%i\n" ++ "Echo=%i\n" + "NotAfter="USEC_FMT"\n", + getpid(), + socket_name, + accept_cached ? 1 : 0, ++ echo ? 1 : 0, + until); + + if (message) +@@ -550,7 +554,7 @@ int ask_password_auto(const char *message, const char *icon, const char *id, + int r; + char *s = NULL, **l = NULL; + +- r = ask_password_tty(message, until, NULL, &s); ++ r = ask_password_tty(message, until, false, NULL, &s); + if (r < 0) + return r; + +@@ -561,5 +565,5 @@ int ask_password_auto(const char *message, const char *icon, const char *id, + *_passphrases = l; + return r; + } else +- return ask_password_agent(message, icon, id, until, accept_cached, _passphrases); ++ return ask_password_agent(message, icon, id, until, false, accept_cached, _passphrases); + } +diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h +index 3839a2df0f..704ee6e1b4 100644 +--- a/src/shared/ask-password-api.h ++++ b/src/shared/ask-password-api.h +@@ -23,10 +23,10 @@ + + #include "util.h" + +-int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase); ++int ask_password_tty(const char *message, usec_t until, bool echo, const char *flag_file, char **_passphrase); + + int ask_password_agent(const char *message, const char *icon, const char *id, +- usec_t until, bool accept_cached, char ***_passphrases); ++ usec_t until, bool echo, bool accept_cached, char ***_passphrases); + + int ask_password_auto(const char *message, const char *icon, const char *id, + usec_t until, bool accept_cached, char ***_passphrases); +diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c +index e7cbde285c..e6dc84b440 100644 +--- a/src/tty-ask-password-agent/tty-ask-password-agent.c ++++ b/src/tty-ask-password-agent/tty-ask-password-agent.c +@@ -214,7 +214,7 @@ static int parse_password(const char *filename, char **wall) { + _cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL; + uint64_t not_after = 0; + unsigned pid = 0; +- bool accept_cached = false; ++ bool accept_cached = false, echo = false; + + const ConfigTableItem items[] = { + { "Ask", "Socket", config_parse_string, 0, &socket_name }, +@@ -222,6 +222,7 @@ static int parse_password(const char *filename, char **wall) { + { "Ask", "Message", config_parse_string, 0, &message }, + { "Ask", "PID", config_parse_unsigned, 0, &pid }, + { "Ask", "AcceptCached", config_parse_bool, 0, &accept_cached }, ++ { "Ask", "Echo", config_parse_bool, 0, &echo }, + {} + }; + +@@ -314,7 +315,7 @@ static int parse_password(const char *filename, char **wall) { + return tty_fd; + } + +- r = ask_password_tty(message, not_after, filename, &password); ++ r = ask_password_tty(message, not_after, echo, filename, &password); + + if (arg_console) { + safe_close(tty_fd); diff --git a/0518-Update-TODO.patch b/0518-Update-TODO.patch new file mode 100644 index 0000000..d075b9a --- /dev/null +++ b/0518-Update-TODO.patch @@ -0,0 +1,21 @@ +From 0536ce5d0ceaf87f3e81faaff41d69ffeed2186f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 5 Oct 2014 15:29:20 -0400 +Subject: [PATCH] Update TODO + +--- + TODO | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/TODO b/TODO +index 526926f862..0c648f9931 100644 +--- a/TODO ++++ b/TODO +@@ -274,6 +274,7 @@ Features: + + * sd-event + - allow multiple signal handlers per signal? ++ - document chaining of signal handler for SIGCHLD and child handlers + + * in the final killing spree, detect processes from the root directory, and + complain loudly if they have argv[0][0] == '@' set. diff --git a/0519-terminal-remove-an-unused-initialization.patch b/0519-terminal-remove-an-unused-initialization.patch new file mode 100644 index 0000000..d4591fb --- /dev/null +++ b/0519-terminal-remove-an-unused-initialization.patch @@ -0,0 +1,22 @@ +From 0077776275cb753e478e0f92d4065dec5276c44a Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Sun, 5 Oct 2014 22:33:20 +0200 +Subject: [PATCH] terminal: remove an unused initialization + +--- + src/libsystemd-terminal/term-screen.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c +index 54bb04752c..5a053a31bd 100644 +--- a/src/libsystemd-terminal/term-screen.c ++++ b/src/libsystemd-terminal/term-screen.c +@@ -4131,7 +4131,7 @@ int term_screen_feed_keyboard(term_screen *screen, + unsigned int mods) { + _cleanup_free_ char *dyn = NULL; + static const size_t padding = 1; +- char buf[128], *start, *p = buf; ++ char buf[128], *start, *p; + + assert_return(screen, -EINVAL); + diff --git a/0520-build-sys-use-linux-memfd.h-if-available.patch b/0520-build-sys-use-linux-memfd.h-if-available.patch new file mode 100644 index 0000000..427caa1 --- /dev/null +++ b/0520-build-sys-use-linux-memfd.h-if-available.patch @@ -0,0 +1,90 @@ +From 27c64db6dff88ebe9761dfe3b0c073d2a9bf2e41 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 5 Oct 2014 18:41:31 -0400 +Subject: [PATCH] build-sys: use linux/memfd.h if available + +linux/memfd.h was added linux 3.17, so it might not be widely +available for a while. + +Also, check if memfd_create is defined, for the HAVE_LINUX_MEMFD_H +check to have a chance of succeeding. + +Also, collapse all ifdefs for memfd-related stuff, because they +were all added together so there's no need to check separately. +--- + configure.ac | 2 ++ + src/shared/memfd.c | 6 +++++- + src/shared/missing.h | 14 -------------- + 3 files changed, 7 insertions(+), 15 deletions(-) + +diff --git a/configure.ac b/configure.ac +index e33c8f75ac..caf1f0e54e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -283,6 +283,7 @@ AM_CONDITIONAL([HAVE_PYTHON_DEVEL], [test "$have_python_devel" = "yes"]) + AC_SEARCH_LIBS([dlsym], [dl], [], [AC_MSG_ERROR([*** Dynamic linking loader library not found])]) + AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([*** POSIX caps headers not found])]) + AC_CHECK_HEADERS([linux/btrfs.h], [], []) ++AC_CHECK_HEADERS([linux/memfd.h], [], []) + + # unconditionally pull-in librt with old glibc versions + AC_SEARCH_LIBS([clock_gettime], [rt], [], []) +@@ -300,6 +301,7 @@ 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, LO_FLAGS_PARTSCAN], + [], [], [[ +diff --git a/src/shared/memfd.c b/src/shared/memfd.c +index 1feca0c979..162c12f7a7 100644 +--- a/src/shared/memfd.c ++++ b/src/shared/memfd.c +@@ -25,11 +25,15 @@ + #include + #include + ++#ifdef HAVE_LINUX_MEMFD_H ++# include ++#endif ++ + #include "util.h" + #include "bus-label.h" +-#include "missing.h" + #include "memfd.h" + #include "utf8.h" ++#include "missing.h" + + int memfd_new(const char *name) { + _cleanup_free_ char *g = NULL; +diff --git a/src/shared/missing.h b/src/shared/missing.h +index 031fe2d1ce..656921d687 100644 +--- a/src/shared/missing.h ++++ b/src/shared/missing.h +@@ -65,25 +65,11 @@ + + #ifndef F_ADD_SEALS + #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +-#endif +- +-#ifndef F_GET_SEALS + #define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) +-#endif + +-#ifndef F_SEAL_SEAL + #define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +-#endif +- +-#ifndef F_SEAL_SHRINK + #define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +-#endif +- +-#ifndef F_SEAL_GROW + #define F_SEAL_GROW 0x0004 /* prevent file from growing */ +-#endif +- +-#ifndef F_SEAL_WRITE + #define F_SEAL_WRITE 0x0008 /* prevent writes */ + #endif + diff --git a/0521-sd-bus-sync-kdbus.h-ABI-break.patch b/0521-sd-bus-sync-kdbus.h-ABI-break.patch new file mode 100644 index 0000000..a01379b --- /dev/null +++ b/0521-sd-bus-sync-kdbus.h-ABI-break.patch @@ -0,0 +1,171 @@ +From d663f1b1a92a778bcdc68f29b8c08cb49431b4f7 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Mon, 6 Oct 2014 18:36:16 +0200 +Subject: [PATCH] sd-bus: sync kdbus.h (ABI break) + +The KDBUS_CMD_FREE ioctl now uses a struct rather than a direct pointer +to the offset to free. + +The KDBUS_CMD_MSG_CANCEL ioctl has also changes, but there's no user of +it yet in systemd. +--- + src/bus-proxyd/bus-proxyd.c | 6 +++++- + src/libsystemd/sd-bus/bus-control.c | 23 ++++++++++++++++++++--- + src/libsystemd/sd-bus/bus-kernel.c | 7 +++++-- + src/libsystemd/sd-bus/kdbus.h | 32 ++++++++++++++++++++++++++++++-- + 4 files changed, 60 insertions(+), 8 deletions(-) + +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +index 5d58cd2af4..cbec04933c 100644 +--- a/src/bus-proxyd/bus-proxyd.c ++++ b/src/bus-proxyd/bus-proxyd.c +@@ -730,6 +730,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { + } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) { + struct kdbus_cmd_name_list cmd = {}; + struct kdbus_name_list *name_list; ++ struct kdbus_cmd_free cmd_free; + struct kdbus_cmd_name *name; + _cleanup_strv_free_ char **owners = NULL; + char *arg0; +@@ -773,7 +774,10 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { + } + } + +- r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd.offset); ++ cmd_free.flags = 0; ++ cmd_free.offset = cmd.offset; ++ ++ r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd_free); + if (r < 0) + return synthetic_reply_method_errno(m, r, NULL); + +diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c +index d9a53c702f..dbd94fc46b 100644 +--- a/src/libsystemd/sd-bus/bus-control.c ++++ b/src/libsystemd/sd-bus/bus-control.c +@@ -223,6 +223,23 @@ _public_ int sd_bus_release_name(sd_bus *bus, const char *name) { + return bus_release_name_dbus1(bus, name); + } + ++static int kernel_cmd_free(sd_bus *bus, uint64_t offset) ++{ ++ struct kdbus_cmd_free cmd; ++ int r; ++ ++ assert(bus); ++ ++ cmd.flags = 0; ++ cmd.offset = offset; ++ ++ r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd); ++ if (r < 0) ++ return -errno; ++ ++ return 0; ++} ++ + static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { + struct kdbus_cmd_name_list cmd = {}; + struct kdbus_name_list *name_list; +@@ -269,9 +286,9 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { + } + } + +- r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset); ++ r = kernel_cmd_free(bus, cmd.offset); + if (r < 0) +- return -errno; ++ return r; + + return 0; + } +@@ -597,7 +614,7 @@ static int bus_get_owner_kdbus( + r = 0; + + fail: +- ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset); ++ kernel_cmd_free(bus, cmd->offset); + return r; + } + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 09ff25fe71..5ae1418afc 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -799,14 +799,17 @@ int bus_kernel_connect(sd_bus *b) { + } + + static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { ++ struct kdbus_cmd_free cmd; + uint64_t off _alignas_(8); + struct kdbus_item *d; + + assert(bus); + assert(k); + +- off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer; +- ioctl(bus->input_fd, KDBUS_CMD_FREE, &off); ++ cmd.flags = 0; ++ cmd.offset = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer; ++ ++ ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd); + + KDBUS_ITEM_FOREACH(d, k, items) { + +diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h +index 801125946b..8994b5673d 100644 +--- a/src/libsystemd/sd-bus/kdbus.h ++++ b/src/libsystemd/sd-bus/kdbus.h +@@ -444,6 +444,31 @@ struct kdbus_cmd_recv { + } __attribute__((aligned(8))); + + /** ++ * struct kdbus_cmd_cancel - struct to cancel a synchronously pending message ++ * @cookie The cookie of the pending message ++ * @flags Flags for the free command. Currently unused. ++ * ++ * This struct is used with the KDBUS_CMD_CANCEL ioctl. ++ */ ++struct kdbus_cmd_cancel { ++ __u64 cookie; ++ __u64 flags; ++} __attribute__((aligned(8))); ++ ++/** ++ * struct kdbus_cmd_free - struct to free a slice of memory in the pool ++ * @offset The offset of the memory slice, as returned by other ++ * ioctls ++ * @flags Flags for the free command. Currently unused. ++ * ++ * This struct is used with the KDBUS_CMD_FREE ioctl. ++ */ ++struct kdbus_cmd_free { ++ __u64 offset; ++ __u64 flags; ++} __attribute__((aligned(8))); ++ ++/** + * enum kdbus_policy_access_type - permissions of a policy record + * @_KDBUS_POLICY_ACCESS_NULL: Uninitialized/invalid + * @KDBUS_POLICY_ACCESS_USER: Grant access to a uid +@@ -710,6 +735,7 @@ struct kdbus_conn_info { + */ + struct kdbus_cmd_update { + __u64 size; ++ __u64 flags; + struct kdbus_item items[0]; + } __attribute__((aligned(8))); + +@@ -807,8 +833,10 @@ enum kdbus_ioctl_type { + struct kdbus_msg), + KDBUS_CMD_MSG_RECV = _IOWR(KDBUS_IOCTL_MAGIC, 0x41, + struct kdbus_cmd_recv), +- KDBUS_CMD_MSG_CANCEL = _IOW(KDBUS_IOCTL_MAGIC, 0x42, __u64 *), +- KDBUS_CMD_FREE = _IOW(KDBUS_IOCTL_MAGIC, 0x43, __u64 *), ++ KDBUS_CMD_MSG_CANCEL = _IOW(KDBUS_IOCTL_MAGIC, 0x42, ++ struct kdbus_cmd_cancel), ++ KDBUS_CMD_FREE = _IOW(KDBUS_IOCTL_MAGIC, 0x43, ++ struct kdbus_cmd_free), + + KDBUS_CMD_NAME_ACQUIRE = _IOWR(KDBUS_IOCTL_MAGIC, 0x50, + struct kdbus_cmd_name), diff --git a/0522-sd-bus-remove-unused-variable.patch b/0522-sd-bus-remove-unused-variable.patch new file mode 100644 index 0000000..b789c56 --- /dev/null +++ b/0522-sd-bus-remove-unused-variable.patch @@ -0,0 +1,22 @@ +From 13303f018d066a1c8378511f77fde127b0e14f64 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Mon, 6 Oct 2014 23:58:46 +0200 +Subject: [PATCH] sd-bus: remove unused variable + +It is no longer used after d663f1b1a92a778bcdc68f29b8c08cb49431b4f7 +--- + src/libsystemd/sd-bus/bus-kernel.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 5ae1418afc..92407133be 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -800,7 +800,6 @@ int bus_kernel_connect(sd_bus *b) { + + static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { + struct kdbus_cmd_free cmd; +- uint64_t off _alignas_(8); + struct kdbus_item *d; + + assert(bus); diff --git a/0523-keymap-Fix-touchpad-toggle-on-Toshiba-Satellite-P75-.patch b/0523-keymap-Fix-touchpad-toggle-on-Toshiba-Satellite-P75-.patch new file mode 100644 index 0000000..1e09998 --- /dev/null +++ b/0523-keymap-Fix-touchpad-toggle-on-Toshiba-Satellite-P75-.patch @@ -0,0 +1,24 @@ +From a046659f8551e1c8f79ba4b66472444e285255df Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Tue, 7 Oct 2014 11:20:04 +0200 +Subject: [PATCH] keymap: Fix touchpad toggle on Toshiba Satellite P75-A7200 + +Just like everywhere else we use KEY_F21 instead of KEY_TOUCHPAD_TOGGLE for X +friendliness. +--- + 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 8a1baa7c4b..1fea32a957 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -1094,7 +1094,7 @@ keyboard:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75 + KEYBOARD_KEY_13c=brightnessdown + KEYBOARD_KEY_13d=brightnessup + KEYBOARD_KEY_13e=switchvideomode +- KEYBOARD_KEY_13f=touchpad_toggle ++ KEYBOARD_KEY_13f=f21 # Touchpad toggle + KEYBOARD_KEY_9e=wlan + + ########################################################### diff --git a/0524-keymap-Fix-touchpad-toggle-key-on-Asus-laptops.patch b/0524-keymap-Fix-touchpad-toggle-key-on-Asus-laptops.patch new file mode 100644 index 0000000..41bcf22 --- /dev/null +++ b/0524-keymap-Fix-touchpad-toggle-key-on-Asus-laptops.patch @@ -0,0 +1,22 @@ +From 4e3deeedc15b03197d591850061316289245c9a9 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Tue, 7 Oct 2014 11:22:31 +0200 +Subject: [PATCH] keymap: Fix touchpad toggle key on Asus laptops + +https://launchpad.net/bugs/1377352 +--- + hwdb/60-keyboard.hwdb | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb +index 1fea32a957..59f467b784 100644 +--- a/hwdb/60-keyboard.hwdb ++++ b/hwdb/60-keyboard.hwdb +@@ -153,6 +153,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnASUS:pn* + + keyboard:name:Asus WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr* + keyboard:name:Eee PC WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr* ++keyboard:name:Asus Laptop extra buttons:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr* + KEYBOARD_KEY_6b=f21 # Touchpad Toggle + + ########################################################### diff --git a/0525-sd-bus-fix-use-after-free-in-close_kdbus_msg.patch b/0525-sd-bus-fix-use-after-free-in-close_kdbus_msg.patch new file mode 100644 index 0000000..d432d8a --- /dev/null +++ b/0525-sd-bus-fix-use-after-free-in-close_kdbus_msg.patch @@ -0,0 +1,35 @@ +From ca794c8e9583eb660f535af32c8c8281a284f270 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 7 Oct 2014 11:32:07 +0200 +Subject: [PATCH] sd-bus: fix use-after-free in close_kdbus_msg() + +Walk the items first, then free the memory of the message. + +Also, while at it, make coverity happy with an explicit (void) prefix. +We intentionally ignore the return value here. +--- + src/libsystemd/sd-bus/bus-kernel.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index 92407133be..b431d78139 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -808,8 +808,6 @@ static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { + cmd.flags = 0; + cmd.offset = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer; + +- ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd); +- + KDBUS_ITEM_FOREACH(d, k, items) { + + if (d->type == KDBUS_ITEM_FDS) +@@ -817,6 +815,8 @@ static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { + else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD) + safe_close(d->memfd.fd); + } ++ ++ (void) ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd); + } + + int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) { diff --git a/0526-sd-bus-fix-KDBUS_CMD_FREE-user.patch b/0526-sd-bus-fix-KDBUS_CMD_FREE-user.patch new file mode 100644 index 0000000..a4dafda --- /dev/null +++ b/0526-sd-bus-fix-KDBUS_CMD_FREE-user.patch @@ -0,0 +1,29 @@ +From 53e9dbcdfbae355aae8edb79d49e50a0ec3912d5 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 7 Oct 2014 12:02:04 +0200 +Subject: [PATCH] sd-bus: fix KDBUS_CMD_FREE user + +Fix a user of the KDBUS_CMD_FREE ioctl that was missed in the transition. +--- + src/libsystemd/sd-bus/bus-message.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index 400ba307bc..c7cb2e60bc 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -128,10 +128,11 @@ static void message_free(sd_bus_message *m) { + message_reset_parts(m); + + if (m->release_kdbus) { +- uint64_t off _alignas_(8); ++ struct kdbus_cmd_free cmd_free; + +- off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer; +- ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off); ++ cmd_free.flags = 0; ++ cmd_free.offset = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer; ++ (void) ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &cmd_free); + } + + if (m->free_kdbus) diff --git a/0527-sd-bus-check-return-value-of-vasprintf.patch b/0527-sd-bus-check-return-value-of-vasprintf.patch new file mode 100644 index 0000000..6f8e5aa --- /dev/null +++ b/0527-sd-bus-check-return-value-of-vasprintf.patch @@ -0,0 +1,32 @@ +From 8bf13eb1e02b9977ae1cd331ae5dc7305a305a09 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 7 Oct 2014 12:10:06 +0200 +Subject: [PATCH] sd-bus: check return value of vasprintf + +Check for OOM situations when vasprintf() returns < 0 in bus_error_setfv(). + +Spotted by coverity. +--- + src/libsystemd/sd-bus/bus-error.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c +index abdfd73204..5ca974a191 100644 +--- a/src/libsystemd/sd-bus/bus-error.c ++++ b/src/libsystemd/sd-bus/bus-error.c +@@ -194,8 +194,13 @@ int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_li + return -ENOMEM; + } + +- if (format) +- vasprintf((char**) &e->message, format, ap); ++ if (format) { ++ int r; ++ ++ r = vasprintf((char**) &e->message, format, ap); ++ if (r < 0) ++ return -ENOMEM; ++ } + + e->_need_free = 1; + diff --git a/0528-bus-proxyd-check-return-values-of-getpeercred-and-ge.patch b/0528-bus-proxyd-check-return-values-of-getpeercred-and-ge.patch new file mode 100644 index 0000000..71ed336 --- /dev/null +++ b/0528-bus-proxyd-check-return-values-of-getpeercred-and-ge.patch @@ -0,0 +1,37 @@ +From 55534fb5e4742b0db9ae5e1e0202c53804147697 Mon Sep 17 00:00:00 2001 +From: Daniel Mack +Date: Tue, 7 Oct 2014 12:36:09 +0200 +Subject: [PATCH] bus-proxyd: check return values of getpeercred() and + getpeersec() + +If we can't get the remote peer or security creds, bail out. + +Spotted by coverity. +--- + src/bus-proxyd/bus-proxyd.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c +index cbec04933c..ce571fa753 100644 +--- a/src/bus-proxyd/bus-proxyd.c ++++ b/src/bus-proxyd/bus-proxyd.c +@@ -1146,8 +1146,17 @@ int main(int argc, char *argv[]) { + sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; + + if (is_unix) { +- getpeercred(in_fd, &ucred); +- getpeersec(in_fd, &peersec); ++ r = getpeercred(in_fd, &ucred); ++ if (r < 0) { ++ log_error("Failed to get peer creds: %s", strerror(-r)); ++ goto finish; ++ } ++ ++ r = getpeersec(in_fd, &peersec); ++ if (r < 0) { ++ log_error("Failed to get security creds: %s", strerror(-r)); ++ goto finish; ++ } + } + + if (arg_drop_privileges) { diff --git a/0529-man-move-commandline-parsing-to-a-separate-section.patch b/0529-man-move-commandline-parsing-to-a-separate-section.patch new file mode 100644 index 0000000..aa21f91 --- /dev/null +++ b/0529-man-move-commandline-parsing-to-a-separate-section.patch @@ -0,0 +1,350 @@ +From 30d88d54f613f9f7831172876ebfd9e285fb043b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 7 Oct 2014 09:19:24 -0400 +Subject: [PATCH] man: move commandline parsing to a separate section + +It is very long already, and obscures the description of +ExecStart, and it is about to get longer. +--- + man/systemd.service.xml | 298 ++++++++++++++++++++++++------------------------ + 1 file changed, 148 insertions(+), 150 deletions(-) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index b9a2f8d82f..dbc82edbd4 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -352,72 +352,59 @@ + ExecStart= + Commands with their + arguments that are executed when this +- service is started. For each of the +- specified commands, the first argument +- must be an absolute and literal path +- to an executable. ++ service is started. The value is split ++ into zero or more command lines is ++ according to the rules described below ++ (see section "Command Lines" below). ++ + + When Type is + not , only one + command may and must be given. When + Type=oneshot is +- used, none or more than one command +- may be specified. Multiple command +- lines may be concatenated in a single +- directive by separating them with +- semicolons (these semicolons must be +- passed as separate +- words). Alternatively, this directive +- may be specified more than once with +- the same effect. Lone semicolons may +- be escaped as +- \;. If the empty +- string is assigned to this option, the +- list of commands to start is reset, +- prior assignments of this option will +- have no effect. If no ++ used, zero or more commands may be ++ specified. This can be specified by ++ providing multiple command lines in ++ the same directive , or alternatively, ++ this directive may be specified more ++ than once with the same effect. If the ++ empty string is assigned to this ++ option, the list of commands to start ++ is reset, prior assignments of this ++ option will have no effect. If no + ExecStart= is + specified, then the service must have + RemainAfterExit=yes + set. + +- Each command line is split on +- whitespace, with the first item being +- the command to execute, and the +- subsequent items being the arguments. +- Double quotes ("...") and single +- quotes ('...') may be used, in which +- case everything until the next +- matching quote becomes part of the +- same argument. Quotes themselves are +- removed after parsing. In addition, a +- trailing backslash +- (\) may be used to +- merge lines. This syntax is intended +- to be very similar to shell syntax, +- but only the meta-characters and +- expansions described in the following +- paragraphs are understood. +- Specifically, redirection using +- <, +- <<, +- >, and +- >>, pipes +- using |, and +- running programs in the background +- using & +- and other elements of shell +- syntax are not supported. +- ++ For each of the specified ++ commands, the first argument must be ++ an absolute and literal path to an ++ executable. Optionally, if the ++ absolute file name is prefixed with ++ @, the second token ++ will be passed as ++ argv[0] to the ++ executed process, followed by the ++ further arguments specified. If the ++ absolute filename is prefixed with ++ -, an exit code of ++ the command normally considered a ++ failure (i.e. non-zero exit status or ++ abnormal exit due to signal) is ++ ignored and considered success. If ++ both - and ++ @ are used, they ++ can appear in either order. + + If more than one command is + specified, the commands are invoked + sequentially in the order they appear + in the unit file. If one of the + commands fails (and is not prefixed +- with -), other lines +- are not executed, and the unit is +- considered failed. ++ with -), other ++ lines are not executed, and the unit ++ is considered failed. + + Unless + Type=forking is +@@ -425,106 +412,6 @@ + command line will be considered the + main process of the daemon. + +- The command line accepts +- % specifiers as +- described in +- systemd.unit5. +- Note that the first argument of the +- command line (i.e. the program to +- execute) may not include +- specifiers. +- +- Basic environment variable +- substitution is supported. Use +- ${FOO} as part of a +- word, or as a word of its own, on the +- command line, in which case it will be +- replaced by the value of the +- environment variable including all +- whitespace it contains, resulting in a +- single argument. Use +- $FOO as a separate +- word on the command line, in which +- case it will be replaced by the value +- of the environment variable split at +- whitespace, resulting in zero or more +- arguments. To pass a literal dollar +- sign, use $$. +- Variables whose value is not known at +- expansion time are treated as empty +- strings. Note that the first argument +- (i.e. the program to execute) may not +- be a variable. +- +- Variables to be used in this +- fashion may be defined through +- Environment= and +- EnvironmentFile=. +- In addition, variables listed in the +- section "Environment variables in +- spawned processes" in +- systemd.exec5, +- which are considered "static +- configuration", may be used (this includes +- e.g. $USER, but not +- $TERM). +- +- Optionally, if the absolute file +- name is prefixed with +- @, the second token +- will be passed as +- argv[0] to the +- executed process, followed by the +- further arguments specified. If the +- absolute filename is prefixed with +- -, an exit code of +- the command normally considered a +- failure (i.e. non-zero exit status or +- abnormal exit due to signal) is ignored +- and considered success. If both +- - and +- @ are used, they +- can appear in either order. +- +- Note that this setting does not +- directly support shell command +- lines. If shell command lines are to +- be used, they need to be passed +- explicitly to a shell implementation +- of some kind. Example: +- ExecStart=/bin/sh -c 'dmesg | tac' +- Example: +- ExecStart=/bin/echo one ; /bin/echo "two two" +- This will execute +- /bin/echo two +- times, each time with one argument: +- one and +- two two, +- respectively. Because two commands are +- specified, +- Type=oneshot must +- be used. +- +- Example: +- ExecStart=/bin/echo / >/dev/null & \; \ +-/bin/ls +- This will execute +- /bin/echo with five +- arguments: /, +- >/dev/null, +- &, +- ;, and +- /bin/ls. +- +- Example: +- Environment="ONE=one" 'TWO=two two' +-ExecStart=/bin/echo $ONE $TWO ${TWO} +- This will execute +- /bin/echo with four +- arguments: one, +- two, +- two, and +- two two. + + + +@@ -1274,6 +1161,117 @@ ExecStart=/bin/echo $ONE $TWO ${TWO} + + + ++ Command lines ++ ++ This section describes command line parsing and ++ variable and specifier substitions for ++ ExecStart=, ++ ExecStartPre=, ++ ExecStartPost=, ++ ExecReload=, ++ ExecStop=, and ++ ExecStopPost= options. ++ ++ Multiple command lines may be concatenated in a ++ single directive by separating them with semicolons ++ (these semicolons must be passed as separate words). ++ Lone semicolons may be escaped as ++ \;. ++ ++ Each command line is split on whitespace, with ++ the first item being the command to execute, and the ++ subsequent items being the arguments. Double quotes ++ ("...") and single quotes ('...') may be used, in ++ which case everything until the next matching quote ++ becomes part of the same argument. Quotes themselves ++ are removed after parsing. In addition, a trailing ++ backslash (\) may be used to merge ++ lines. ++ ++ This syntax is intended to be very similar to ++ shell syntax, but only the meta-characters and ++ expansions described in the following paragraphs are ++ understood. Specifically, redirection using ++ <, <<, ++ >, and ++ >>, pipes using ++ |, running programs in the ++ background using &, and ++ other elements of shell syntax are not ++ supported. ++ ++ The command line accepts % ++ specifiers as described in ++ systemd.unit5. ++ Note that the first argument of the command line ++ (i.e. the program to execute) may not include ++ specifiers. ++ ++ Basic environment variable substitution is ++ supported. Use ${FOO} as part of a ++ word, or as a word of its own, on the command line, in ++ which case it will be replaced by the value of the ++ environment variable including all whitespace it ++ contains, resulting in a single argument. Use ++ $FOO as a separate word on the ++ command line, in which case it will be replaced by the ++ value of the environment variable split at whitespace, ++ resulting in zero or more arguments. To pass a literal ++ dollar sign, use $$. Variables ++ whose value is not known at expansion time are treated ++ as empty strings. Note that the first argument ++ (i.e. the program to execute) may not be a ++ variable. ++ ++ Variables to be used in this fashion may be ++ defined through Environment= and ++ EnvironmentFile=. In addition, ++ variables listed in the section "Environment variables ++ in spawned processes" in ++ systemd.exec5, ++ which are considered "static configuration", may be ++ used (this includes e.g. $USER, but ++ not $TERM). ++ ++ Note that shell command lines are not directly ++ supported. If shell command lines are to be used, they ++ need to be passed explicitly to a shell implementation ++ of some kind. Example: ++ ExecStart=/bin/sh -c 'dmesg | tac' ++ ++ Example: ++ ++ ExecStart=/bin/echo one ; /bin/echo "two two" ++ ++ This will execute /bin/echo ++ two times, each time with one argument: ++ one and two two, ++ respectively. Because two commands are specified, ++ Type=oneshot must be used. ++ ++ Example: ++ ++ ExecStart=/bin/echo / >/dev/null & \; \ ++/bin/ls ++ ++ This will execute /bin/echo ++ with five arguments: /, ++ >/dev/null, ++ &, ;, and ++ /bin/ls. ++ ++ Example: ++ ++ Environment="ONE=one" 'TWO=two two' ++ExecStart=/bin/echo $ONE $TWO ${TWO} ++ ++ This will execute /bin/echo ++ with four arguments: one, ++ two, two, and ++ two two. ++ ++ ++ + See Also + + systemd1, diff --git a/0530-man-document-stripping-of-quotes.patch b/0530-man-document-stripping-of-quotes.patch new file mode 100644 index 0000000..0371968 --- /dev/null +++ b/0530-man-document-stripping-of-quotes.patch @@ -0,0 +1,77 @@ +From 5d9a2698e74eefc20ea7cbbaeaffb566e398f2ba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 7 Oct 2014 09:19:41 -0400 +Subject: [PATCH] man: document stripping of quotes + +--- + man/systemd.service.xml | 50 ++++++++++++++++++++++++++++++++----------------- + 1 file changed, 33 insertions(+), 17 deletions(-) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index dbc82edbd4..50ff2f5bd5 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -1215,13 +1215,39 @@ + contains, resulting in a single argument. Use + $FOO as a separate word on the + command line, in which case it will be replaced by the +- value of the environment variable split at whitespace, +- resulting in zero or more arguments. To pass a literal +- dollar sign, use $$. Variables +- whose value is not known at expansion time are treated +- as empty strings. Note that the first argument +- (i.e. the program to execute) may not be a +- variable. ++ value of the environment variable split at whitespace ++ resulting in zero or more arguments. For this type of ++ expansion, quotes and respected when splitting into ++ words, and afterwards removed. ++ ++ Example: ++ ++ Environment="ONE=one" 'TWO=two two' ++ExecStart=/bin/echo $ONE $TWO ${TWO} ++ ++ This will execute /bin/echo ++ with four arguments: one, ++ two, two, and ++ two two. ++ ++ Example: ++ Environment=ONE='one' "TWO='two two' too" THREE= ++ExecStart=/bin/echo ${ONE} ${TWO} ${THREE} ++ExecStart=/bin/echo $ONE $TWO $THREE ++ This results in echo being ++ called twice, the first time with arguments ++ 'one', ++ 'two two' too, , ++ and the second time with arguments ++ one, two two, ++ too. ++ ++ ++ To pass a literal dollar sign, use ++ $$. Variables whose value is not ++ known at expansion time are treated as empty ++ strings. Note that the first argument (i.e. the ++ program to execute) may not be a variable. + + Variables to be used in this fashion may be + defined through Environment= and +@@ -1259,16 +1285,6 @@ + >/dev/null, + &, ;, and + /bin/ls. +- +- Example: +- +- Environment="ONE=one" 'TWO=two two' +-ExecStart=/bin/echo $ONE $TWO ${TWO} +- +- This will execute /bin/echo +- with four arguments: one, +- two, two, and +- two two. + + + diff --git a/0531-Update-TODO.patch b/0531-Update-TODO.patch new file mode 100644 index 0000000..4f4c5e4 --- /dev/null +++ b/0531-Update-TODO.patch @@ -0,0 +1,28 @@ +From d19e85f0d474ed1882561b458d528cbae49f640e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 7 Oct 2014 09:11:03 -0400 +Subject: [PATCH] Update TODO + +--- + TODO | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/TODO b/TODO +index 0c648f9931..10baa1cec3 100644 +--- a/TODO ++++ b/TODO +@@ -10,6 +10,14 @@ Bugfixes: + + * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point. + ++After killing 'systemd --user', systemctl restart user@... fails. ++ ++ExecStart with unicode characters fails in strv_split_quoted: ++ ++ [Service] ++ Environment=ONE='one' "TWO='two two' too" THREE= ++ ExecStart=/bin/python3 -c 'import sys;print(sys.argv)' $ONE $TWO $THREE ++ + External: + * Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros. + diff --git a/0532-proc-sys-prefixes-are-not-necessary-for-sysctl-anymo.patch b/0532-proc-sys-prefixes-are-not-necessary-for-sysctl-anymo.patch new file mode 100644 index 0000000..9c1c0e1 --- /dev/null +++ b/0532-proc-sys-prefixes-are-not-necessary-for-sysctl-anymo.patch @@ -0,0 +1,36 @@ +From 1b600437bac3c0676cc72f589909c4cbfe38ba10 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 7 Oct 2014 02:02:59 -0400 +Subject: [PATCH] /proc/sys prefixes are not necessary for sysctl anymore + +--- + man/sysctl.d.xml | 2 +- + rules/99-systemd.rules.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml +index 5529fc98bf..3002ebd0fd 100644 +--- a/man/sysctl.d.xml ++++ b/man/sysctl.d.xml +@@ -158,7 +158,7 @@ + /etc/udev/rules.d/99-bridge.rules: + + +- ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge" ++ ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/net/bridge" + + + /etc/sysctl.d/bridge.conf: +diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in +index aa435c4143..e30d9a8f1b 100644 +--- a/rules/99-systemd.rules.in ++++ b/rules/99-systemd.rules.in +@@ -52,7 +52,7 @@ SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??: + + # Apply sysctl variables to network devices (and only to those) as they appear. + +-ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/$name --prefix=/proc/sys/net/ipv4/neigh/$name --prefix=/proc/sys/net/ipv6/conf/$name --prefix=/proc/sys/net/ipv6/neigh/$name" ++ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/net/ipv4/conf/$name --prefix=/net/ipv4/neigh/$name --prefix=/net/ipv6/conf/$name --prefix=/net/ipv6/neigh/$name" + + # Pull in backlight save/restore for all backlight devices and + # keyboard backlights diff --git a/0533-core-don-t-allow-enabling-if-unit-is-masked.patch b/0533-core-don-t-allow-enabling-if-unit-is-masked.patch new file mode 100644 index 0000000..64c80d5 --- /dev/null +++ b/0533-core-don-t-allow-enabling-if-unit-is-masked.patch @@ -0,0 +1,33 @@ +From 85fa479ca5358d9472245eb0da6a86b5d644ccf9 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 7 Oct 2014 13:35:41 +0200 +Subject: [PATCH] core: don't allow enabling if unit is masked + +--- + src/shared/install.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/src/shared/install.c b/src/shared/install.c +index fa064c230f..945bb2748d 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1516,6 +1516,19 @@ int unit_file_enable( + return r; + + STRV_FOREACH(i, files) { ++ UnitFileState state; ++ ++ state = unit_file_get_state(scope, root_dir, *i); ++ if (state < 0) { ++ log_error("Failed to get unit file state for %s: %s", *i, strerror(-state)); ++ return state; ++ } ++ ++ 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); + if (r < 0) + return r; diff --git a/0534-fedora-disable-resolv.conf-symlink.patch b/0534-fedora-disable-resolv.conf-symlink.patch new file mode 100644 index 0000000..66b5c96 --- /dev/null +++ b/0534-fedora-disable-resolv.conf-symlink.patch @@ -0,0 +1,22 @@ +From e2c48e9a4cff991e432472cd12a7b47a3049ece9 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 + +--- + 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 f567c8d6ea..125d6e0a17 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 +-) + C /etc/nsswitch.conf - - - - + C /etc/pam.d - - - - diff --git a/0535-fedora-add-bridge-sysctl-configuration.patch b/0535-fedora-add-bridge-sysctl-configuration.patch new file mode 100644 index 0000000..5824d10 --- /dev/null +++ b/0535-fedora-add-bridge-sysctl-configuration.patch @@ -0,0 +1,87 @@ +From ea3a099cb842beca5292d71e78f54c9dddde0ac6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 7 Oct 2014 01:49:10 -0400 +Subject: [PATCH] fedora: add bridge sysctl configuration + +Udev rule is added to load those settings when the bridge +module is loaded. + +https://bugzilla.redhat.com/show_bug.cgi?id=634736 +--- + Makefile.am | 8 ++++++-- + rules/.gitignore | 1 + + rules/99-bridge.rules.in | 9 +++++++++ + sysctl.d/50-bridge.conf | 4 ++++ + 4 files changed, 20 insertions(+), 2 deletions(-) + create mode 100644 rules/99-bridge.rules.in + create mode 100644 sysctl.d/50-bridge.conf + +diff --git a/Makefile.am b/Makefile.am +index e52db1793b..41e94575ef 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -445,7 +445,8 @@ CLEANFILES += \ + $(nodist_zshcompletion_DATA) + + dist_sysctl_DATA = \ +- sysctl.d/50-default.conf ++ sysctl.d/50-default.conf \ ++ sysctl.d/50-bridge.conf + + dist_systemunit_DATA = \ + units/graphical.target \ +@@ -3281,7 +3282,8 @@ dist_udevrules_DATA += \ + rules/95-udev-late.rules + + nodist_udevrules_DATA += \ +- rules/99-systemd.rules ++ rules/99-systemd.rules \ ++ rules/99-bridge.rules + + dist_udevhwdb_DATA = \ + hwdb/20-pci-vendor-model.hwdb \ +@@ -3306,10 +3308,12 @@ sharepkgconfig_DATA = \ + + EXTRA_DIST += \ + rules/99-systemd.rules.in \ ++ rules/99-bridge.rules.in \ + src/udev/udev.pc.in + + CLEANFILES += \ + rules/99-systemd.rules \ ++ rules/99-bridge.rules \ + src/udev/udev.pc + + EXTRA_DIST += \ +diff --git a/rules/.gitignore b/rules/.gitignore +index 93a50ddd80..46c7f3ce91 100644 +--- a/rules/.gitignore ++++ b/rules/.gitignore +@@ -1 +1,2 @@ + /99-systemd.rules ++/99-bridge.rules +diff --git a/rules/99-bridge.rules.in b/rules/99-bridge.rules.in +new file mode 100644 +index 0000000000..f46f96bd2e +--- /dev/null ++++ b/rules/99-bridge.rules.in +@@ -0,0 +1,9 @@ ++# 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. ++ ++# Apply sysctl settings to bridges ++ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/net/bridge" +diff --git a/sysctl.d/50-bridge.conf b/sysctl.d/50-bridge.conf +new file mode 100644 +index 0000000000..b586bf15fa +--- /dev/null ++++ b/sysctl.d/50-bridge.conf +@@ -0,0 +1,4 @@ ++# Disable netfilter on bridges. ++net.bridge.bridge-nf-call-ip6tables = 0 ++net.bridge.bridge-nf-call-iptables = 0 ++net.bridge.bridge-nf-call-arptables = 0 diff --git a/systemd.spec b/systemd.spec index 3fbaa58..f20c00f 100644 --- a/systemd.spec +++ b/systemd.spec @@ -16,7 +16,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 216 -Release: 8%{?gitcommit:.git%{gitcommit}}%{?dist} +Release: 9%{?gitcommit:.git%{gitcommit}}%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: A System and Service Manager @@ -35,25 +35,543 @@ Source5: 85-display-manager.preset Source6: yum-protect-systemd.conf # Patch series is available from http://cgit.freedesktop.org/systemd/systemd-stable/log/?h=v215-stable -# GIT_DIR=~/src/systemd/.git git format-patch-ab -M -N --no-signature v215..v215-stable -# i=1; for p in 0*patch;do printf "Patch%03d: %s\n" $i $p; ((i++));done - -# Presently not accepted upstream, but we disable systemd-resolved in -# the presets anyways, and this unbreaks anaconda/lorax/livecd-creator -# etc. -Patch0: 0001-resolved-Move-symlink-creation-from-tmpfiles-to-daem.patch - -# timesyncd patches from upstream to be nice to NTP pool -Patch0002: 0002-timesyncd-check-if-stratum-is-valid.patch -Patch0003: 0003-timesyncd-fix-calculation-of-transmit-time.patch -Patch0004: 0004-timesyncd-get-kernel-timestamp-in-nanoseconds.patch -Patch0005: 0005-timesyncd-check-root-distance.patch -Patch0006: 0006-timesyncd-manager-don-t-clear-current_server_name-if.patch -Patch0007: 0007-timesyncd-wait-before-reconnecting-to-first-server.patch -Patch0008: 0008-timesyncd-remove-retry_timer-logic-which-is-covered-.patch -Patch0009: 0009-timesyncd-allow-two-missed-replies-before-reselectin.patch -Patch0010: 0010-timesyncd-don-t-reset-polling-interval-when-reselect.patch -Patch0011: 0011-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch +# GIT_DIR=~/src/systemd/.git git format-patch-ab -M -N --no-signature v216..master +# i=1; for p in 0*patch;do printf "Patch%04d: %s\n" $i $p; ((i++));done +Patch0001: 0001-systemctl-fail-in-the-case-that-no-unit-files-were-f.patch +Patch0002: 0002-build-remove-repeated-KMOD-section.patch +Patch0003: 0003-machine-id-setup-don-t-try-to-read-UUID-from-VM-cont.patch +Patch0004: 0004-resolved-dns-rr-fix-typo.patch +Patch0005: 0005-resolved-fix-which-return-codes-we-check.patch +Patch0006: 0006-journal-remote-remove-unreachable-code.patch +Patch0007: 0007-util-return-after-freeing-all-members-of-array.patch +Patch0008: 0008-journal-upload-make-sure-that-r-is-initialized.patch +Patch0009: 0009-resolved-write-resolv.conf-search-switch-arguments.patch +Patch0010: 0010-sd-event-add-API-to-access-epoll_fd.patch +Patch0011: 0011-journalctl-add-t-identifier-STRING-option.patch +Patch0012: 0012-CODING_STYLE-document-that-we-don-t-break-lines-at-8.patch +Patch0013: 0013-util-change-return-value-of-startswith-to-non-const.patch +Patch0014: 0014-util-simplify-close_nointr-a-bit.patch +Patch0015: 0015-util-make-asynchronous_close-really-work-like-an-asy.patch +Patch0016: 0016-core-unify-how-we-generate-the-prefix-string-when-du.patch +Patch0017: 0017-service-asynchronous_close-already-checks-for-negati.patch +Patch0018: 0018-service-remove-some-pointless-linebreaks-to-make-thi.patch +Patch0019: 0019-service-don-t-invoke-functions-at-the-same-time-as-d.patch +Patch0020: 0020-service-strv-introduce-strv_find_startswith-and-make.patch +Patch0021: 0021-manager-reuse-sockaddr_union-instead-of-redefining-o.patch +Patch0022: 0022-manager-don-t-dispatch-sd_notify-messages-and-SIGCHL.patch +Patch0023: 0023-core-allow-informing-systemd-about-service-status-ch.patch +Patch0024: 0024-notify-send-STOPPING-1-from-our-daemons.patch +Patch0025: 0025-update-TODO.patch +Patch0026: 0026-bus-when-terminating-our-bus-actviated-services-that.patch +Patch0027: 0027-execute-explain-in-a-comment-why-close_all_fds-is-in.patch +Patch0028: 0028-service-use-the-right-timeout-for-stop-processes-we-.patch +Patch0029: 0029-update-TODO.patch +Patch0030: 0030-service-allow-services-of-Type-oneshot-that-specify-.patch +Patch0031: 0031-install-simplify-usage-of-_cleanup_-macros.patch +Patch0032: 0032-systemctl-in-list-unit-files-always-show-legend-even.patch +Patch0033: 0033-update-TODO.patch +Patch0034: 0034-dbus1-generator-properly-free-the-FILE.patch +Patch0035: 0035-shared-add-MAXSIZE-and-use-it-in-resolved.patch +Patch0036: 0036-missing.h-add-fake-__NR_memfd_create-for-MIPS.patch +Patch0037: 0037-missing.h-add-a-cpp-warning-for-__NR_memfd_create-on.patch +Patch0038: 0038-core-add-support-for-a-configurable-system-wide-star.patch +Patch0039: 0039-core-print-startup-finished-messages-even-if-we-log-.patch +Patch0040: 0040-resolved-fix-typo-in-log-message.patch +Patch0041: 0041-core-introduce-poweroff-as-new-failure-action-types.patch +Patch0042: 0042-core-split-up-starting-manager-state-into-initializi.patch +Patch0043: 0043-update-TODO.patch +Patch0044: 0044-systemctl-fix-broken-list-unit-files-with-root.patch +Patch0045: 0045-sd-event-split-run-into-prepare-wait-dispatch.patch +Patch0046: 0046-sd-event-sd_event_prepare-stay-in-PREPARED-if-sd_eve.patch +Patch0047: 0047-update-TODO.patch +Patch0048: 0048-Revert-systemctl-fix-broken-list-unit-files-with-roo.patch +Patch0049: 0049-udev-hwdb-do-not-look-at-usb_device-parents.patch +Patch0050: 0050-update-TODO.patch +Patch0051: 0051-NEWS-Fix-typos.patch +Patch0052: 0052-missing-add-BPF_XOR.patch +Patch0053: 0053-networkd-wait-online-add-missing-short-option-i-to-o.patch +Patch0054: 0054-test-compress-make-sure-asserts-with-side-effects-us.patch +Patch0055: 0055-test-path-util-use-assert_se-in-all-assertions.patch +Patch0056: 0056-test-util-use-assert_se-for-call-to-safe_mkdir-with-.patch +Patch0057: 0057-sd-bus-remove-unused-call-bus_kernel_create_monitor.patch +Patch0058: 0058-systemctl-Correct-error-message-printed-when-bus_pro.patch +Patch0059: 0059-sd-bus-don-t-include-internal-header-memfd.h-in-publ.patch +Patch0060: 0060-util-make-sure-reset_all_signal_handlers-continues-w.patch +Patch0061: 0061-util-reset-signals-when-we-fork-off-agents.patch +Patch0062: 0062-util-make-use-of-newly-added-reset_signal_mask-call-.patch +Patch0063: 0063-sd-journal-never-log-anything-by-default-from-a-libr.patch +Patch0064: 0064-logind-add-HandleLidSwitchDocked-option-to-logind.co.patch +Patch0065: 0065-units-order-systemd-fsck-.service-after-local-fs-pre.patch +Patch0066: 0066-hibernate-resume-add-a-tool-to-write-a-device-node-s.patch +Patch0067: 0067-hibernate-resume-generator-add-a-generator-for-insta.patch +Patch0068: 0068-man-reword-sd-hibernate-resume-description-and-add-l.patch +Patch0069: 0069-Document-.-.-udev-match-syntax.patch +Patch0070: 0070-po-update-Polish-translation.patch +Patch0071: 0071-keymap-Adjust-for-more-Samsung-900X4-series.patch +Patch0072: 0072-systemctl-fix-broken-list-unit-files-with-root.patch +Patch0073: 0073-tmpfiles-make-resolv.conf-entry-conditional-on-resol.patch +Patch0074: 0074-TODO.patch +Patch0075: 0075-shared-drop-UNIQUE.patch +Patch0076: 0076-shared-make-container_of-use-unique-variable-names.patch +Patch0077: 0077-login-fix-memory-leak-on-DropController.patch +Patch0078: 0078-udev-add-missing-new-line-in-udevadm-error.patch +Patch0079: 0079-util-make-lookup_uid-global.patch +Patch0080: 0080-bus-split-bus_map_all_properties-into-multiple-helpe.patch +Patch0081: 0081-terminal-add-system-view-interface.patch +Patch0082: 0082-terminal-add-input-interface.patch +Patch0083: 0083-terminal-add-evdev-elements-to-idev.patch +Patch0084: 0084-terminal-add-xkb-based-keyboard-devices-to-idev.patch +Patch0085: 0085-terminal-add-systemd-evcat-input-debugging-tool.patch +Patch0086: 0086-man-add-sample-glib-sd-event-integration.patch +Patch0087: 0087-util-fix-minimal-race-where-we-might-miss-SIGTERMs-w.patch +Patch0088: 0088-update-TODO.patch +Patch0089: 0089-terminal-remove-unused-variable.patch +Patch0090: 0090-sd-journal-properly-convert-object-size-on-big-endia.patch +Patch0091: 0091-sd-journal-verify-that-object-start-with-the-field-n.patch +Patch0092: 0092-terminal-sysview-don-t-return-uninitialized-error-co.patch +Patch0093: 0093-nspawn-fix-network-interface.patch +Patch0094: 0094-terminal-free-xkb-state-on-keyboard-destruction.patch +Patch0095: 0095-terminal-free-sysview-device-names-on-destruction.patch +Patch0096: 0096-bus-fix-use-after-free-in-slot-release.patch +Patch0097: 0097-macro-use-unique-variable-names-for-math-macros.patch +Patch0098: 0098-use-the-switch_root-function-in-shutdown.patch +Patch0099: 0099-locale-fix-sending-PropertiesChanged-for-x11-keymap-.patch +Patch0100: 0100-bus-don-t-skip-interfaces-in-bus_message_map_propert.patch +Patch0101: 0101-networkctl-do-not-mix-dns-and-ntp-servers.patch +Patch0102: 0102-update-TODO.patch +Patch0103: 0103-hibernate-resume-refuse-to-run-outside-of-an-initrd.patch +Patch0104: 0104-sd-rtnl-log-if-kernel-buffer-is-overrun-as-we-curren.patch +Patch0105: 0105-sd-event-allow-naming-event-sources.patch +Patch0106: 0106-sd-event-use-event-source-name-rather-than-address-i.patch +Patch0107: 0107-sd-event-name-event-sources-used-in-libraries.patch +Patch0108: 0108-sd-event-simplify-sd_event_source_set_name.patch +Patch0109: 0109-systemd-firstboot.service-fix-man-page-section.patch +Patch0110: 0110-systemd-firstboot-fix-typo-in-man-page.patch +Patch0111: 0111-systemd-journal-upload-fix-invalid-After.patch +Patch0112: 0112-Fix-a-few-typos-in-log-messages.patch +Patch0113: 0113-timesyncd-check-if-stratum-is-valid.patch +Patch0114: 0114-timesyncd-fix-calculation-of-transmit-time.patch +Patch0115: 0115-timesyncd-get-kernel-timestamp-in-nanoseconds.patch +Patch0116: 0116-timesyncd-check-root-distance.patch +Patch0117: 0117-Update-Russian-translation.patch +Patch0118: 0118-completion-filter-templates-from-restartable-units.patch +Patch0119: 0119-udev-remove-userspace-firmware-loading-support.patch +Patch0120: 0120-udev-bump-event-timeout-to-60-seconds.patch +Patch0121: 0121-libudev-fix-symbol-version-for-udev_queue_flush-and-.patch +Patch0122: 0122-Update-french-translation.patch +Patch0123: 0123-Fix-a-few-more-typos.patch +Patch0124: 0124-sd-ipv4ll-name-the-correct-source.patch +Patch0125: 0125-journal-compress-use-LZ4_compress_continue.patch +Patch0126: 0126-test-compress-also-test-with-incompressible-inputs.patch +Patch0127: 0127-systemd-fix-error-message.patch +Patch0128: 0128-cgroup-util-shorten-cg_path_get_session.patch +Patch0129: 0129-test-dhcp6-client-Fix-option-length.patch +Patch0130: 0130-sd-dhcp6-client-properly-calculate-buffer-size-when-.patch +Patch0131: 0131-timesyncd-manager-don-t-clear-current_server_name-if.patch +Patch0132: 0132-units-make-emergency.service-conflict-with-rescue.se.patch +Patch0133: 0133-units-m4-is-not-needed-for-rescue.service.patch +Patch0134: 0134-units-update-rescue.service-and-emergency.service.patch +Patch0135: 0135-Quote-unit-names-in-suggested-systemctl-commandlines.patch +Patch0136: 0136-journalctl-Allow-to-disable-line-cap-with-lines-all.patch +Patch0137: 0137-missing-add-IFF_MULTI_QUEUE.patch +Patch0138: 0138-test-network-fix-off-by-one-error-in-test.patch +Patch0139: 0139-journal-remote-fix-check-if-realloc-failed.patch +Patch0140: 0140-config-parser-fix-mem-leak.patch +Patch0141: 0141-login-fix-mem-leak.patch +Patch0142: 0142-login-simplify-controller-handling.patch +Patch0143: 0143-rules-remove-firmware-loading-rules.patch +Patch0144: 0144-sd-rtnl-don-t-assign-to-unused-variable.patch +Patch0145: 0145-timesyncd-wait-before-reconnecting-to-first-server.patch +Patch0146: 0146-timesyncd-remove-retry_timer-logic-which-is-covered-.patch +Patch0147: 0147-timesyncd-allow-two-missed-replies-before-reselectin.patch +Patch0148: 0148-timesyncd-don-t-reset-polling-interval-when-reselect.patch +Patch0149: 0149-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch +Patch0150: 0150-man-fix-file-extension-in-udev-rules-example.patch +Patch0151: 0151-base_filesystem_create-do-not-try-to-create-root-if-.patch +Patch0152: 0152-initrd-parse-etc.service-ignore-return-code-of-daemo.patch +Patch0153: 0153-update-TODO.patch +Patch0154: 0154-base-file-system-always-generate-error-messages-loca.patch +Patch0155: 0155-update-TODO.patch +Patch0156: 0156-man-two-fixes-reported-on-irc-by-wget.patch +Patch0157: 0157-build-sys-configure-option-to-disable-hibernation.patch +Patch0158: 0158-localed-double-free-in-error-path-and-modernization.patch +Patch0159: 0159-localed-remove-free_and_copy.patch +Patch0160: 0160-localed-log-locale-keymap-changes-in-detail.patch +Patch0161: 0161-localed-introduce-helper-function-to-simplify-matchi.patch +Patch0162: 0162-localed-check-for-partially-matching-converted-keyma.patch +Patch0163: 0163-systemd-fix-argument-ordering-in-UnsetAndSetEnvironm.patch +Patch0164: 0164-man-fix-typo.patch +Patch0165: 0165-Update-TODO.patch +Patch0166: 0166-networkd-move-carrier-gained-lost-handling-from-link.patch +Patch0167: 0167-networkd-link-save-link-flags-when-the-link-is-added.patch +Patch0168: 0168-networkd-link-do-not-manage-loopback-links.patch +Patch0169: 0169-networkd-link-clarify-log-message-when-receiving-add.patch +Patch0170: 0170-build-don-t-install-busname-units-and-target-if-kdbu.patch +Patch0171: 0171-networkd-link-allow-loopback-links-to-be-manage-but-.patch +Patch0172: 0172-hibernate-resume-let-s-move-all-hibernate-resume-too.patch +Patch0173: 0173-man-make-it-more-clear-that-the-concepts-systemctl-1.patch +Patch0174: 0174-exec-factor-out-most-function-arguments-of-exec_spaw.patch +Patch0175: 0175-exec-move-code-executed-after-fork-into-exec_child.patch +Patch0176: 0176-exit-status-fix-URL-in-comment.patch +Patch0177: 0177-update-TODO.patch +Patch0178: 0178-man-fix-references-to-systemctl-man-page-which-is-no.patch +Patch0179: 0179-hwdb-Update-database-of-Bluetooth-company-identifier.patch +Patch0180: 0180-bus-factor-out-bus-policy-items.patch +Patch0181: 0181-bus-add-kdbus-endpoint-types.patch +Patch0182: 0182-bus-add-code-to-create-custom-endpoints-and-set-thei.patch +Patch0183: 0183-bus-parse-BusPolicy-directive-in-service-files.patch +Patch0184: 0184-namespace-add-support-for-custom-kdbus-endpoint.patch +Patch0185: 0185-exit-status-add-new-exit-code-for-custom-endpoint-er.patch +Patch0186: 0186-service-hook-up-custom-endpoint-logic.patch +Patch0187: 0187-networkd-tuntap-return-correct-error-when-dev-net-tu.patch +Patch0188: 0188-networkd-netdev-failing-to-create-a-netdev-is-not-fa.patch +Patch0189: 0189-units-networkd-order-after-udev.patch +Patch0190: 0190-networkd-add-preferred-source-to-dhcp4-gateway-route.patch +Patch0191: 0191-TODO.patch +Patch0192: 0192-sd-network-add-_get_network_file-api.patch +Patch0193: 0193-networkctl-show-the-network-file-applied-to-each-lin.patch +Patch0194: 0194-udev-net_setup_link-export-the-.link-filename-applie.patch +Patch0195: 0195-udev-link-config-only-set-name-on-success.patch +Patch0196: 0196-networkctl-show-the-link-file-applied-to-each-link.patch +Patch0197: 0197-networkd-allow-specification-of-DHCP-route-metric.patch +Patch0198: 0198-machined-remove-redundant-sd_notify.patch +Patch0199: 0199-rules-net-setup-link-preserve-ID_NET_LINK_FILE-and-I.patch +Patch0200: 0200-rules-net-setup-link-remove-stray-linebreak.patch +Patch0201: 0201-namespace-avoid-posible-use-of-uninitialized-variabl.patch +Patch0202: 0202-execute-silence-warnings.patch +Patch0203: 0203-hwdb-update.patch +Patch0204: 0204-build-sys-make-hibernation-support-configure-option-.patch +Patch0205: 0205-udev-import-the-full-db-on-MOVE-events-for-devices-w.patch +Patch0206: 0206-udev-event-keep-one-rtnl-per-worker-rather-than-per-.patch +Patch0207: 0207-udev-net_setup_link-open-ethtool-and-rtnl-connection.patch +Patch0208: 0208-udev-netif_rename-don-t-log-to-kmsg.patch +Patch0209: 0209-udev-drop-print_kmsg.patch +Patch0210: 0210-sd-dhcp6-client-Implement-Elapsed-Time-option.patch +Patch0211: 0211-test-dhcp6-client-Add-checks-for-Elapsed-Time-option.patch +Patch0212: 0212-TODO-Remove-Elapsed-Time-DHCPv6-option-as-it-is-done.patch +Patch0213: 0213-udev-fix-copy-paste-error-in-log-message.patch +Patch0214: 0214-udev-timeout-increase-timeout.patch +Patch0215: 0215-backlight-Avoid-error-when-state-restore-is-disabled.patch +Patch0216: 0216-terminal-discard-async-read-errors-for-evdev.patch +Patch0217: 0217-terminal-remove-redundant-struct-prefixes.patch +Patch0218: 0218-udev-allow-removing-tags-via-TAG-foobar.patch +Patch0219: 0219-terminal-remove-unused-set.h-inclusion-in-idev.patch +Patch0220: 0220-terminal-enable-sessions-in-evcat-after-taking-contr.patch +Patch0221: 0221-terminal-fix-wrong-return-value-in-idev-if-fcntl-fai.patch +Patch0222: 0222-terminal-drop-redundant-assertion.patch +Patch0223: 0223-bus-avoid-using-m-kdbus-after-freeing-it.patch +Patch0224: 0224-journal-do-not-dereference-already-freed-patterns.patch +Patch0225: 0225-terminal-fix-uninitialized-variable-in-strerror-log-.patch +Patch0226: 0226-journal-do-not-leak-mmaps-on-OOM.patch +Patch0227: 0227-bus-unref-buscreds-on-failure.patch +Patch0228: 0228-test-fix-mem-leak-in-fdopen-test.patch +Patch0229: 0229-activate-fix-fd-leak-in-do_accept.patch +Patch0230: 0230-manager-use-correct-cleanup-function.patch +Patch0231: 0231-firstboot-silence-a-warning.patch +Patch0232: 0232-udev-timeout-warn-after-a-third-of-the-timeout-befor.patch +Patch0233: 0233-analyze-avoid-a-null-dereference.patch +Patch0234: 0234-core-smack-setup-Actually-allow-for-succesfully-load.patch +Patch0235: 0235-analyze-fix-mem-leak.patch +Patch0236: 0236-core-fix-a-potential-mem-leak.patch +Patch0237: 0237-core-use-correct-function-to-free-CalendarSpec.patch +Patch0238: 0238-networkd-remove-vestigial-event-sources.patch +Patch0239: 0239-resolved-fall-back-to-hardcoded-ifindex-when-checkin.patch +Patch0240: 0240-sd-dhcp-fix-test-of-magic-cookie.patch +Patch0241: 0241-test-fix-test-of-uid-range.patch +Patch0242: 0242-build-colorize-gcc-only-if-on-tty.patch +Patch0243: 0243-hashmap-introduce-hash_ops-to-make-struct-Hashmap-sm.patch +Patch0244: 0244-hashmap-set-remove-unused-functions.patch +Patch0245: 0245-hashmap-minor-hashmap_replace-optimization.patch +Patch0246: 0246-sd-bus-use-proper-ITERATOR_FIRST-abstraction.patch +Patch0247: 0247-remove-unneeded-error.h-includes.patch +Patch0248: 0248-terminal-fix-missing-hashmap_new-conversions.patch +Patch0249: 0249-man-sd_bus_error-typo-fix.patch +Patch0250: 0250-udev-split-out-help-and-modernise-a-bit.patch +Patch0251: 0251-udev-split-out-parse_argv.patch +Patch0252: 0252-udev-drop-duplicate-logging.patch +Patch0253: 0253-udev-don-t-close-std-in-out-err.patch +Patch0254: 0254-udevd-initialize-epoll_event-structs-on-allocation.patch +Patch0255: 0255-udev-only-print-after-final-log-level-has-been-deter.patch +Patch0256: 0256-udev-apply-permissions-to-static-nodes-before-signal.patch +Patch0257: 0257-libudev-drop-util_lookup_-user-group.patch +Patch0258: 0258-libudev-util-drop-util_delete_path.patch +Patch0259: 0259-udev-util-use-log_level_from_string.patch +Patch0260: 0260-udevd-use-safe_ato-in-place-of-strto.patch +Patch0261: 0261-udev-rules-add-missing-whitespace-to-log-message.patch +Patch0262: 0262-gpt-auto-generator-fix-typo.patch +Patch0263: 0263-libsystemd-network-avoid-double-free-in-error-case.patch +Patch0264: 0264-hostname-add-missing-EMITS_CHANGE-annotation.patch +Patch0265: 0265-bootchart-use-safe_atod-rather-than-strtod.patch +Patch0266: 0266-bootchart-oom-check-correct-variable.patch +Patch0267: 0267-sd-bus-sd_bus_message_get_errno-should-only-return-p.patch +Patch0268: 0268-terminal-sd_bus_error_get_errno-returns-positive-err.patch +Patch0269: 0269-missing-memfd_create-takes-unsigned-int-flags-in-fin.patch +Patch0270: 0270-core-fix-resource-leak-in-manager_environment_add.patch +Patch0271: 0271-sysv-generator-fix-resource-leak.patch +Patch0272: 0272-shared-fix-resource-leak-in-config_parse_default_ins.patch +Patch0273: 0273-test-silence-a-coverity-report.patch +Patch0274: 0274-terminal-remove-dead-code-checking-O_WRONLY.patch +Patch0275: 0275-util-remove-a-unnecessary-check.patch +Patch0276: 0276-sysctl-make-prefix-allow-all-kinds-of-sysctl-paths.patch +Patch0277: 0277-bus-never-respond-to-GetManagedObjects-on-sub-paths.patch +Patch0278: 0278-bus-fix-error-leak-in-bus_node_exists.patch +Patch0279: 0279-networkd-dhcp4-fix-unchecked-return-value.patch +Patch0280: 0280-libsystemd-network-dhcp-test-assert-that-malloc0-suc.patch +Patch0281: 0281-udev-rules-close-empty-file.patch +Patch0282: 0282-nss-resolve-remove-dead-code.patch +Patch0283: 0283-udev-event-modernize-spawn_read.patch +Patch0284: 0284-udev-event-explicitly-don-t-read-from-invalid-fd.patch +Patch0285: 0285-udev-event-modernize-spawn_exec.patch +Patch0286: 0286-shared-conf-parser.patch +Patch0287: 0287-logind-fix-typo.patch +Patch0288: 0288-sysv-generator-don-t-check-first-if-hashmap-contains.patch +Patch0289: 0289-Fix-resource-leak-coverity-CID-1237760.patch +Patch0290: 0290-systemctl-fix-resource-leak-CID-1237747.patch +Patch0291: 0291-sd-bus-sync-kdbus.h.patch +Patch0292: 0292-tests-fix-resource-mem-leaks.patch +Patch0293: 0293-libudev-monitor-warn-if-we-fail-to-request-SO_PASSCR.patch +Patch0294: 0294-shared-conf-parser-don-t-leak-memory-on-error-in-DEF.patch +Patch0295: 0295-bus-fix-bus_print_property-to-use-int-for-booleans.patch +Patch0296: 0296-udev-fix-path-for-database-names-on-change-event.patch +Patch0297: 0297-man-use-the-escape-for-in-example-instead-of-space.patch +Patch0298: 0298-journal-Do-not-count-on-the-compiler-initializing-fo.patch +Patch0299: 0299-udev-link-config-remove-unneded-linux-netdevice.h-in.patch +Patch0300: 0300-sd-rtnl-rtnl-message-remove-unneeded-linux-includes.patch +Patch0301: 0301-include-fcntl.h-rather-than-sys-fcntl.h.patch +Patch0302: 0302-mount-order-options-before-other-arguments-to-mount.patch +Patch0303: 0303-journal-upload-Remove-compilation-warning.patch +Patch0304: 0304-core-Remove-uninitialized-warnings-from-bus-endpoint.patch +Patch0305: 0305-sysusers-Remove-some-gcc-warnings-about-uninitialize.patch +Patch0306: 0306-journal-remote-check-return-code-of-sd_event_default.patch +Patch0307: 0307-udevd-parse_argv-warn-if-argumens-are-invalid.patch +Patch0308: 0308-udevd-check-return-of-various-functions.patch +Patch0309: 0309-udevadm-hwdb-check-return-value-of-fseeko.patch +Patch0310: 0310-udev-node-warn-if-chmod-chown-fails.patch +Patch0311: 0311-udev-ctrl-log-if-setting-SO_PASSCRED-fails.patch +Patch0312: 0312-udev-fix-typos.patch +Patch0313: 0313-udevd-don-t-fail-if-run-udev-exists.patch +Patch0314: 0314-timesyncd-check-return-of-setting-IP_TOS.patch +Patch0315: 0315-nss-remove-dead-code.patch +Patch0316: 0316-pty-include-linux-ioctl.h-for-TIOCSIG.patch +Patch0317: 0317-shared-label.h-add-missing-stdio.h-include.patch +Patch0318: 0318-shared-sparse-endian.h-add-missing-byteswap.h-includ.patch +Patch0319: 0319-test-warn-if-we-could-not-parse-the-loop-count-argum.patch +Patch0320: 0320-shared-wtmp-utmp-don-t-clear-store_wtmp-in-utmp_put_.patch +Patch0321: 0321-socket-introduce-SELinuxContextFromNet-option.patch +Patch0322: 0322-login-pause-devices-before-acknowledging-VT-switches.patch +Patch0323: 0323-terminal-add-graphics-interface.patch +Patch0324: 0324-terminal-add-grdev-DRM-backend.patch +Patch0325: 0325-terminal-add-systemd-modeset-debugging-tool.patch +Patch0326: 0326-nspawn-don-t-try-to-create-veth-link-with-too-long-i.patch +Patch0327: 0327-terminal-parse-ID_SEAT-not-only-for-parents-but-the-.patch +Patch0328: 0328-terminal-forward-DEVICE_CHANGE-events-via-sysview.patch +Patch0329: 0329-terminal-make-drm-connectors-first-level-devices.patch +Patch0330: 0330-terminal-reduce-speed-of-morphing-colors-in-modeset-.patch +Patch0331: 0331-terminal-modeset-forward-DEVICE_CHANGE-events-into-g.patch +Patch0332: 0332-terminal-grdev-treat-udev-devices-without-devnum-as-.patch +Patch0333: 0333-terminal-grdev-refresh-device-state-on-hotplug-event.patch +Patch0334: 0334-terminal-split-grdrm_crtc_commit-apart.patch +Patch0335: 0335-terminal-grdev-raise-frame-event-after-DISPLAY_ADD-C.patch +Patch0336: 0336-terminal-grdev-schedule-virtual-frame-events-if-hw-d.patch +Patch0337: 0337-terminal-restructure-some-logging-calls-in-grdrm.patch +Patch0338: 0338-terminal-fix-mode-sync-for-connectors.patch +Patch0339: 0339-test-udev-restrict-nemuric-uid-s-to-existing-ones.patch +Patch0340: 0340-bus-policy-story-mandatory-items-in-right-list.patch +Patch0341: 0341-bus-policy-append-items-rather-than-prepending-them.patch +Patch0342: 0342-bus_policy-set-i-ug-id_valid.patch +Patch0343: 0343-bus-policy-resolve-ug-id-of-POLICY_ITEM_-USER-GROUP.patch +Patch0344: 0344-bus-policy-implement-dump_items-with-LIST_FOREACH.patch +Patch0345: 0345-bus-policy-do-not-exit-from-policy_dump.patch +Patch0346: 0346-bus-policy-print-numeric-gu-id-in-dump_items.patch +Patch0347: 0347-bus-policy-add-policy-check-function.patch +Patch0348: 0348-bus-policy-add-test-utility.patch +Patch0349: 0349-terminal-print-RESYNC-state-in-evcat.patch +Patch0350: 0350-terminal-always-call-_enable-_disable-on-evdev-devic.patch +Patch0351: 0351-terminal-forward-evdev-RESYNC-events-to-linked-devic.patch +Patch0352: 0352-terminal-raise-sysview-DEVICE_CHANGE-events-per-atta.patch +Patch0353: 0353-test-util-make-valgrind-happy.patch +Patch0354: 0354-util-add-alloca_align.patch +Patch0355: 0355-bus-align-kdbus-ioctl-parameters-to-8byte.patch +Patch0356: 0356-login-add-public-sd_session_get_desktop-API.patch +Patch0357: 0357-man-fix-typo-and-add-link.patch +Patch0358: 0358-exit-status.c-bring-EXIT_BUS_ENDPOINT-label-in-line-.patch +Patch0359: 0359-terminal-make-evdev-logind-matches-per-session.patch +Patch0360: 0360-terminal-allow-user-context-to-be-retrieved-stored.patch +Patch0361: 0361-terminal-handle-callback-errors-in-sysview-instead-o.patch +Patch0362: 0362-terminal-signal-object-removal-during-sysview_contex.patch +Patch0363: 0363-util-avoid-non-portable-__WORDSIZE.patch +Patch0364: 0364-sd-bus-sync-kdbus.h-API-ABI-break.patch +Patch0365: 0365-logind-add-support-for-Triton2-Power-Button.patch +Patch0366: 0366-terminal-fix-spelling-mistake.patch +Patch0367: 0367-Fix-warning-about-unused-variable-with-SELINUX.patch +Patch0368: 0368-localed-rename-write_data_x11-to-x11_write_data.patch +Patch0369: 0369-sd-bus-sync-kdbus.h-API-break.patch +Patch0370: 0370-sd-bus-sync-kdbus.h.patch +Patch0371: 0371-Silence-some-unchecked-return-value-warnings.patch +Patch0372: 0372-terminal-fix-tile-offset-calculation.patch +Patch0373: 0373-terminal-verify-grdev-tiles-are-correctly-linked.patch +Patch0374: 0374-terminal-verify-kernel-returned-DRM-events-are-not-t.patch +Patch0375: 0375-terminal-provide-display-dimensions-to-API-users.patch +Patch0376: 0376-bus-remove-unused-check.patch +Patch0377: 0377-bus-policy-split-API-for-bus-proxyd.patch +Patch0378: 0378-fileio-make-parse_env_file-return-number-of-parsed-i.patch +Patch0379: 0379-localectl-print-warning-when-there-are-options-given.patch +Patch0380: 0380-bus-proxyd-add-some-asserts.patch +Patch0381: 0381-shared-path-util-try-to-make-PATH_FORECH_PREFIX-look.patch +Patch0382: 0382-bus-proxy-drop-one-wrong-assert.patch +# Patch0383: 0383-readahead-wipe-out-readahead.patch +Patch0384: 0384-delta-warn-if-diff-failed.patch +Patch0385: 0385-nspawn-check-some-more-return-values.patch +Patch0386: 0386-journal-remote-initialize-writer-hashmap-before-use.patch +Patch0387: 0387-journal-remote-fix-counting-of-events-written.patch +Patch0388: 0388-journal-build-fix-when-LZ4-is-enabled-but-XZ-is-not.patch +Patch0389: 0389-man-sd_event_new-tweaks.patch +Patch0390: 0390-build-sys-add-sd_session_get_desktop-to-Makefile-man.patch +Patch0391: 0391-man-add-sd_event_add_signal-3.patch +Patch0392: 0392-man-add-sd_event_add_child-3.patch +Patch0393: 0393-man-document-sd_event_add_-defer-post-exit.patch +Patch0394: 0394-man-use-constant-markup-for-errno-value.patch +Patch0395: 0395-only-build-and-install-systemd-bus-proxyd-if-enable-.patch +Patch0396: 0396-build-sys-do-not-distribute-make-man-rules.py.patch +Patch0397: 0397-do-not-install-factory-etc-pam.d-if-disable-pam.patch +Patch0398: 0398-Revert-only-build-and-install-systemd-bus-proxyd-if-.patch +Patch0399: 0399-make-utmp-wtmp-support-configurable.patch +Patch0400: 0400-systemd-tmpfiles-Fix-IGNORE_DIRECTORY_PATH-age-handl.patch +Patch0401: 0401-test-bus-policy-load-policy-files-from-TEST_DIR.patch +Patch0402: 0402-shutdownd-clean-up-initialization-of-struct.patch +Patch0403: 0403-shell-completion-zsh-journalctl-s-b-changes.patch +Patch0404: 0404-catalog-add-Polish-translation.patch +Patch0405: 0405-logind-add-support-for-TPS65217-Power-Button.patch +Patch0406: 0406-bootchart-parse-userinput-with-safe_atoi.patch +Patch0407: 0407-bootchart-check-return-of-strftime.patch +Patch0408: 0408-test-bus-policy-silence-coverity.patch +Patch0409: 0409-bootchart-Do-not-try-to-access-data-for-non-existing.patch +Patch0410: 0410-sd-bus-clean-up-string-length-calculation.patch +Patch0411: 0411-terminal-add-sysview_seat_switch_to.patch +Patch0412: 0412-bus-sync-kdbus.h-ABI-break.patch +Patch0413: 0413-terminal-add-helper-to-retrieve-the-seat-of-a-sessio.patch +Patch0414: 0414-bus-use-2M-as-maximum-message-size-in-benchmark.patch +Patch0415: 0415-journalctl-do-not-output-reboot-markers-when-running.patch +Patch0416: 0416-journal-remote-fix-handling-of-non-blocking-sources.patch +Patch0417: 0417-swap-introduce-Discard-property.patch +Patch0418: 0418-fstab-generator-properly-deal-with-discard-as-non-la.patch +Patch0419: 0419-core-swap-follow-the-configured-unit-by-default.patch +Patch0420: 0420-core-swap-advertise-Discard-over-dbus.patch +Patch0421: 0421-core-dbus-simplify-handling-of-CPUQuotaPerSecUSec.patch +Patch0422: 0422-Do-not-format-USEC_INFINITY-as-NULL.patch +Patch0423: 0423-nspawn-log-when-tearing-down-of-loop-device-fails.patch +Patch0424: 0424-util-silence-coverity.patch +Patch0425: 0425-udev-hwdb-New-Entry-for-Dell-XPS12-9Q33-keyboard.patch +Patch0426: 0426-core-execute-don-t-leak-strv.patch +Patch0427: 0427-shared-util-use-nicer-idiom-to-silence-Coverity.patch +Patch0428: 0428-vconsole-silence-coverity.patch +Patch0429: 0429-test-path-util-fix-a-mem-leak-and-avoid-confusing-co.patch +Patch0430: 0430-test-date-don-t-fail-test-if-log_max_level-is-higher.patch +Patch0431: 0431-test-fileio-Remove-dead-check.patch +Patch0432: 0432-core-limit-timestamp-to-sane-precision.patch +Patch0433: 0433-tmpfiles-use-allocated-buffer-for-path.patch +Patch0434: 0434-shared-util-use-nicer-idiom-to-silence-Coverity.patch +Patch0435: 0435-tests-add-tests-for-hashmap-set-_steal_first.patch +Patch0436: 0436-gitignore-add-test-set.patch +Patch0437: 0437-Remove-repeated-includes.patch +Patch0438: 0438-core-swap-only-make-configured-units-part-of-swap.ta.patch +Patch0439: 0439-hwdb-Update-database-of-Bluetooth-company-identifier.patch +Patch0440: 0440-PORTING-DBUS1-we-use-1.-llu-not-0.-llu-for-D-Bus-uni.patch +Patch0441: 0441-sd-bus-use-terms-from-the-D-Bus-Specification-a-bit-.patch +Patch0442: 0442-terminal-move-unifont-internal.h-to-unifont.h.patch +Patch0443: 0443-terminal-add-unifont_get_width-height.patch +Patch0444: 0444-terminal-move-unifont-map-to-datadir.patch +Patch0445: 0445-terminal-add-term.h-header-for-library-users.patch +Patch0446: 0446-terminal-add-helpers-to-retrieve-page-dimensions.patch +Patch0447: 0447-barrier-fix-up-constructor-error-handling.patch +Patch0448: 0448-Correct-a-few-typos.patch +Patch0449: 0449-sd-bus-sync-kdbus.h-ABI-break.patch +Patch0450: 0450-localectl-count-locale-variables-from-0-instead-of-V.patch +Patch0451: 0451-localectl-always-print-warnings-with-log_warning-ins.patch +Patch0452: 0452-journalctl-add-utc-option.patch +Patch0453: 0453-add-a-transient-user-unit-directory.patch +Patch0454: 0454-Rename-user_runtime-to-user_runtime_dir.patch +Patch0455: 0455-Fix-order-and-document-user-unit-dirs.patch +Patch0456: 0456-virt-detect-that-we-are-running-inside-the-docker-co.patch +Patch0457: 0457-sd-bus-sync-kdbus.h-ABI-break.patch +Patch0458: 0458-sd-dhcp6-client-support-custom-DUIDs.patch +Patch0459: 0459-sd-dhcp6-support-custom-DUID-s-up-to-the-size-specif.patch +Patch0460: 0460-sd-dhcp6-specify-the-type-explicitly-when-setting-cu.patch +Patch0461: 0461-sd-dhcp6-do-basic-sanity-checking-of-supplied-DUID.patch +Patch0462: 0462-update-TODO.patch +Patch0463: 0463-kdbus-make-sure-we-never-invoke-free-on-an-uninitial.patch +Patch0464: 0464-kdbus-don-t-clobber-return-values-use-strjoin-instea.patch +Patch0465: 0465-systemctl-remove-spurious-newline.patch +Patch0466: 0466-Revert-mount-order-options-before-other-arguments-to.patch +Patch0467: 0467-firstboot-silence-coverity.patch +Patch0468: 0468-man-add-sd_event_get_fd-3.patch +Patch0469: 0469-man-add-sd_event_set_name-3.patch +Patch0470: 0470-test-barrier-add-checks-after-the-barrier-constructo.patch +Patch0471: 0471-glib-event-glue-remove-some-unnecessary-lines.patch +Patch0472: 0472-man-fix-sd_event_set_name-compilation.patch +Patch0473: 0473-bootchart-use-n-a-if-PRETTY_NAME-is-not-found.patch +Patch0474: 0474-journalctl-make-utc-work-everywhere.patch +Patch0475: 0475-fileio-label-return-error-when-writing-fails.patch +Patch0476: 0476-terminal-fix-back-buffer-selection-on-DRM-page-flip.patch +Patch0477: 0477-terminal-make-utf8-decoder-return-length.patch +Patch0478: 0478-terminal-grdev-simplify-DRM-event-parsing.patch +Patch0479: 0479-terminal-drm-provide-pipe-target-callback.patch +Patch0480: 0480-terminal-grdev-provide-front-and-back-buffer-to-rend.patch +Patch0481: 0481-terminal-grdev-allow-arbitrary-fb-age-contexts.patch +Patch0482: 0482-terminal-drm-clear-applied-flag-when-changing-state.patch +Patch0483: 0483-terminal-add-screen-renderer.patch +Patch0484: 0484-terminal-subterm-use-screen-renderer.patch +Patch0485: 0485-terminal-unifont-add-built-in-fallback-glyph.patch +Patch0486: 0486-terminal-idev-don-t-map-XKB_KEY_NoSymbol-as-ASCII-0.patch +Patch0487: 0487-terminal-screen-add-keyboard-mapping.patch +Patch0488: 0488-terminal-idev-add-helper-to-match-keyboard-shortcuts.patch +Patch0489: 0489-terminal-screen-mark-cursor-dirty-on-enabled-disable.patch +Patch0490: 0490-terminal-screen-add-cursor-rendering.patch +Patch0491: 0491-terminal-screen-add-color-converter.patch +Patch0492: 0492-terminal-screen-adjust-screen-age-only-on-update.patch +Patch0493: 0493-pty-optimize-read-loop.patch +Patch0494: 0494-console-add-user-console-daemon.patch +Patch0495: 0495-man-use-more-markup-in-daemon-7.patch +Patch0496: 0496-sd-event-check-the-value-of-received-signal.patch +Patch0497: 0497-core-namespace-remove-invalid-check.patch +Patch0498: 0498-core-namespace-remove-invalid-check.patch +Patch0499: 0499-sd-bus-split-out-cleanup-into-separate-function.patch +Patch0500: 0500-fstab-generator-Small-cleanup.patch +Patch0501: 0501-sd-id128-do-stricter-checking-of-random-boot-id.patch +Patch0502: 0502-man-say-that-SecureBits-are-space-separated.patch +Patch0503: 0503-build-sys-fix-make-distcheck.patch +Patch0504: 0504-systemd-bus-proxyd-distribute-the-.in-file-also-for-.patch +Patch0505: 0505-consoled-move-from-bin-to-lib-systemd.patch +Patch0506: 0506-consoled-add-a-unit-file.patch +Patch0507: 0507-test-only-use-assert_se.patch +Patch0508: 0508-terminal-fix-restoring-of-screen-flags.patch +Patch0509: 0509-terminal-fix-TERM_FLAG_-comment.patch +Patch0510: 0510-terminal-subterm-skip-setting-parent-s-cursor.patch +Patch0511: 0511-terminal-screen-save-state-in-separate-object.patch +Patch0512: 0512-terminal-screen-add-support-for-alternate-screen-buf.patch +Patch0513: 0513-terminal-subterm-leave-bold-light-conversion-to-pare.patch +Patch0514: 0514-terminal-screen-perform-bold-light-conversion-only-o.patch +Patch0515: 0515-terminal-idev-don-t-remove-consumed-mods-from-kbd-ma.patch +Patch0516: 0516-bus-add-assert-to-check-that-we-re-not-freeing-a-sta.patch +Patch0517: 0517-ask-password-Add-echo-to-enable-echoing-the-user-inp.patch +Patch0518: 0518-Update-TODO.patch +Patch0519: 0519-terminal-remove-an-unused-initialization.patch +Patch0520: 0520-build-sys-use-linux-memfd.h-if-available.patch +Patch0521: 0521-sd-bus-sync-kdbus.h-ABI-break.patch +Patch0522: 0522-sd-bus-remove-unused-variable.patch +Patch0523: 0523-keymap-Fix-touchpad-toggle-on-Toshiba-Satellite-P75-.patch +Patch0524: 0524-keymap-Fix-touchpad-toggle-key-on-Asus-laptops.patch +Patch0525: 0525-sd-bus-fix-use-after-free-in-close_kdbus_msg.patch +Patch0526: 0526-sd-bus-fix-KDBUS_CMD_FREE-user.patch +Patch0527: 0527-sd-bus-check-return-value-of-vasprintf.patch +Patch0528: 0528-bus-proxyd-check-return-values-of-getpeercred-and-ge.patch +Patch0529: 0529-man-move-commandline-parsing-to-a-separate-section.patch +Patch0530: 0530-man-document-stripping-of-quotes.patch +Patch0531: 0531-Update-TODO.patch +Patch0532: 0532-proc-sys-prefixes-are-not-necessary-for-sysctl-anymo.patch +Patch0533: 0533-core-don-t-allow-enabling-if-unit-is-masked.patch +Patch0534: 0534-fedora-disable-resolv.conf-symlink.patch + # kernel-install patch for grubby, drop if grubby is obsolete Patch1000: kernel-install-grubby.patch @@ -270,8 +788,12 @@ systemd-journal-gatewayd serves journal events over the network using HTTP. --exclude units/.gitignore \ --exclude units/user/.gitignore \ --exclude src/libsystemd/sd-bus/PORTING-DBUS1 \ + --exclude CODING_STYLE \ + --exclude src/readahead/Makefile \ + --exclude src/libsystemd-terminal/unifont-def.h \ %{patches} %endif + %ifarch ppc ppc64 ppc64le # Disable link warnings, somehow they cause the link to fail. sed -r -i 's/\blibsystemd-(login|journal|id128|daemon).c \\/\\/' Makefile.am @@ -301,6 +823,7 @@ CONFIGURE_OPTS=( --with-rc-local-script-path-start=/etc/rc.d/rc.local --with-ntp-servers='0.%{ntpvendor}.pool.ntp.org 1.%{ntpvendor}.pool.ntp.org 2.%{ntpvendor}.pool.ntp.org 3.%{ntpvendor}.pool.ntp.org' --disable-kdbus + --disable-terminal ) pushd build3 @@ -567,8 +1090,8 @@ getent passwd systemd-journal-upload >/dev/null 2>&1 || useradd -r -l -g systemd %dir %{_sysconfdir}/udev %dir %{_sysconfdir}/udev/rules.d %dir %{_prefix}/lib/systemd -%dir %{_prefix}/lib/systemd/system-generators -%dir %{_prefix}/lib/systemd/user-generators +%{_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 @@ -666,15 +1189,6 @@ getent passwd systemd-journal-upload >/dev/null 2>&1 || useradd -r -l -g systemd %exclude %{_prefix}/lib/systemd/systemd-journal-remote %{_prefix}/lib/systemd/systemd-* %{_prefix}/lib/udev -%{_prefix}/lib/systemd/system-generators/systemd-cryptsetup-generator -%{_prefix}/lib/systemd/system-generators/systemd-getty-generator -%{_prefix}/lib/systemd/system-generators/systemd-rc-local-generator -%{_prefix}/lib/systemd/system-generators/systemd-fstab-generator -%{_prefix}/lib/systemd/system-generators/systemd-system-update-generator -%{_prefix}/lib/systemd/system-generators/systemd-efi-boot-generator -%{_prefix}/lib/systemd/system-generators/systemd-gpt-auto-generator -%{_prefix}/lib/systemd/system-generators/systemd-sysv-generator -%{_prefix}/lib/systemd/system-generators/systemd-debug-generator %{_prefix}/lib/tmpfiles.d/systemd.conf %{_prefix}/lib/tmpfiles.d/systemd-nologin.conf %{_prefix}/lib/tmpfiles.d/x11.conf @@ -814,6 +1328,10 @@ getent passwd systemd-journal-upload >/dev/null 2>&1 || useradd -r -l -g systemd %{_datadir}/systemd/gatewayd %changelog +* Fri Oct 03 2014 Zbigniew Jędrzejewski-Szmek - 216-9 +- Update to latest git, but without the readahead removal patch + (#1114786, #1141137) + * Wed Oct 01 2014 Kay Sievers - 216-8 - revert "don't reset selinux context during CHANGE events"