Update to latest git

This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2014-10-03 22:43:52 -04:00
parent 5cdc00d6e6
commit 62fe9450da
537 changed files with 65534 additions and 147 deletions

View File

@ -1,32 +0,0 @@
From 73403e8de2c5bc6d54f89ae2f1c9aa12b92ecb7a Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
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

View File

@ -0,0 +1,52 @@
From fdbdf6ec29bda40763d7d3e7bb2a63e2f5d60c4c Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
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);

View File

@ -0,0 +1,26 @@
From 413f6df864083130a380b2f7adbb5aa970139fe7 Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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

View File

@ -0,0 +1,120 @@
From 5dd6d0f8ff1681fff9369e0aa2532979954dbfde Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;
+ }
+ }
+ }
+ }
}
}

View File

@ -0,0 +1,36 @@
From 03664a62914782dbd8f069bbcf8a0c8ca1df7010 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
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;

View File

@ -0,0 +1,25 @@
From be754d5443e5fe44ead733ad509b127409cdb0f0 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;

View File

@ -0,0 +1,21 @@
From 7a855149eaf6dbd336d9defab5b4a9c70b75d5e6 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
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;

View File

@ -0,0 +1,27 @@
From 081e009bef5a09c986bfabdf46e96810afaed1c3 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
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)

View File

@ -0,0 +1,22 @@
From e1ad6e245dcf63faa8f183063eb97678f4f9ac94 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
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;

View File

@ -0,0 +1,26 @@
From a9feff3d774eaa1cc1b59189e8f344c01e69f888 Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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);

View File

@ -0,0 +1,56 @@
From 9b364545435d2b65fcf73519b3064bb7c28093b7 Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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);

View File

@ -0,0 +1,143 @@
From 730836403aee5f5bb998e6e3622ea7068fce0699 Mon Sep 17 00:00:00 2001
From: Harald Hoyer <harald@redhat.com>
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 @@
</varlistentry>
<varlistentry>
+ <term><option>-t</option></term>
+ <term><option>--identifier=<replaceable>SYSLOG_IDENTIFIER</replaceable>|<replaceable>PATTERN</replaceable></option></term>
+
+ <listitem><para>Show messages for the
+ specified syslog identifier
+ <replaceable>SYSLOG_IDENTIFIER</replaceable>, or
+ for any of the messages with a <literal>SYSLOG_IDENTIFIER</literal>
+ matched by <replaceable>PATTERN</replaceable>.</para>
+
+ <para>This parameter can be specified
+ multiple times.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-u</option></term>
<term><option>--unit=<replaceable>UNIT</replaceable>|<replaceable>PATTERN</replaceable></option></term>
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));

View File

@ -0,0 +1,24 @@
From 3fdbc8205885f117b7dea289b44217310663e731 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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.

View File

@ -0,0 +1,48 @@
From 11adc1aef7a1a6e9ba3fda8eb34eb5fadedc0385 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;
}

View File

@ -0,0 +1,55 @@
From a9f85faf43ae2289e19ba9105c36496aefe66072 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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) {

View File

@ -0,0 +1,42 @@
From 5ed1227238724959f020169f5332086439709b55 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;
}

View File

@ -0,0 +1,127 @@
From 4c94096027f21d4ed0efe991534a926d39d52369 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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"

View File

@ -0,0 +1,24 @@
From abb4c1cc0161cc6b371ee7ea2550df17a3bfc21e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);
}

View File

@ -0,0 +1,526 @@
From 8bb2d17d2b89e87b2e9d8f6c147a757f4670b0fc Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;

View File

@ -0,0 +1,30 @@
From f49650cee2c5256dc0491432e1f12a4ae19be6c5 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;

View File

@ -0,0 +1,139 @@
From 28849dbadb7cd127f7f89e8892ec94c6a05070da Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,30 @@
From 55836941ff642d42403921fa9d5fd2f8376ae722 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,99 @@
From 70af4d17dafe81acc96f71f4ec06fbea7386bc38 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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. */

View File

@ -0,0 +1,471 @@
From 308d72dc1e2106f94ae637e2ea510e8d466d2af1 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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 @@
<refnamediv>
<refname>sd_notify</refname>
<refname>sd_notifyf</refname>
- <refpurpose>Notify service manager about start-up completion and other daemon status changes</refpurpose>
+ <refpurpose>Notify service manager about start-up completion and other service status changes</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -70,12 +70,12 @@
<refsect1>
<title>Description</title>
- <para><function>sd_notify()</function> 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.</para>
+ <para><function>sd_notify()</function> 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.</para>
<para>If the <parameter>unset_environment</parameter>
parameter is non-zero, <function>sd_notify()</function>
@@ -99,58 +99,87 @@
<varlistentry>
<term>READY=1</term>
- <listitem><para>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
+ <listitem><para>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".</para></listitem>
+ only value services should send is
+ <literal>READY=1</literal>
+ (i.e. <literal>READY=0</literal> is
+ not defined).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>RELOADING=1</term>
+
+ <listitem><para>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
+ <literal>READY=1</literal>
+ notification when it completed
+ reloading its
+ configuration.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>STOPPING=1</term>
+
+ <listitem><para>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.</para></listitem>
</varlistentry>
<varlistentry>
<term>STATUS=...</term>
<listitem><para>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..."</para></listitem>
+ <literal>STATUS=Completed 66% of file
+ system
+ check...</literal></para></listitem>
</varlistentry>
<varlistentry>
<term>ERRNO=...</term>
- <listitem><para>If a daemon fails, the
+ <listitem><para>If a service fails, the
errno-style error code, formatted as
- string. Example: "ERRNO=2" for
+ string. Example: <literal>ERRNO=2</literal> for
ENOENT.</para></listitem>
</varlistentry>
<varlistentry>
<term>BUSERROR=...</term>
- <listitem><para>If a daemon fails, the
+ <listitem><para>If a service fails, the
D-Bus error-style error code. Example:
- "BUSERROR=org.freedesktop.DBus.Error.TimedOut"</para></listitem>
+ <literal>BUSERROR=org.freedesktop.DBus.Error.TimedOut</literal></para></listitem>
</varlistentry>
<varlistentry>
<term>MAINPID=...</term>
<listitem><para>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"</para></listitem>
+ <literal>MAINPID=4711</literal></para></listitem>
</varlistentry>
<varlistentry>
@@ -183,7 +212,7 @@
clashes.</para>
<para>Note that systemd will accept status data sent
- from a daemon only if the
+ from a service only if the
<varname>NotifyAccess=</varname> option is correctly
set in the service definition file. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
@@ -222,7 +251,7 @@
<varname>$NOTIFY_SOCKET</varname> is <literal>@</literal>, the string is
understood as Linux abstract namespace socket. The
datagram is accompanied by the process credentials of
- the sending daemon, using SCM_CREDENTIALS.</para>
+ the sending service, using SCM_CREDENTIALS.</para>
</refsect1>
<refsect1>
@@ -232,7 +261,7 @@
<varlistentry>
<term><varname>$NOTIFY_SOCKET</varname></term>
- <listitem><para>Set by the init system
+ <listitem><para>Set by the service manager
for supervised processes for status
and start-up completion
notification. This environment variable
@@ -249,9 +278,9 @@
<example>
<title>Start-up Notification</title>
- <para>When a daemon finished starting up, it
+ <para>When a service finished starting up, it
might issue the following call to notify
- the init system:</para>
+ the service manager:</para>
<programlisting>sd_notify(0, "READY=1");</programlisting>
</example>
@@ -259,7 +288,7 @@
<example>
<title>Extended Start-up Notification</title>
- <para>A daemon could send the following after
+ <para>A service could send the following after
completing initialization:</para>
<programlisting>sd_notifyf(0, "READY=1\n"
@@ -271,7 +300,7 @@
<example>
<title>Error Cause Notification</title>
- <para>A daemon could send the following shortly before exiting, on failure</para>
+ <para>A service could send the following shortly before exiting, on failure</para>
<programlisting>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;
}

View File

@ -0,0 +1,236 @@
From af4ec4309e8f82aad87a8d574785c12f8763d5f8 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;
}

34
0025-update-TODO.patch Normal file
View File

@ -0,0 +1,34 @@
From 55cdcbacf70f05a40a155af24f6d2da6b478cba6 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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

View File

@ -0,0 +1,49 @@
From 430e21c2f7e77d600257ead56419f511e48e854a Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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 <sys/socket.h>
#include <sys/capability.h>
+#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)

View File

@ -0,0 +1,25 @@
From f461c8073dee9cd10bfae5ae3586e785ec8a5d07 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,106 @@
From 21b2ce39d4038cd6176394836fdcfb7fba63f424 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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,

22
0029-update-TODO.patch Normal file
View File

@ -0,0 +1,22 @@
From 1954ea346dc28226c0fffde848d49a297165b0a9 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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

View File

@ -0,0 +1,166 @@
From 96fb8242cc1ef6b0e28f6c86a4f57950095dd7f1 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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 @@
<para>If set to
<option>simple</option> (the default
- value if neither
+ if neither
<varname>Type=</varname> nor
- <varname>BusName=</varname> are
+ <varname>BusName=</varname>, but
+ <varname>ExecStart=</varname> are
specified), it is expected that the
process configured with
<varname>ExecStart=</varname> is the
@@ -177,13 +178,17 @@
exits.</para>
<para>Behavior of
- <option>oneshot</option> is similar
- to <option>simple</option>; however,
- it is expected that the process has to
+ <option>oneshot</option> is similar to
+ <option>simple</option>; however, it
+ is expected that the process has to
exit before systemd starts follow-up
units. <varname>RemainAfterExit=</varname>
is particularly useful for this type
- of service.</para>
+ of service. This is the implied
+ default if neither
+ <varname>Type=</varname> or
+ <varname>ExecStart=</varname> are
+ specified.</para>
<para>Behavior of
<option>dbus</option> is similar to
@@ -313,22 +318,27 @@
<para>When <varname>Type</varname> is
not <option>oneshot</option>, only one
- command may be given. When
+ command may and must be given. When
<varname>Type=oneshot</varname> 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
<literal>\;</literal>. 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.</para>
+ have no effect. If no
+ <varname>ExecStart=</varname> is
+ specified, then the service must have
+ <varname>RemainAfterExit=yes</varname>
+ set.</para>
<para>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,

View File

@ -0,0 +1,126 @@
From 59ccf93d97f0a37522e5f4fbf5cc0288dbedf495 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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)

View File

@ -0,0 +1,46 @@
From 4fe1be9ce2e0cca6354a4167f0a1a7e1f943c91c Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;
}

24
0033-update-TODO.patch Normal file
View File

@ -0,0 +1,24 @@
From 337ce7442a0602116c6253ebf202bd34f675f627 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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"

View File

@ -0,0 +1,59 @@
From 0975b63fb31263e535a2d26ed41e66e23f468bc5 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,75 @@
From 40a1eebde6be7ac3f1885147fc24e06ad1da260c Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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 <daniele@grinta.net>.
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) {

View File

@ -0,0 +1,25 @@
From a7d611f280b3eadafd6b411b659a321b4d6e63f4 Mon Sep 17 00:00:00 2001
From: Daniel Mack <zonque@gmail.com>
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

View File

@ -0,0 +1,23 @@
From 2de1851fe3611c59abf77127c6b5bc1b91eb7cba Mon Sep 17 00:00:00 2001
From: Daniel Mack <zonque@gmail.com>
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

View File

@ -0,0 +1,704 @@
From 2928b0a863091f8f291fddb168988711afd389ef Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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.</para></listitem>
</varlistentry>
-
<varlistentry>
<term><varname>TimerSlackNSec=</varname></term>
@@ -281,6 +280,32 @@
</varlistentry>
<varlistentry>
+ <term><varname>StartTimeoutSec=</varname></term>
+ <term><varname>StartTimeoutAction=</varname></term>
+ <term><varname>StartTimeoutRebootArgument=</varname></term>
+
+ <listitem><para>Configures an over-all
+ system start-up timeout and controls
+ what to do when the timeout is
+ reached. <varname>StartTimeoutSec=</varname>
+ specifies the timeout, and defaults to
+ <literal>15min</literal>. <varname>StartTimeoutAction=</varname>
+ 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
+ <varname>StartLimitAction=</varname>
+ setting, see
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details. Defaults to
+ <option>reboot-force</option>. <varname>StartTimeoutRebootArgument=</varname>
+ configures an optional reboot string
+ to pass to the
+ <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ system call.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>DefaultTimerAccuracySec=</varname></term>
<listitem><para>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}</programlisting>
</varlistentry>
<varlistentry>
+ <term><varname>FailureAction=</varname></term>
+ <listitem><para>Configure the action
+ to take when the service enters a failed
+ state. Takes the same values as
+ <varname>StartLimitAction=</varname>
+ and executes the same actions.
+ Defaults to <option>none</option>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>RebootArgument=</varname></term>
<listitem><para>Configure the optional
argument for the
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call if
<varname>StartLimitAction=</varname>
+ or <varname>FailureAction=</varname>
is a reboot action. This works just
like the optional argument to
<command>systemctl reboot</command>
command.</para></listitem>
</varlistentry>
- <varlistentry>
- <term><varname>FailureAction=</varname></term>
- <listitem><para>Configure the action
- to take when the service enters a failed
- state. Takes the same values as
- <varname>StartLimitAction=</varname>
- and executes the same actions.
- Defaults to <option>none</option>.
- </para></listitem>
- </varlistentry>
-
</variablelist>
<para>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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/reboot.h>
+#include <linux/reboot.h>
+#include <sys/syscall.h>
+
+#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 <http://www.gnu.org/licenses/>.
+***/
+
+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 <signal.h>
#include <dirent.h>
#include <unistd.h>
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <sys/syscall.h>
#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);

View File

@ -0,0 +1,85 @@
From e12919e8be5c80efe09a57f642bbd2411b313ced Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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)

View File

@ -0,0 +1,22 @@
From c4147df156835513c43260a14fc9f7af177f737f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,219 @@
From f07756bfe25c64119704c93a634162d6c88b5c89 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. Defaults to
- <option>reboot-force</option>. <varname>StartTimeoutRebootArgument=</varname>
+ <option>poweroff-force</option>. <varname>StartTimeoutRebootArgument=</varname>
configures an optional reboot string
to pass to the
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
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}</programlisting>
hit. Takes one of
<option>none</option>,
<option>reboot</option>,
- <option>reboot-force</option>, or
- <option>reboot-immediate</option>. If
- <option>none</option> is set,
- hitting the rate limit will trigger no
- action besides that the start will not
- be permitted. <option>reboot</option>
+ <option>reboot-force</option>,
+ <option>reboot-immediate</option>,
+ <option>poweroff</option>,
+ <option>poweroff-force</option> or
+ <option>poweroff-immediate</option>. If
+ <option>none</option> is set, hitting
+ the rate limit will trigger no action
+ besides that the start will not be
+ permitted. <option>reboot</option>
causes a reboot following the normal
shutdown procedure (i.e. equivalent to
<command>systemctl reboot</command>).
- <option>reboot-force</option> causes
- a forced reboot which will terminate
- all processes forcibly but should
- cause no dirty file systems on reboot
+ <option>reboot-force</option> causes a
+ forced reboot which will terminate all
+ processes forcibly but should cause no
+ dirty file systems on reboot
(i.e. equivalent to <command>systemctl
reboot -f</command>) and
<option>reboot-immediate</option>
causes immediate execution of the
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call, which might result in
- data loss. Defaults to
+ data loss. Similar,
+ <option>poweroff</option>,
+ <option>poweroff-force</option>,
+ <option>poweroff-immediate</option>
+ have the effect of powering down the
+ system with similar
+ semantics. Defaults to
<option>none</option>.</para></listitem>
</varlistentry>
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, &param) >= 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

View File

@ -0,0 +1,88 @@
From d81afec1c9bf4b73e3df8996d65ecae95d19b6db Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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,

32
0043-update-TODO.patch Normal file
View File

@ -0,0 +1,32 @@
From d74f9e8e8a3dcddb043ef193e4bb14f58efa095f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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

View File

@ -0,0 +1,27 @@
From 41a451cc2901a5deb985aea4cc8de204a22e5612 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
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;

View File

@ -0,0 +1,244 @@
From c45a5a74465a39280b855f9d720b2ab4779a47fa Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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);

View File

@ -0,0 +1,27 @@
From 6d148a842ebb04a9a9bc2853e167a9d8eddf8cd8 Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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) {

30
0047-update-TODO.patch Normal file
View File

@ -0,0 +1,30 @@
From 42aeb14a4a0fa7d43da96a8ed0fb0e180a2dd5c8 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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.

View File

@ -0,0 +1,26 @@
From 4fc13f521ab44eb55c599b07c18860c1aeca35a7 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;

View File

@ -0,0 +1,60 @@
From 77cf759ea05bea476cdcb8d0dcd04c4e6fb3b2ff Mon Sep 17 00:00:00 2001
From: Kay Sievers <kay@vrfy.org>
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 <simon.mcvittie@collabora.co.uk>.
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) {

24
0050-update-TODO.patch Normal file
View File

@ -0,0 +1,24 @@
From 8dac15b6e9792c2b0f503ddf78ac499817904a6f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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

33
0051-NEWS-Fix-typos.patch Normal file
View File

@ -0,0 +1,33 @@
From daa05349dfefb12638c96e034c11be613bdc39b7 Mon Sep 17 00:00:00 2001
From: Ansgar Burchardt <ansgar@43-1.org>
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.

View File

@ -0,0 +1,22 @@
From 7965435e588c8d2fb824c5fd4b8c2739bc30acdf Mon Sep 17 00:00:00 2001
From: Michael Olbrich <m.olbrich@pengutronix.de>
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

View File

@ -0,0 +1,23 @@
From 32dfe42c66085c55916e5306a9a07d42d3958b6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= <stlman@poczta.fm>
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) {

View File

@ -0,0 +1,33 @@
From 52754725e185f1331f821d85ed2ef78fb92af1fe Mon Sep 17 00:00:00 2001
From: Filipe Brandenburger <filbranden@google.com>
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 */");

View File

@ -0,0 +1,78 @@
From 8d95631ea6c039a60bb7ac456f687a8fdf0c4381 Mon Sep 17 00:00:00 2001
From: Filipe Brandenburger <filbranden@google.com>
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;
}
}

View File

@ -0,0 +1,27 @@
From 684fc8927e0f83496d4384ac434e265f7cd7a87b Mon Sep 17 00:00:00 2001
From: Filipe Brandenburger <filbranden@google.com>
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);

View File

@ -0,0 +1,65 @@
From bb19cb17076bbec942ad08f94d41ba36b28a5a13 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,25 @@
From 498cfc230af8f83675be2e92057956f1792969e4 Mon Sep 17 00:00:00 2001
From: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
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;
}

View File

@ -0,0 +1,36 @@
From f2322f0b64107b2eee1fadb6c59857381277a9f8 Mon Sep 17 00:00:00 2001
From: Hristo Venev <mustrumr97@gmail.com>
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;

View File

@ -0,0 +1,47 @@
From 24a5d6b04e17d447cf122f02a8a2dedd843cce45 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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) {

View File

@ -0,0 +1,66 @@
From 1dedb74a2e1d840b531b76b01a76979f3b57456b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,101 @@
From 1b6d7fa742e303611dff8d7ebfa86ee5fb8b7dc7 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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);

View File

@ -0,0 +1,22 @@
From 36202fd2bc252616966166c98ccb0e0e5ece1fc9 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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;

View File

@ -0,0 +1,244 @@
From 3c56cab44150ad47323970cfadfb0257c6305a74 Mon Sep 17 00:00:00 2001
From: Ben Wolsieffer <benwolsieffer@gmail.com>
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 @@
<term><varname>HandleSuspendKey=</varname></term>
<term><varname>HandleHibernateKey=</varname></term>
<term><varname>HandleLidSwitch=</varname></term>
+ <term><varname>HandleLidSwitchDocked=</varname></term>
<listitem><para>Controls whether
logind shall handle the system power
@@ -255,13 +256,18 @@
and
<varname>HandleLidSwitch=</varname>
default to <literal>suspend</literal>.
+ <varname>HandleLidSwitchDocked=</varname>
+ defaults to <literal>ignore</literal>.
<varname>HandleHibernateKey=</varname>
defaults to
- <literal>hibernate</literal>. Note
- that the lid switch is ignored if the
- system is inserted in a docking
- station, or if more than one display
- is connected.</para></listitem>
+ <literal>hibernate</literal>. If the
+ system is inserted in a docking station,
+ or if more than one display is connected,
+ the action specified by
+ <varname>HandleLidSwitchDocked=</varname>
+ occurs; otherwise the
+ <varname>HandleLidSwitch=</varname>
+ action occurs.</para></listitem>
</varlistentry>
<varlistentry>
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[];

View File

@ -0,0 +1,25 @@
From 66f311206e908a5b6f21e66fad73e1e5ea3e31d6 Mon Sep 17 00:00:00 2001
From: Ivan Shapovalov <intelfx100@gmail.com>
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]

View File

@ -0,0 +1,353 @@
From 42483a747489ff46aed3588b78bf4b9480dbeaf7 Mon Sep 17 00:00:00 2001
From: Ivan Shapovalov <intelfx100@gmail.com>
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 @@
+<?xml version="1.0"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ 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 <http://www.gnu.org/licenses/>.
+-->
+<refentry id="systemd-hibernate-resume@.service">
+
+ <refentryinfo>
+ <title>systemd-hibernate-resume@.service</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Ivan</firstname>
+ <surname>Shapovalov</surname>
+ <email>intelfx100@gmail.com</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd-hibernate-resume@.service</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd-hibernate-resume@.service</refname>
+ <refname>systemd-hibernate-resume</refname>
+ <refpurpose>Resume from hibernation</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>systemd-hibernate-resume@.service</filename></para>
+ <para><filename>/usr/lib/systemd/systemd-hibernate-resume</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><filename>systemd-hibernate-resume@.service</filename> 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.</para>
+
+ <para><filename>systemd-hibernate-resume</filename> only supports
+ the in-kernel hibernation implementation, known as swsusp.
+ Internally, it works by writing the major:minor of specified
+ device node to <filename>/sys/power/resume</filename>.</para>
+
+ <para>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.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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

View File

@ -0,0 +1,330 @@
From d2c68822c47e37b582820f45b496b2e7d1f9e642 Mon Sep 17 00:00:00 2001
From: Ivan Shapovalov <intelfx100@gmail.com>
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 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>resume=</varname></term>
+
+ <listitem>
+ <para>Enables resume from hibernation
+ using the specified device.
+ All <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>-like
+ pathes are supported. For details, see
+ <citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -373,7 +384,8 @@
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-modules-load.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-rfkill@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd-rfkill@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
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 @@
+<?xml version="1.0"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ 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 <http://www.gnu.org/licenses/>.
+-->
+<refentry id="systemd-hibernate-resume-generator">
+
+ <refentryinfo>
+ <title>systemd-hibernate-resume-generator</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Ivan</firstname>
+ <surname>Shapovalov</surname>
+ <email>intelfx100@gmail.com</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd-hibernate-resume-generator</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd-hibernate-resume-generator</refname>
+ <refpurpose>Unit generator for resume= kernel parameter</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>/usr/lib/systemd/system-generators/systemd-hibernate-resume-generator</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><filename>systemd-hibernate-resume-generator</filename> is
+ a generator that instantiates
+ <citerefentry><refentrytitle>systemd-hibernate-resume@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ unit according to the value of <option>resume=</option>
+ parameter specified on the kernel command line.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Kernel Command Line</title>
+
+ <para><filename>systemd-hibernate-resume-generator</filename> understands
+ the following kernel command line parameters:</para>
+
+ <variablelist class='kernel-commandline-options'>
+
+ <varlistentry>
+ <term><varname>resume=</varname></term>
+
+ <listitem><para>Takes a path to the resume
+ device. Both persistent block device pathes like
+ <filename>/dev/disk/by-foo/bar</filename> and
+ <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>-style
+ specifiers like <literal>FOO=bar</literal>
+ are supported.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-hibernate-resume@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+
+#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;
+}

View File

@ -0,0 +1,35 @@
From 36f5ace2db7fc43796107b2da9874e4c4bbc623e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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 @@
<refsect1>
<title>Description</title>
- <para><filename>systemd-hibernate-resume@.service</filename> 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.</para>
+ <para><filename>systemd-hibernate-resume@.service</filename>
+ initiates the resume from hibernation. It is
+ instantiated with the device to resume from as the
+ template argument.</para>
<para><filename>systemd-hibernate-resume</filename> only supports
- the in-kernel hibernation implementation, known as swsusp.
+ the in-kernel hibernation implementation, known as
+ <ulink url="https://www.kernel.org/doc/Documentation/power/swsusp.txt">swsusp</ulink>.
Internally, it works by writing the major:minor of specified
device node to <filename>/sys/power/resume</filename>.</para>

View File

@ -0,0 +1,39 @@
From bf2e0ece853b888eb37055849975ddeab3f5f051 Mon Sep 17 00:00:00 2001
From: Andrei Borzenkov <arvidjaar@gmail.com>
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 @@
</varlistentry>
</variablelist>
- <para>Most of the fields support shell glob pattern matching. The following
- pattern characters are supported:</para>
+ <para>Most of the fields support shell glob pattern matching and
+ alternate patterns. The following special characters are supported:</para>
<variablelist>
<varlistentry>
<term><literal>*</literal></term>
@@ -300,6 +300,14 @@
any characters not enclosed are matched.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>|</literal></term>
+ <listitem>
+ <para>Separates alternative patterns. For example, the pattern string
+ <literal>abc|x*</literal> would match either <literal>abc</literal>
+ or <literal>x*</literal>.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para>The following keys can get values assigned:</para>

View File

@ -0,0 +1,63 @@
From 1977376274fc81f13e4220d224237e7cc71f0c63 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Dr=C4=85g?= <piotrdrag@gmail.com>
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 <piotrdrag@gmail.com>, 2011, 2013.
+# Piotr Drąg <piotrdrag@gmail.com>, 2011, 2013, 2014.
# Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>, 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 <piotrdrag@gmail.com>\n"
"Language-Team: Polish <trans-pl@lists.fedoraproject.org>\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."

View File

@ -0,0 +1,26 @@
From e512e8a255ef29d5a8eb605f8849202ea3d3e4cb Mon Sep 17 00:00:00 2001
From: Martin Pitt <martin.pitt@ubuntu.com>
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

View File

@ -0,0 +1,34 @@
From 81fc054dc7c365545bca86d78bf36a12658cedb3 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
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? */)

View File

@ -0,0 +1,114 @@
From aeb50ff0bd4bbbca74c4695072232348351d512d Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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 - - - -

44
0074-TODO.patch Normal file
View File

@ -0,0 +1,44 @@
From 285e8c126b1607188249c42e74c172cb69cc99a6 Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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

View File

@ -0,0 +1,41 @@
From 418bcb0ce3b704ea26ee1b4a68706abca536f65a Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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

View File

@ -0,0 +1,119 @@
From fb835651aff79a1e7fc5795086c9b26e59a8e6ca Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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();

View File

@ -0,0 +1,33 @@
From 60240797a4ce464ec7a0537ccbec4c83f599251c Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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

View File

@ -0,0 +1,26 @@
From 92e63a51052e9ba2fbe6e47a173b6264ae292a58 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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();

View File

@ -0,0 +1,37 @@
From f1566e63da92cee5cbc0074df9cd9a8dc078a62e Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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);

View File

@ -0,0 +1,172 @@
From aae2b488d084cf2af9a552a55e1d9cc614f2a12a Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,975 @@
From e202fa31fb2d60084e7b2ab7976a81c138184d40 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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 <dh.herrmann@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
+#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 <dh.herrmann@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
+#include <systemd/sd-login.h>
+#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 <dh.herrmann@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+/*
+ * IDev
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
+#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);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,566 @@
From 8e9371905c743cf997b2e8fa7fe3238f81f741fe Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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 <dh.herrmann@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <libevdev/libevdev.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
+#include <systemd/sd-login.h>
+#include <termios.h>
+#include <unistd.h>
+#include <xkbcommon/xkbcommon.h>
+#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) ? : "<unknown>");
+
+ /* 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 ? : "<none>");
+
+ 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;
+}

View File

@ -0,0 +1,93 @@
From c609cb9898dc8dec5dcb0b1d111b3f6b6a5e09d4 Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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 <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#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;
+}

View File

@ -0,0 +1,91 @@
From 8a7c93d858c342744adf481565d8bb03b9713dcf Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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

22
0088-update-TODO.patch Normal file
View File

@ -0,0 +1,22 @@
From eff3f4f9e92b56d9dfb90d5094e48cc743c776cc Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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...

View File

@ -0,0 +1,21 @@
From 00b333bb1039809a42ba4c7f25ba85f68766477d Mon Sep 17 00:00:00 2001
From: Thomas Hindoe Paaboel Andersen <phomes@gmail.com>
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;

View File

@ -0,0 +1,36 @@
From 57cd09acf2c63a414aa2131c00a2b3f600eb0133 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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);
}

View File

@ -0,0 +1,51 @@
From 0f99f74a14ef193c1ebde687c5cc76e1d67b85ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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. */

View File

@ -0,0 +1,26 @@
From 371ad55d460559b4262e25d0f9b64dc37c3f7565 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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) {

View File

@ -0,0 +1,37 @@
From 3125b3ef5db70d45882c7d6f617705802c5f939e Mon Sep 17 00:00:00 2001
From: Tom Gundersen <teg@jklm.no>
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;

View File

@ -0,0 +1,23 @@
From 200716a628b70fe723e7d4e09bb2ece10c10bdc0 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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);

View File

@ -0,0 +1,38 @@
From fa9838ddd62ea31f8aea99757916a16d76b31cbc Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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;

View File

@ -0,0 +1,70 @@
From d974ad0524942882f489914013d08ab16d147170 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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);
}

View File

@ -0,0 +1,131 @@
From 667a0377fb25ddb0c3efbc43d186ffd4c097ce41 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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 <dh.herrmann@gmail.com>
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) {

View File

@ -0,0 +1,275 @@
From 5a4bf02ff57e4dd3453f2b868c72fe45f60033a3 Mon Sep 17 00:00:00 2001
From: Harald Hoyer <harald@redhat.com>
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 <http://www.gnu.org/licenses/>.
***/
-int switch_root(const char *switch_root);
+int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags);

View File

@ -0,0 +1,25 @@
From c168eb6785bacc2042687bf879259dfc27d5a523 Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
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);

Some files were not shown because too many files have changed in this diff Show More