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/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/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/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/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/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/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/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/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/0002-timesyncd-check-if-stratum-is-valid.patch b/0113-timesyncd-check-if-stratum-is-valid.patch similarity index 77% rename from 0002-timesyncd-check-if-stratum-is-valid.patch rename to 0113-timesyncd-check-if-stratum-is-valid.patch index 73194e3..17ac17c 100644 --- a/0002-timesyncd-check-if-stratum-is-valid.patch +++ b/0113-timesyncd-check-if-stratum-is-valid.patch @@ -1,15 +1,14 @@ -From df5380ac8abfc615b4baa0d001afe0e605d34d9b Mon Sep 17 00:00:00 2001 +From 07610e108e2d3f046da683a3a69c4d5cccd2cf8e 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 +Subject: [PATCH] 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 +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 @@ -22,6 +21,3 @@ index d80c72f..60f39c6 100644 log_debug("Server is not synchronized. Disconnecting."); return manager_connect(m); } --- -2.1.0 - diff --git a/0003-timesyncd-fix-calculation-of-transmit-time.patch b/0114-timesyncd-fix-calculation-of-transmit-time.patch similarity index 86% rename from 0003-timesyncd-fix-calculation-of-transmit-time.patch rename to 0114-timesyncd-fix-calculation-of-transmit-time.patch index 323616c..4e817db 100644 --- a/0003-timesyncd-fix-calculation-of-transmit-time.patch +++ b/0114-timesyncd-fix-calculation-of-transmit-time.patch @@ -1,18 +1,16 @@ -From 6840db7f47122699d420a80c2e6b6a34c7818759 Mon Sep 17 00:00:00 2001 +From 73c76e6330d31e1d04454fd7408dd56b4eedca9f 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 +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. - -(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 +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 @@ -33,6 +31,3 @@ index 60f39c6..3339606 100644 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-timesyncd-get-kernel-timestamp-in-nanoseconds.patch b/0115-timesyncd-get-kernel-timestamp-in-nanoseconds.patch similarity index 90% rename from 0004-timesyncd-get-kernel-timestamp-in-nanoseconds.patch rename to 0115-timesyncd-get-kernel-timestamp-in-nanoseconds.patch index 53e59d3..0096750 100644 --- a/0004-timesyncd-get-kernel-timestamp-in-nanoseconds.patch +++ b/0115-timesyncd-get-kernel-timestamp-in-nanoseconds.patch @@ -1,15 +1,14 @@ -From 6ec4258a64383467322da227adfe4780a4777f3a Mon Sep 17 00:00:00 2001 +From 487a36821ea214a73e1d0dcbd6d84123b50d1135 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 +Subject: [PATCH] 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 +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) { @@ -61,6 +60,3 @@ index 3339606..2b0580c 100644 if (r < 0) return -errno; --- -2.1.0 - diff --git a/0005-timesyncd-check-root-distance.patch b/0116-timesyncd-check-root-distance.patch similarity index 93% rename from 0005-timesyncd-check-root-distance.patch rename to 0116-timesyncd-check-root-distance.patch index a850bc5..4d1816d 100644 --- a/0005-timesyncd-check-root-distance.patch +++ b/0116-timesyncd-check-root-distance.patch @@ -1,7 +1,7 @@ -From 60bfbd03ff57e6096b13c292ff33fd5570508a05 Mon Sep 17 00:00:00 2001 +From 3af0442c52090f34ae7a1c8e6b6587c540c06896 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 +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 @@ -9,14 +9,12 @@ 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 +index 2b0580cf01..9b8b7d3eb6 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -89,6 +89,9 @@ @@ -77,6 +75,3 @@ index 2b0580c..9b8b7d3 100644 ntpmsg.stratum == 1 ? ntpmsg.refid : "n/a", origin - OFFSET_1900_1970, receive - OFFSET_1900_1970, --- -2.1.0 - 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/0006-timesyncd-manager-don-t-clear-current_server_name-if.patch b/0131-timesyncd-manager-don-t-clear-current_server_name-if.patch similarity index 78% rename from 0006-timesyncd-manager-don-t-clear-current_server_name-if.patch rename to 0131-timesyncd-manager-don-t-clear-current_server_name-if.patch index 2c6700b..20d1740 100644 --- a/0006-timesyncd-manager-don-t-clear-current_server_name-if.patch +++ b/0131-timesyncd-manager-don-t-clear-current_server_name-if.patch @@ -1,20 +1,18 @@ -From 8573eb093a4ccd6e966b60a68236f403dbd67d56 Mon Sep 17 00:00:00 2001 +From 20f8d3cf1be4ad76234ffb85eeae7f9892ee72cd 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 +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] - -(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 +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) { @@ -30,6 +28,3 @@ index 9b8b7d3..696dd10 100644 manager_disconnect(m); --- -2.1.0 - 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/0007-timesyncd-wait-before-reconnecting-to-first-server.patch b/0145-timesyncd-wait-before-reconnecting-to-first-server.patch similarity index 92% rename from 0007-timesyncd-wait-before-reconnecting-to-first-server.patch rename to 0145-timesyncd-wait-before-reconnecting-to-first-server.patch index 8cdcf97..dffbd67 100644 --- a/0007-timesyncd-wait-before-reconnecting-to-first-server.patch +++ b/0145-timesyncd-wait-before-reconnecting-to-first-server.patch @@ -1,22 +1,20 @@ -From 6aa136216f2f78a840215e53ababeea7b65fc061 Mon Sep 17 00:00:00 2001 +From 63463bf091949e0178b749016828ec400c106582 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 +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. - -(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 +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) { @@ -72,7 +70,7 @@ index 696dd10..b7b39ef 100644 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 +index 2345bf8f36..bb3e50915e 100644 --- a/src/timesync/timesyncd-manager.h +++ b/src/timesync/timesyncd-manager.h @@ -41,6 +41,7 @@ struct Manager { @@ -83,6 +81,3 @@ index 2345bf8..bb3e509 100644 /* network */ sd_event_source *network_event_source; --- -2.1.0 - diff --git a/0008-timesyncd-remove-retry_timer-logic-which-is-covered-.patch b/0146-timesyncd-remove-retry_timer-logic-which-is-covered-.patch similarity index 85% rename from 0008-timesyncd-remove-retry_timer-logic-which-is-covered-.patch rename to 0146-timesyncd-remove-retry_timer-logic-which-is-covered-.patch index 9f5bea6..6586010 100644 --- a/0008-timesyncd-remove-retry_timer-logic-which-is-covered-.patch +++ b/0146-timesyncd-remove-retry_timer-logic-which-is-covered-.patch @@ -1,17 +1,16 @@ -From aebe463f08041d5c38023b414153a79295a5457f Mon Sep 17 00:00:00 2001 +From 665c6a9eab46b0b253af6566ca9fc70c866b3fcd 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 +Subject: [PATCH] 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 +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) { @@ -43,7 +42,7 @@ index b7b39ef..19a28f3 100644 /* 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 +index bb3e50915e..0ac0e179c1 100644 --- a/src/timesync/timesyncd-manager.h +++ b/src/timesync/timesyncd-manager.h @@ -59,7 +59,6 @@ struct Manager { @@ -54,6 +53,3 @@ index bb3e509..0ac0e17 100644 bool pending; /* poll timer */ --- -2.1.0 - diff --git a/0009-timesyncd-allow-two-missed-replies-before-reselectin.patch b/0147-timesyncd-allow-two-missed-replies-before-reselectin.patch similarity index 92% rename from 0009-timesyncd-allow-two-missed-replies-before-reselectin.patch rename to 0147-timesyncd-allow-two-missed-replies-before-reselectin.patch index 5b76446..7790163 100644 --- a/0009-timesyncd-allow-two-missed-replies-before-reselectin.patch +++ b/0147-timesyncd-allow-two-missed-replies-before-reselectin.patch @@ -1,21 +1,18 @@ -From e558311df376973727c9924c1416a2101e55673d Mon Sep 17 00:00:00 2001 +From e8206972be6a7ebeb198cd0d400bc7a94a6a5fc5 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 +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. - -(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 +index 19a28f37e2..a66852d7d2 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -92,6 +92,9 @@ @@ -74,7 +71,7 @@ index 19a28f3..a66852d 100644 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 +index 0ac0e179c1..8296d41295 100644 --- a/src/timesync/timesyncd-manager.h +++ b/src/timesync/timesyncd-manager.h @@ -53,6 +53,7 @@ struct Manager { @@ -85,6 +82,3 @@ index 0ac0e17..8296d41 100644 uint64_t packet_count; sd_event_source *event_timeout; --- -2.1.0 - diff --git a/0010-timesyncd-don-t-reset-polling-interval-when-reselect.patch b/0148-timesyncd-don-t-reset-polling-interval-when-reselect.patch similarity index 78% rename from 0010-timesyncd-don-t-reset-polling-interval-when-reselect.patch rename to 0148-timesyncd-don-t-reset-polling-interval-when-reselect.patch index a16c58b..bca140e 100644 --- a/0010-timesyncd-don-t-reset-polling-interval-when-reselect.patch +++ b/0148-timesyncd-don-t-reset-polling-interval-when-reselect.patch @@ -1,18 +1,16 @@ -From 0c4d8d57d2581ea8e90f5b22ac81b249b6b28671 Mon Sep 17 00:00:00 2001 +From 80cd2606b91ce2735a0609c6f964917cf12685aa 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 +Subject: [PATCH] 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 +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) { @@ -25,6 +23,3 @@ index a66852d..3261bc1 100644 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/0149-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch similarity index 87% rename from 0011-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch rename to 0149-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch index 8a8d47c..7757413 100644 --- a/0011-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch +++ b/0149-Revert-timesyncd-remove-retry_timer-logic-which-is-c.patch @@ -1,8 +1,8 @@ -From 1d282632e027281c81a97c2bf2d7a803553651dc Mon Sep 17 00:00:00 2001 +From ab4df227d466e881e4279821b5fc1563f0e7e933 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" +Subject: [PATCH] Revert "timesyncd: remove retry_timer logic which is covered + by the server timeout" This reverts commit 665c6a9eab46b0b253af6566ca9fc70c866b3fcd. @@ -10,15 +10,13 @@ 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 +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) { @@ -50,7 +48,7 @@ index 3261bc1..a5678cc 100644 /* 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 +index 8296d41295..c7efdc5dfb 100644 --- a/src/timesync/timesyncd-manager.h +++ b/src/timesync/timesyncd-manager.h @@ -60,6 +60,7 @@ struct Manager { @@ -61,6 +59,3 @@ index 8296d41..c7efdc5 100644 bool pending; /* poll timer */ --- -2.1.0 - 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 +# 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 -# 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 # 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"