Compare commits

...

No commits in common. "imports/c8s/systemd-239-70.el8" and "c8" have entirely different histories.

158 changed files with 15757 additions and 12 deletions

View File

@ -0,0 +1,44 @@
From 004130ae74688eb321aadc05192bab69fe5cbcbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 22 Jul 2022 11:45:12 +0200
Subject: [PATCH] manager: limit access to private dbus socket
For the system manager, /run/systemd/private is publicly accessible, because
/run/systemd is 0755, and /run/systemd/private is 0777. For the user manager,
/run/user/<uid> is 0700, and /run/user/<uid>/systemd/private is 0777. This
does not directly cause any security issue because we check the sender in
bus_check_peercred (ucred.uid != 0 && ucred.uid != geteuid()).
But it makes sense to limit access to the socket to avoid wasting time in PID1.
Somebody could send messages there that'd we'd reject anyway. It also makes
things more explicit.
(cherry picked from commit df1cbd1adf26071aab41d96e054452a3d66103a4)
Resolves: #2119405
---
src/core/dbus.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 66d838cdb4..ec6c52cb85 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -42,6 +42,7 @@
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
+#include "umask-util.h"
#include "user-util.h"
#define CONNECTIONS_MAX 4096
@@ -1019,7 +1020,8 @@ int bus_init_private(Manager *m) {
if (fd < 0)
return log_error_errno(errno, "Failed to allocate private socket: %m");
- r = bind(fd, &sa.sa, salen);
+ RUN_WITH_UMASK(0077)
+ r = bind(fd, &sa.sa, salen);
if (r < 0)
return log_error_errno(errno, "Failed to bind private socket: %m");

View File

@ -0,0 +1,35 @@
From b0574acc0bddceb0af47f6cce327a87041ab4b52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 11 Nov 2018 12:33:06 +0100
Subject: [PATCH] journalctl: do not treat EINTR as an error when waiting for
events
Fixup for 2a1e0f2228bbdfbc18635e959f47df7da50b62fe. Fixes #10724.
Reproducer: start 'journalctl -f' in a terminal window, change window size.
(cherry picked from commit 8e143a123276a9636987b08f555603927ca9e186)
Resolves: #2161683
---
src/journal/journalctl.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index fa83dce562..228cfe7e49 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -2084,8 +2084,13 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
if (r < 0)
return log_error_errno(r, "Failed to determine journal waiting time: %m");
- if (ppoll(pollfds, ELEMENTSOF(pollfds), timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0)
+ if (ppoll(pollfds, ELEMENTSOF(pollfds),
+ timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) {
+ if (errno == EINTR)
+ return 0;
+
return log_error_errno(errno, "Couldn't wait for journal event: %m");
+ }
if (pollfds[1].revents & (POLLHUP|POLLERR)) { /* STDOUT has been closed? */
log_debug("Standard output has been closed.");

View File

@ -0,0 +1,76 @@
From b9dd7ee5f4d0f6d51899d7e14ac7ef2fd2840b8f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 9 Oct 2018 17:37:57 +0200
Subject: [PATCH] core: bring manager_startup() and manager_reload() more
inline
Both functions do partly the same, let's make sure they do it in the
same order, and that we don't miss some calls.
This makes a number of changes:
1. Moves exec_runtime_vacuum() two calls down in manager_startup(). This
should not have any effect but makes manager_startup() more like
manager_reload().
2. Calls manager_recheck_journal(), manager_recheck_dbus(),
manager_enqueue_sync_bus_names() in manager_startup() too. This is a
good idea since during reeexec we pass through manager_startup() and
hence can't assume dbus and journald weren't up yet, hence let's
check if they are ready to be connected to.
3. Include manager_enumerate_perpetual() in manager_reload(), too. This
is not strictly necessary, since these units are included in the
serialization anyway, but it's still a nice thing, in particular as
theoretically the deserialization could fail.
(cherry picked from commit 3ad2afb6a204513c7834c64ab864e40169874390)
Resolves: #2059633
---
src/core/manager.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index e083596e58..4a9f9bfcf9 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1665,12 +1665,12 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* Release any dynamic users no longer referenced */
dynamic_user_vacuum(m, true);
- exec_runtime_vacuum(m);
-
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
manager_vacuum_uid_refs(m);
manager_vacuum_gid_refs(m);
+ exec_runtime_vacuum(m);
+
if (serialization) {
assert(m->n_reloading > 0);
m->n_reloading--;
@@ -1681,6 +1681,13 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->send_reloading_done = true;
}
+ /* It might be safe to log to the journal now and connect to dbus */
+ manager_recheck_journal(m);
+ manager_recheck_dbus(m);
+
+ /* Sync current state of bus names with our set of listening units */
+ (void) manager_enqueue_sync_bus_names(m);
+
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
@@ -3505,7 +3512,8 @@ int manager_reload(Manager *m) {
lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
- /* First, enumerate what we can from all config files */
+ /* First, enumerate what we can from kernel and suchlike */
+ manager_enumerate_perpetual(m);
manager_enumerate(m);
/* Second, deserialize our stored data */

View File

@ -0,0 +1,35 @@
From b1b7aaf83414c5b0bed6e61d38aefe29a21fdbcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 23 Nov 2022 16:09:56 +0100
Subject: [PATCH] pam: add a call to pam_namespace
A call to pam_namespace is required so that children of user@.service end up in
a namespace as expected. pam_namespace gets called as part of the stack that
creates a session (login, sshd, gdm, etc.) and those processes end up in a
namespace, but it also needs to be called from our stack which is parallel and
descends from pid1 itself.
The call to pam_namespace is similar to the call to pam_keyinit that was added
in ab79099d1684457d040ee7c28b2012e8c1ea9a4f. The pam stack for user@.service
creates a new session which is disconnected from the parent environment. Both
calls are not suitable for inclusion in the shared part of the stack (e.g.
@system-auth on Fedora/RHEL systems), because for example su/sudo/runuser
should not include them.
(cherry picked from commit 0ef48896d9f23b9fd547a532a4e6e6b8f8b12901)
Resolves: #1861836
---
src/login/systemd-user.m4 | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/login/systemd-user.m4 b/src/login/systemd-user.m4
index 20c8999331..eb291beaed 100644
--- a/src/login/systemd-user.m4
+++ b/src/login/systemd-user.m4
@@ -9,4 +9,5 @@ session required pam_selinux.so nottys open
)m4_dnl
session required pam_loginuid.so
session optional pam_keyinit.so force revoke
+session required pam_namespace.so
session optional pam_systemd.so

View File

@ -0,0 +1,31 @@
From 4b573adbcc040fa50f1130cb8cf1bdb9559565cf Mon Sep 17 00:00:00 2001
From: Boqun Feng <boqun.feng@gmail.com>
Date: Wed, 13 Oct 2021 11:32:09 +0800
Subject: [PATCH] virt: Support detection for ARM64 Hyper-V guests
The detection of Microsoft Hyper-V VMs is done by cpuid currently,
however there is no cpuid on ARM64. And since ARM64 is now a supported
architecture for Microsoft Hyper-V guests[1], then use DMI tables to
detect a Hyper-V guest, which is more generic and works for ARM64.
[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7aff79e297ee1aa0126924921fd87a4ae59d2467
(cherry picked from commit 506bbc8569014253ea8614b680ccbc4fc2513a87)
Resolves: #2158307
---
src/basic/virt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 00d1c894e6..cc95097101 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -162,6 +162,7 @@ static int detect_vm_dmi_vendor(void) {
{ "Parallels", VIRTUALIZATION_PARALLELS },
/* https://wiki.freebsd.org/bhyve */
{ "BHYVE", VIRTUALIZATION_BHYVE },
+ { "Microsoft", VIRTUALIZATION_MICROSOFT },
};
unsigned i;
int r;

View File

@ -0,0 +1,41 @@
From e732bc987f2f779e89f30193bf694e0456ab7ce0 Mon Sep 17 00:00:00 2001
From: Boqun Feng <boqun.feng@gmail.com>
Date: Tue, 23 Nov 2021 15:09:26 +0800
Subject: [PATCH] virt: Fix the detection for Hyper-V VMs
Use product_version instead of product_name in DMI table and the string
"Hyper-V" to avoid misdetection.
Fixes: #21468
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
(cherry picked from commit 76eec0649936d9ae2f9087769f463feaf0cf5cb4)
Related: #2158307
---
src/basic/virt.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/basic/virt.c b/src/basic/virt.c
index cc95097101..f750a0463f 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -143,7 +143,8 @@ static int detect_vm_dmi_vendor(void) {
"/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
"/sys/class/dmi/id/sys_vendor",
"/sys/class/dmi/id/board_vendor",
- "/sys/class/dmi/id/bios_vendor"
+ "/sys/class/dmi/id/bios_vendor",
+ "/sys/class/dmi/id/product_version" /* For Hyper-V VMs test */
};
static const struct {
@@ -162,7 +163,7 @@ static int detect_vm_dmi_vendor(void) {
{ "Parallels", VIRTUALIZATION_PARALLELS },
/* https://wiki.freebsd.org/bhyve */
{ "BHYVE", VIRTUALIZATION_BHYVE },
- { "Microsoft", VIRTUALIZATION_MICROSOFT },
+ { "Hyper-V", VIRTUALIZATION_MICROSOFT },
};
unsigned i;
int r;

View File

@ -0,0 +1,98 @@
From 9c95d8dda42de288a57638a44dd5ea967469063d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 7 Oct 2022 12:28:31 +0200
Subject: [PATCH] basic: add STRERROR() wrapper for strerror_r()
(cherry picked from commit 2c5d05b3cd986568105d67891e4010b868dea24f)
Related: #2155520
---
src/basic/util.h | 10 ++++++++++
src/test/test-util.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
diff --git a/src/basic/util.h b/src/basic/util.h
index 76b76d7e91..195f02cf5f 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -153,6 +153,16 @@ static inline void _reset_errno_(int *saved_errno) {
errno = *saved_errno;
}
+/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */
+#define ERRNO_BUF_LEN 1024
+
+/* Note: the lifetime of the compound literal is the immediately surrounding block,
+ * see C11 §6.5.2.5, and
+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks
+ *
+ * Note that we use the GNU variant of strerror_r() here. */
+#define STRERROR(errnum) strerror_r(abs(errnum), (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN)
+
#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno
#define UNPROTECT_ERRNO \
diff --git a/src/test/test-util.c b/src/test/test-util.c
index df60d89115..c93eaf7fc6 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -12,6 +12,7 @@
#include "process-util.h"
#include "raw-clone.h"
#include "rm-rf.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "util.h"
@@ -321,6 +322,42 @@ static void test_system_tasks_max_scale(void) {
assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX);
}
+static void test_strerror_not_threadsafe(void) {
+ /* Just check that strerror really is not thread-safe. */
+ log_info("strerror(%d) → %s", 200, strerror(200));
+ log_info("strerror(%d) → %s", 201, strerror(201));
+ log_info("strerror(%d) → %s", INT_MAX, strerror(INT_MAX));
+
+ log_info("strerror(%d), strerror(%d) → %p, %p", 200, 201, strerror(200), strerror(201));
+
+ /* This call is not allowed, because the first returned string becomes invalid when
+ * we call strerror the second time:
+ *
+ * log_info("strerror(%d), strerror(%d) → %s, %s", 200, 201, strerror(200), strerror(201));
+ */
+}
+
+static void test_STRERROR(void) {
+ /* Just check that STRERROR really is thread-safe. */
+ log_info("STRERROR(%d) → %s", 200, STRERROR(200));
+ log_info("STRERROR(%d) → %s", 201, STRERROR(201));
+ log_info("STRERROR(%d), STRERROR(%d) → %s, %s", 200, 201, STRERROR(200), STRERROR(201));
+
+ const char *a = STRERROR(200), *b = STRERROR(201);
+ assert_se(strstr(a, "200"));
+ assert_se(strstr(b, "201"));
+
+ /* Check with negative values */
+ assert_se(streq(a, STRERROR(-200)));
+ assert_se(streq(b, STRERROR(-201)));
+
+ const char *c = STRERROR(INT_MAX);
+ char buf[DECIMAL_STR_MAX(int)];
+ xsprintf(buf, "%d", INT_MAX); /* INT_MAX is hexadecimal, use printf to convert to decimal */
+ log_info("STRERROR(%d) → %s", INT_MAX, c);
+ assert_se(strstr(c, buf));
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -340,5 +377,8 @@ int main(int argc, char *argv[]) {
test_system_tasks_max();
test_system_tasks_max_scale();
+ test_strerror_not_threadsafe();
+ test_STRERROR();
+
return 0;
}

View File

@ -0,0 +1,529 @@
From f53c6620c55488e2a3bd92957b21b6b95a7a3d35 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Thu, 12 Jan 2023 15:47:09 +0100
Subject: [PATCH] coredump: put context array into a struct
[dtardon: This is based on commit f46c706bdd4316ae8ed6baf7a8c382b90b84f648 ,
but does just the minimal change to introduce the Context struct that is
needed by the following commit.]
Related: #2155520
---
src/coredump/coredump.c | 208 +++++++++++++++++++++-------------------
1 file changed, 108 insertions(+), 100 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index fb3a6ecfe9..ebc56d8342 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -91,6 +91,10 @@ enum {
_CONTEXT_MAX
};
+typedef struct Context {
+ const char *meta[_CONTEXT_MAX];
+} Context;
+
typedef enum CoredumpStorage {
COREDUMP_STORAGE_NONE,
COREDUMP_STORAGE_EXTERNAL,
@@ -184,7 +188,7 @@ static int fix_acl(int fd, uid_t uid) {
return 0;
}
-static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
+static int fix_xattr(int fd, const Context *context) {
static const char * const xattrs[_CONTEXT_MAX] = {
[CONTEXT_PID] = "user.coredump.pid",
@@ -209,10 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
for (i = 0; i < _CONTEXT_MAX; i++) {
int k;
- if (isempty(context[i]) || !xattrs[i])
+ if (isempty(context->meta[i]) || !xattrs[i])
continue;
- k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE);
+ k = fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE);
if (k < 0 && r == 0)
r = -errno;
}
@@ -230,7 +234,7 @@ static int fix_permissions(
int fd,
const char *filename,
const char *target,
- const char *context[_CONTEXT_MAX],
+ const Context *context,
uid_t uid) {
int r;
@@ -273,18 +277,18 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) {
return 1;
}
-static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
+static int make_filename(const Context *context, char **ret) {
_cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
sd_id128_t boot = {};
int r;
assert(context);
- c = filename_escape(context[CONTEXT_COMM]);
+ c = filename_escape(context->meta[CONTEXT_COMM]);
if (!c)
return -ENOMEM;
- u = filename_escape(context[CONTEXT_UID]);
+ u = filename_escape(context->meta[CONTEXT_UID]);
if (!u)
return -ENOMEM;
@@ -292,11 +296,11 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
if (r < 0)
return r;
- p = filename_escape(context[CONTEXT_PID]);
+ p = filename_escape(context->meta[CONTEXT_PID]);
if (!p)
return -ENOMEM;
- t = filename_escape(context[CONTEXT_TIMESTAMP]);
+ t = filename_escape(context->meta[CONTEXT_TIMESTAMP]);
if (!t)
return -ENOMEM;
@@ -313,7 +317,7 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
}
static int save_external_coredump(
- const char *context[_CONTEXT_MAX],
+ const Context *context,
int input_fd,
char **ret_filename,
int *ret_node_fd,
@@ -334,19 +338,19 @@ static int save_external_coredump(
assert(ret_data_fd);
assert(ret_size);
- r = parse_uid(context[CONTEXT_UID], &uid);
+ r = parse_uid(context->meta[CONTEXT_UID], &uid);
if (r < 0)
return log_error_errno(r, "Failed to parse UID: %m");
- r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit);
+ r = safe_atou64(context->meta[CONTEXT_RLIMIT], &rlimit);
if (r < 0)
- return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]);
+ return log_error_errno(r, "Failed to parse resource limit: %s", context->meta[CONTEXT_RLIMIT]);
if (rlimit < page_size()) {
/* Is coredumping disabled? Then don't bother saving/processing the coredump.
* Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses
* ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */
log_info("Resource limits disable core dumping for process %s (%s).",
- context[CONTEXT_PID], context[CONTEXT_COMM]);
+ context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]);
return -EBADSLT;
}
@@ -371,7 +375,7 @@ static int save_external_coredump(
r = copy_bytes(input_fd, fd, max_size, 0);
if (r < 0) {
- log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]);
+ log_error_errno(r, "Cannot store coredump of %s (%s): %m", context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]);
goto fail;
}
*ret_truncated = r == 1;
@@ -659,12 +663,12 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
return 1;
}
-static int change_uid_gid(const char *context[]) {
+static int change_uid_gid(const Context *context) {
uid_t uid;
gid_t gid;
int r;
- r = parse_uid(context[CONTEXT_UID], &uid);
+ r = parse_uid(context->meta[CONTEXT_UID], &uid);
if (r < 0)
return r;
@@ -677,7 +681,7 @@ static int change_uid_gid(const char *context[]) {
uid = gid = 0;
}
} else {
- r = parse_gid(context[CONTEXT_GID], &gid);
+ r = parse_gid(context->meta[CONTEXT_GID], &gid);
if (r < 0)
return r;
}
@@ -685,23 +689,23 @@ static int change_uid_gid(const char *context[]) {
return drop_privileges(uid, gid, 0);
}
-static bool is_journald_crash(const char *context[_CONTEXT_MAX]) {
+static bool is_journald_crash(const Context *context) {
assert(context);
- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE);
+ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE);
}
-static bool is_pid1_crash(const char *context[_CONTEXT_MAX]) {
+static bool is_pid1_crash(const Context *context) {
assert(context);
- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) ||
- streq_ptr(context[CONTEXT_PID], "1");
+ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) ||
+ streq_ptr(context->meta[CONTEXT_PID], "1");
}
#define SUBMIT_COREDUMP_FIELDS 4
static int submit_coredump(
- const char *context[_CONTEXT_MAX],
+ Context *context,
struct iovec *iovec,
size_t n_iovec_allocated,
size_t n_iovec,
@@ -760,11 +764,11 @@ static int submit_coredump(
if (coredump_size <= arg_process_size_max) {
_cleanup_free_ char *stacktrace = NULL;
- r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace);
+ r = coredump_make_stack_trace(coredump_fd, context->meta[CONTEXT_EXE], &stacktrace);
if (r >= 0)
- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
- " (", context[CONTEXT_COMM], ") of user ",
- context[CONTEXT_UID], " dumped core.",
+ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID],
+ " (", context->meta[CONTEXT_COMM], ") of user ",
+ context->meta[CONTEXT_UID], " dumped core.",
journald_crash ? "\nCoredump diverted to " : "",
journald_crash ? filename : "",
"\n\n", stacktrace);
@@ -779,9 +783,9 @@ static int submit_coredump(
if (!core_message)
#endif
log:
- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
- " (", context[CONTEXT_COMM], ") of user ",
- context[CONTEXT_UID], " dumped core.",
+ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID],
+ " (", context->meta[CONTEXT_COMM], ") of user ",
+ context->meta[CONTEXT_UID], " dumped core.",
journald_crash && filename ? "\nCoredump diverted to " : NULL,
journald_crash && filename ? filename : NULL);
if (!core_message)
@@ -826,7 +830,7 @@ log:
return 0;
}
-static void map_context_fields(const struct iovec *iovec, const char* context[]) {
+static void map_context_fields(const struct iovec *iovec, Context *context) {
static const char * const context_field_names[] = {
[CONTEXT_PID] = "COREDUMP_PID=",
@@ -857,7 +861,7 @@ static void map_context_fields(const struct iovec *iovec, const char* context[])
/* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
* buffer, though not included in the iov_len count. (see below) */
- context[i] = p;
+ context->meta[i] = p;
break;
}
}
@@ -866,7 +870,7 @@ static int process_socket(int fd) {
_cleanup_close_ int coredump_fd = -1;
struct iovec *iovec = NULL;
size_t n_iovec = 0, n_allocated = 0, i, k;
- const char *context[_CONTEXT_MAX] = {};
+ Context context = {};
int r;
assert(fd >= 0);
@@ -950,7 +954,7 @@ static int process_socket(int fd) {
iovec[n_iovec].iov_len = (size_t) n;
cmsg_close_all(&mh);
- map_context_fields(iovec + n_iovec, context);
+ map_context_fields(iovec + n_iovec, &context);
n_iovec++;
}
@@ -960,24 +964,24 @@ static int process_socket(int fd) {
}
/* Make sure we got all data we really need */
- assert(context[CONTEXT_PID]);
- assert(context[CONTEXT_UID]);
- assert(context[CONTEXT_GID]);
- assert(context[CONTEXT_SIGNAL]);
- assert(context[CONTEXT_TIMESTAMP]);
- assert(context[CONTEXT_RLIMIT]);
- assert(context[CONTEXT_HOSTNAME]);
- assert(context[CONTEXT_COMM]);
+ assert(context.meta[CONTEXT_PID]);
+ assert(context.meta[CONTEXT_UID]);
+ assert(context.meta[CONTEXT_GID]);
+ assert(context.meta[CONTEXT_SIGNAL]);
+ assert(context.meta[CONTEXT_TIMESTAMP]);
+ assert(context.meta[CONTEXT_RLIMIT]);
+ assert(context.meta[CONTEXT_HOSTNAME]);
+ assert(context.meta[CONTEXT_COMM]);
assert(coredump_fd >= 0);
/* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s
* granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we
* are reconstructing the original kernel context, we chop this off again, here. */
- k = strlen(context[CONTEXT_TIMESTAMP]);
+ k = strlen(context.meta[CONTEXT_TIMESTAMP]);
if (k > 6)
- context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6);
+ context.meta[CONTEXT_TIMESTAMP] = strndupa(context.meta[CONTEXT_TIMESTAMP], k - 6);
- r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd);
+ r = submit_coredump(&context, iovec, n_allocated, n_iovec, coredump_fd);
finish:
for (i = 0; i < n_iovec; i++)
@@ -1062,7 +1066,7 @@ static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const ch
}
static int gather_pid_metadata(
- char* context[_CONTEXT_MAX],
+ Context *context,
char **comm_fallback,
struct iovec *iovec, size_t *n_iovec) {
@@ -1077,65 +1081,69 @@ static int gather_pid_metadata(
const char *p;
int r, signo;
- r = parse_pid(context[CONTEXT_PID], &pid);
+ r = parse_pid(context->meta[CONTEXT_PID], &pid);
if (r < 0)
- return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]);
+ return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[CONTEXT_PID]);
- r = get_process_comm(pid, &context[CONTEXT_COMM]);
+ r = get_process_comm(pid, &t);
if (r < 0) {
log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m");
- context[CONTEXT_COMM] = strv_join(comm_fallback, " ");
- if (!context[CONTEXT_COMM])
+ context->meta[CONTEXT_COMM] = strv_join(comm_fallback, " ");
+ if (!context->meta[CONTEXT_COMM])
return log_oom();
- }
+ } else
+ context->meta[CONTEXT_COMM] = t;
- r = get_process_exe(pid, &context[CONTEXT_EXE]);
+ r = get_process_exe(pid, &t);
if (r < 0)
log_warning_errno(r, "Failed to get EXE, ignoring: %m");
+ else
+ context->meta[CONTEXT_EXE] = t;
- if (cg_pid_get_unit(pid, &context[CONTEXT_UNIT]) >= 0) {
- if (!is_journald_crash((const char**) context)) {
+ if (cg_pid_get_unit(pid, &t) >= 0) {
+ if (!is_journald_crash(context)) {
/* OK, now we know it's not the journal, hence we can make use of it now. */
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_open();
}
/* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */
- if (is_pid1_crash((const char**) context)) {
+ if (is_pid1_crash(context)) {
log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
disable_coredumps();
}
- set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
- }
+ set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context->meta[CONTEXT_UNIT]);
+ } else
+ context->meta[CONTEXT_UNIT] = t;
if (cg_pid_get_user_unit(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t);
/* The next few are mandatory */
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context->meta[CONTEXT_PID]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context->meta[CONTEXT_UID]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context->meta[CONTEXT_GID]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context->meta[CONTEXT_SIGNAL]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context->meta[CONTEXT_RLIMIT]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context->meta[CONTEXT_HOSTNAME]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context->meta[CONTEXT_COMM]))
return log_oom();
- if (context[CONTEXT_EXE] &&
- !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
+ if (context->meta[CONTEXT_EXE] &&
+ !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context->meta[CONTEXT_EXE]))
return log_oom();
if (sd_pid_get_session(pid, &t) >= 0)
@@ -1198,11 +1206,11 @@ static int gather_pid_metadata(
if (get_process_environ(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t);
- t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
+ t = strjoin("COREDUMP_TIMESTAMP=", context->meta[CONTEXT_TIMESTAMP], "000000");
if (t)
iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
- if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
+ if (safe_atoi(context->meta[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
return 0; /* we successfully acquired all metadata */
@@ -1210,7 +1218,7 @@ static int gather_pid_metadata(
static int process_kernel(int argc, char* argv[]) {
- char* context[_CONTEXT_MAX] = {};
+ Context context = {};
struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS];
size_t i, n_iovec, n_to_free = 0;
int r;
@@ -1222,15 +1230,15 @@ static int process_kernel(int argc, char* argv[]) {
return -EINVAL;
}
- context[CONTEXT_PID] = argv[1 + CONTEXT_PID];
- context[CONTEXT_UID] = argv[1 + CONTEXT_UID];
- context[CONTEXT_GID] = argv[1 + CONTEXT_GID];
- context[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL];
- context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
- context[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT];
- context[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME];
+ context.meta[CONTEXT_PID] = argv[1 + CONTEXT_PID];
+ context.meta[CONTEXT_UID] = argv[1 + CONTEXT_UID];
+ context.meta[CONTEXT_GID] = argv[1 + CONTEXT_GID];
+ context.meta[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL];
+ context.meta[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
+ context.meta[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT];
+ context.meta[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME];
- r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
+ r = gather_pid_metadata(&context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
if (r < 0)
goto finish;
@@ -1243,8 +1251,8 @@ static int process_kernel(int argc, char* argv[]) {
assert(n_iovec <= ELEMENTSOF(iovec));
- if (is_journald_crash((const char**) context) || is_pid1_crash((const char**) context))
- r = submit_coredump((const char**) context,
+ if (is_journald_crash(&context) || is_pid1_crash(&context))
+ r = submit_coredump(&context,
iovec, ELEMENTSOF(iovec), n_iovec,
STDIN_FILENO);
else
@@ -1255,15 +1263,15 @@ static int process_kernel(int argc, char* argv[]) {
free(iovec[i].iov_base);
/* Those fields are allocated by gather_pid_metadata */
- free(context[CONTEXT_COMM]);
- free(context[CONTEXT_EXE]);
- free(context[CONTEXT_UNIT]);
+ free((char *) context.meta[CONTEXT_COMM]);
+ free((char *) context.meta[CONTEXT_EXE]);
+ free((char *) context.meta[CONTEXT_UNIT]);
return r;
}
static int process_backtrace(int argc, char *argv[]) {
- char *context[_CONTEXT_MAX] = {};
+ Context context = {};
_cleanup_free_ char *message = NULL;
_cleanup_free_ struct iovec *iovec = NULL;
size_t n_iovec, n_allocated, n_to_free = 0, i;
@@ -1279,13 +1287,13 @@ static int process_backtrace(int argc, char *argv[]) {
return -EINVAL;
}
- context[CONTEXT_PID] = argv[2 + CONTEXT_PID];
- context[CONTEXT_UID] = argv[2 + CONTEXT_UID];
- context[CONTEXT_GID] = argv[2 + CONTEXT_GID];
- context[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL];
- context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
- context[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT];
- context[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME];
+ context.meta[CONTEXT_PID] = argv[2 + CONTEXT_PID];
+ context.meta[CONTEXT_UID] = argv[2 + CONTEXT_UID];
+ context.meta[CONTEXT_GID] = argv[2 + CONTEXT_GID];
+ context.meta[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL];
+ context.meta[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
+ context.meta[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT];
+ context.meta[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME];
n_allocated = 34 + COREDUMP_STORAGE_EXTERNAL;
/* 26 metadata, 2 static, +unknown input, 4 storage, rounded up */
@@ -1293,7 +1301,7 @@ static int process_backtrace(int argc, char *argv[]) {
if (!iovec)
return log_oom();
- r = gather_pid_metadata(context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free);
+ r = gather_pid_metadata(&context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free);
if (r < 0)
goto finish;
if (r > 0) {
@@ -1320,10 +1328,10 @@ static int process_backtrace(int argc, char *argv[]) {
if (journal_importer_eof(&importer)) {
log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter");
- message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
- " (", context[CONTEXT_COMM], ")"
- " of user ", context[CONTEXT_UID],
- " failed with ", context[CONTEXT_SIGNAL]);
+ message = strjoin("MESSAGE=Process ", context.meta[CONTEXT_PID],
+ " (", context.meta[CONTEXT_COMM], ")"
+ " of user ", context.meta[CONTEXT_UID],
+ " failed with ", context.meta[CONTEXT_SIGNAL]);
if (!message) {
r = log_oom();
goto finish;
@@ -1349,9 +1357,9 @@ static int process_backtrace(int argc, char *argv[]) {
free(iovec[i].iov_base);
/* Those fields are allocated by gather_pid_metadata */
- free(context[CONTEXT_COMM]);
- free(context[CONTEXT_EXE]);
- free(context[CONTEXT_UNIT]);
+ free((char *) context.meta[CONTEXT_COMM]);
+ free((char *) context.meta[CONTEXT_EXE]);
+ free((char *) context.meta[CONTEXT_UNIT]);
return r;
}

View File

@ -0,0 +1,354 @@
From d178865d3d9940423f4d99360e3dc2fcaf0b2c96 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 28 Nov 2022 12:12:55 +0100
Subject: [PATCH] coredump: do not allow user to access coredumps with changed
uid/gid/capabilities
When the user starts a program which elevates its permissions via setuid,
setgid, or capabilities set on the file, it may access additional information
which would then be visible in the coredump. We shouldn't make the the coredump
visible to the user in such cases.
Reported-by: Matthias Gerstner <mgerstner@suse.de>
This reads the /proc/<pid>/auxv file and attaches it to the process metadata as
PROC_AUXV. Before the coredump is submitted, it is parsed and if either
at_secure was set (which the kernel will do for processes that are setuid,
setgid, or setcap), or if the effective uid/gid don't match uid/gid, the file
is not made accessible to the user. If we can't access this data, we assume the
file should not be made accessible either. In principle we could also access
the auxv data from a note in the core file, but that is much more complex and
it seems better to use the stand-alone file that is provided by the kernel.
Attaching auxv is both convient for this patch (because this way it's passed
between the stages along with other fields), but I think it makes sense to save
it in general.
We use the information early in the core file to figure out if the program was
32-bit or 64-bit and its endianness. This way we don't need heuristics to guess
whether the format of the auxv structure. This test might reject some cases on
fringe architecutes. But the impact would be limited: we just won't grant the
user permissions to view the coredump file. If people report that we're missing
some cases, we can always enhance this to support more architectures.
I tested auxv parsing on amd64, 32-bit program on amd64, arm64, arm32, and
ppc64el, but not the whole coredump handling.
(cherry picked from commit 3e4d0f6cf99f8677edd6a237382a65bfe758de03)
Resolves: #2155520
---
src/coredump/coredump.c | 190 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 182 insertions(+), 8 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index ebc56d8342..d8acd2d3a7 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdio_ext.h>
#include <sys/prctl.h>
+#include <sys/auxv.h>
#include <sys/xattr.h>
#include <unistd.h>
@@ -88,11 +89,13 @@ enum {
CONTEXT_COMM,
CONTEXT_EXE,
CONTEXT_UNIT,
+ CONTEXT_PROC_AUXV,
_CONTEXT_MAX
};
typedef struct Context {
const char *meta[_CONTEXT_MAX];
+ size_t meta_size[_CONTEXT_MAX];
} Context;
typedef enum CoredumpStorage {
@@ -148,8 +151,7 @@ static inline uint64_t storage_size_max(void) {
return 0;
}
-static int fix_acl(int fd, uid_t uid) {
-
+static int fix_acl(int fd, uid_t uid, bool allow_user) {
#if HAVE_ACL
_cleanup_(acl_freep) acl_t acl = NULL;
acl_entry_t entry;
@@ -157,6 +159,11 @@ static int fix_acl(int fd, uid_t uid) {
int r;
assert(fd >= 0);
+ assert(uid_is_valid(uid));
+
+ /* We don't allow users to read coredumps if the uid or capabilities were changed. */
+ if (!allow_user)
+ return 0;
if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
return 0;
@@ -235,7 +242,8 @@ static int fix_permissions(
const char *filename,
const char *target,
const Context *context,
- uid_t uid) {
+ uid_t uid,
+ bool allow_user) {
int r;
@@ -245,7 +253,7 @@ static int fix_permissions(
/* Ignore errors on these */
(void) fchmod(fd, 0640);
- (void) fix_acl(fd, uid);
+ (void) fix_acl(fd, uid, allow_user);
(void) fix_xattr(fd, context);
if (fsync(fd) < 0)
@@ -316,6 +324,154 @@ static int make_filename(const Context *context, char **ret) {
return 0;
}
+static int parse_auxv64(
+ const uint64_t *auxv,
+ size_t size_bytes,
+ int *at_secure,
+ uid_t *uid,
+ uid_t *euid,
+ gid_t *gid,
+ gid_t *egid) {
+
+ assert(auxv || size_bytes == 0);
+
+ if (size_bytes % (2 * sizeof(uint64_t)) != 0)
+ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes);
+
+ size_t words = size_bytes / sizeof(uint64_t);
+
+ /* Note that we set output variables even on error. */
+
+ for (size_t i = 0; i + 1 < words; i += 2)
+ switch (auxv[i]) {
+ case AT_SECURE:
+ *at_secure = auxv[i + 1] != 0;
+ break;
+ case AT_UID:
+ *uid = auxv[i + 1];
+ break;
+ case AT_EUID:
+ *euid = auxv[i + 1];
+ break;
+ case AT_GID:
+ *gid = auxv[i + 1];
+ break;
+ case AT_EGID:
+ *egid = auxv[i + 1];
+ break;
+ case AT_NULL:
+ if (auxv[i + 1] != 0)
+ goto error;
+ return 0;
+ }
+ error:
+ return log_warning_errno(-ENODATA,
+ "AT_NULL terminator not found, cannot parse auxv structure.");
+}
+
+static int parse_auxv32(
+ const uint32_t *auxv,
+ size_t size_bytes,
+ int *at_secure,
+ uid_t *uid,
+ uid_t *euid,
+ gid_t *gid,
+ gid_t *egid) {
+
+ assert(auxv || size_bytes == 0);
+
+ size_t words = size_bytes / sizeof(uint32_t);
+
+ if (size_bytes % (2 * sizeof(uint32_t)) != 0)
+ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes);
+
+ /* Note that we set output variables even on error. */
+
+ for (size_t i = 0; i + 1 < words; i += 2)
+ switch (auxv[i]) {
+ case AT_SECURE:
+ *at_secure = auxv[i + 1] != 0;
+ break;
+ case AT_UID:
+ *uid = auxv[i + 1];
+ break;
+ case AT_EUID:
+ *euid = auxv[i + 1];
+ break;
+ case AT_GID:
+ *gid = auxv[i + 1];
+ break;
+ case AT_EGID:
+ *egid = auxv[i + 1];
+ break;
+ case AT_NULL:
+ if (auxv[i + 1] != 0)
+ goto error;
+ return 0;
+ }
+ error:
+ return log_warning_errno(-ENODATA,
+ "AT_NULL terminator not found, cannot parse auxv structure.");
+}
+
+static int grant_user_access(int core_fd, const Context *context) {
+ int at_secure = -1;
+ uid_t uid = UID_INVALID, euid = UID_INVALID;
+ uid_t gid = GID_INVALID, egid = GID_INVALID;
+ int r;
+
+ assert(core_fd >= 0);
+ assert(context);
+
+ if (!context->meta[CONTEXT_PROC_AUXV])
+ return log_warning_errno(-ENODATA, "No auxv data, not adjusting permissions.");
+
+ uint8_t elf[EI_NIDENT];
+ errno = 0;
+ if (pread(core_fd, &elf, sizeof(elf), 0) != sizeof(elf))
+ return log_warning_errno(errno > 0 ? -errno : -EIO,
+ "Failed to pread from coredump fd: %s",
+ errno > 0 ? STRERROR(errno) : "Unexpected EOF");
+
+ if (elf[EI_MAG0] != ELFMAG0 ||
+ elf[EI_MAG1] != ELFMAG1 ||
+ elf[EI_MAG2] != ELFMAG2 ||
+ elf[EI_MAG3] != ELFMAG3 ||
+ elf[EI_VERSION] != EV_CURRENT)
+ return log_info_errno(-EUCLEAN,
+ "Core file does not have ELF header, not adjusting permissions.");
+ if (!IN_SET(elf[EI_CLASS], ELFCLASS32, ELFCLASS64) ||
+ !IN_SET(elf[EI_DATA], ELFDATA2LSB, ELFDATA2MSB))
+ return log_info_errno(-EUCLEAN,
+ "Core file has strange ELF class, not adjusting permissions.");
+
+ if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN))
+ return log_info_errno(-EUCLEAN,
+ "Core file has non-native endianness, not adjusting permissions.");
+
+ if (elf[EI_CLASS] == ELFCLASS64)
+ r = parse_auxv64((const uint64_t*) context->meta[CONTEXT_PROC_AUXV],
+ context->meta_size[CONTEXT_PROC_AUXV],
+ &at_secure, &uid, &euid, &gid, &egid);
+ else
+ r = parse_auxv32((const uint32_t*) context->meta[CONTEXT_PROC_AUXV],
+ context->meta_size[CONTEXT_PROC_AUXV],
+ &at_secure, &uid, &euid, &gid, &egid);
+ if (r < 0)
+ return r;
+
+ /* We allow access if we got all the data and at_secure is not set and
+ * the uid/gid matches euid/egid. */
+ bool ret =
+ at_secure == 0 &&
+ uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
+ gid != GID_INVALID && egid != GID_INVALID && gid == egid;
+ log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
+ ret ? "permit" : "restrict",
+ uid, euid, gid, egid, yes_no(at_secure));
+ return ret;
+}
+
static int save_external_coredump(
const Context *context,
int input_fd,
@@ -395,6 +551,8 @@ static int save_external_coredump(
goto fail;
}
+ bool allow_user = grant_user_access(fd, context) > 0;
+
#if HAVE_XZ || HAVE_LZ4
/* If we will remove the coredump anyway, do not compress. */
if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
@@ -420,7 +578,7 @@ static int save_external_coredump(
goto fail_compressed;
}
- r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid);
+ r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user);
if (r < 0)
goto fail_compressed;
@@ -443,7 +601,7 @@ static int save_external_coredump(
uncompressed:
#endif
- r = fix_permissions(fd, tmp, fn, context, uid);
+ r = fix_permissions(fd, tmp, fn, context, uid, allow_user);
if (r < 0)
goto fail;
@@ -842,6 +1000,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) {
[CONTEXT_HOSTNAME] = "COREDUMP_HOSTNAME=",
[CONTEXT_COMM] = "COREDUMP_COMM=",
[CONTEXT_EXE] = "COREDUMP_EXE=",
+ [CONTEXT_PROC_AUXV] = "COREDUMP_PROC_AUXV=",
};
unsigned i;
@@ -862,6 +1021,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) {
/* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
* buffer, though not included in the iov_len count. (see below) */
context->meta[i] = p;
+ context->meta_size[i] = iovec->iov_len - strlen(context_field_names[i]);
break;
}
}
@@ -1070,7 +1230,7 @@ static int gather_pid_metadata(
char **comm_fallback,
struct iovec *iovec, size_t *n_iovec) {
- /* We need 27 empty slots in iovec!
+ /* We need 28 empty slots in iovec!
*
* Note that if we fail on oom later on, we do not roll-back changes to the iovec structure. (It remains valid,
* with the first n_iovec fields initialized.) */
@@ -1078,6 +1238,7 @@ static int gather_pid_metadata(
uid_t owner_uid;
pid_t pid;
char *t;
+ size_t size;
const char *p;
int r, signo;
@@ -1187,6 +1348,19 @@ static int gather_pid_metadata(
if (read_full_file(p, &t, NULL) >=0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t);
+ /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */
+ p = procfs_file_alloca(pid, "auxv");
+ if (read_full_file(p, &t, &size) >= 0) {
+ char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1);
+ if (buf) {
+ /* Add a dummy terminator to make save_context() happy. */
+ *((uint8_t*) mempcpy(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size)) = '\0';
+ iovec[(*n_iovec)++] = IOVEC_MAKE(buf, size + strlen("COREDUMP_PROC_AUXV="));
+ }
+
+ free(t);
+ }
+
if (get_process_cwd(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t);
@@ -1219,7 +1393,7 @@ static int gather_pid_metadata(
static int process_kernel(int argc, char* argv[]) {
Context context = {};
- struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS];
+ struct iovec iovec[30 + SUBMIT_COREDUMP_FIELDS];
size_t i, n_iovec, n_to_free = 0;
int r;

View File

@ -0,0 +1,70 @@
From a55bdb007ca24900a704f72359305b04125d9e05 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 20 Apr 2022 10:13:43 +0200
Subject: [PATCH] logind: remember our idle state and use it to detect idle
level transitions
Fixes #16391
(cherry picked from commit 4e2cfb778b9ed7f22ee98f48f28cf8678d25ad32)
Resolved: #1866955
---
src/login/logind.c | 23 +++++++++++++++++++----
src/login/logind.h | 1 +
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/src/login/logind.c b/src/login/logind.c
index 6b576dad0d..bb1d3f3523 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1027,18 +1027,33 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
n = now(CLOCK_MONOTONIC);
r = manager_get_idle_hint(m, &since);
- if (r <= 0)
+ if (r <= 0) {
/* Not idle. Let's check if after a timeout it might be idle then. */
elapse = n + m->idle_action_usec;
- else {
+ m->was_idle = false;
+ } else {
+
/* Idle! Let's see if it's time to do something, or if
* we shall sleep for longer. */
if (n >= since.monotonic + m->idle_action_usec &&
(m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) {
- log_info("System idle. Taking action.");
+ bool is_edge = false;
+
+ /* We weren't idle previously or some activity happened while we were sleeping, and now we are
+ * idle. Let's remember that for the next time and make this an edge transition. */
+ if (!m->was_idle || since.monotonic >= m->idle_action_not_before_usec) {
+ is_edge = true;
+ m->was_idle = true;
+ }
+
+ if (m->idle_action == HANDLE_LOCK && !is_edge)
+ /* We are idle and we were before so we are actually not taking any action. */
+ log_debug("System idle.");
+ else
+ log_info("System idle. Doing %s operation.", handle_action_to_string(m->idle_action));
- manager_handle_action(m, 0, m->idle_action, false, false);
+ manager_handle_action(m, 0, m->idle_action, false, is_edge);
m->idle_action_not_before_usec = n;
}
diff --git a/src/login/logind.h b/src/login/logind.h
index 606adf4fe6..b9b4a5113f 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -101,6 +101,7 @@ struct Manager {
usec_t idle_action_usec;
usec_t idle_action_not_before_usec;
HandleAction idle_action;
+ bool was_idle;
usec_t stop_idle_session_usec;

View File

@ -0,0 +1,103 @@
From 1925845dc10330e4b48fec68333fac6ef2b7bf5c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 1 Jun 2022 08:56:08 +0900
Subject: [PATCH] test: import logind test from debian/ubuntu test suite
[dtardon: Picked just the scaffolding, not the tests themselves.]
(cherry picked from commit 9c94ab0f6ff22da4278a6e9a93ddc480607c55ac)
Related: #1866955
---
test/TEST-35-LOGIN/Makefile | 1 +
test/TEST-35-LOGIN/test.sh | 55 +++++++++++++++++++++++++++++++++
test/TEST-35-LOGIN/testsuite.sh | 9 ++++++
3 files changed, 65 insertions(+)
create mode 120000 test/TEST-35-LOGIN/Makefile
create mode 100755 test/TEST-35-LOGIN/test.sh
create mode 100755 test/TEST-35-LOGIN/testsuite.sh
diff --git a/test/TEST-35-LOGIN/Makefile b/test/TEST-35-LOGIN/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-35-LOGIN/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-35-LOGIN/test.sh b/test/TEST-35-LOGIN/test.sh
new file mode 100755
index 0000000000..32410c8149
--- /dev/null
+++ b/test/TEST-35-LOGIN/test.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+TEST_DESCRIPTION="LOGIN"
+
+# shellcheck source=test/test-functions
+. "${TEST_BASE_DIR:?}/test-functions"
+
+test_setup() {
+ create_empty_image
+ mkdir -p "$TESTDIR"/root
+ mount "${LOOPDEV}p1" "$TESTDIR"/root
+
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name="${LOOPDEV}p2")
+
+ setup_basic_environment
+
+ inst_binary pkill
+ inst_binary useradd
+ inst_binary userdel
+
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-machined.service
+
+ # setup the testsuite service
+ cat >"$initdir"/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/bin/bash -x /testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+ cp testsuite.sh "$initdir"/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount "$TESTDIR"/root
+}
+
+do_test "$@"
diff --git a/test/TEST-35-LOGIN/testsuite.sh b/test/TEST-35-LOGIN/testsuite.sh
new file mode 100755
index 0000000000..9855b4bc80
--- /dev/null
+++ b/test/TEST-35-LOGIN/testsuite.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+: >/failed
+
+touch /testok
+rm /failed

View File

@ -0,0 +1,37 @@
From 21c281585983fe2efc2b74d712d98ff7e6c013b1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Jun 2022 09:11:00 +0900
Subject: [PATCH] test: introduce inst_recursive() helper function
(cherry picked from commit da0465dc95388afc15598357452afef85035c639)
Related: #1866955
---
test/test-functions | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/test/test-functions b/test/test-functions
index 19363be858..9606a1b085 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -1224,6 +1224,20 @@ inst_any() {
return 1
}
+inst_recursive() {
+ local p item
+
+ for p in "$@"; do
+ while read -r item; do
+ if [[ -d "$item" ]]; then
+ inst_dir "$item"
+ elif [[ -f "$item" ]]; then
+ inst_simple "$item"
+ fi
+ done < <(find "$p" 2>/dev/null)
+ done
+}
+
# dracut_install [-o ] <file> [<file> ... ]
# Install <file> to the initramfs image
# -o optionally install the <file> and don't fail, if it is not there

View File

@ -0,0 +1,148 @@
From 638c2418e705410344e07e77f944530df0f4608f Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 1 Jul 2022 12:59:57 +0200
Subject: [PATCH] tests: verify that Lock D-Bus signal is sent when
IdleAction=lock
(cherry picked from commit 181656fc0faa885d69bc34822b8e9b5de3fdf6bf)
Related: #1866955
---
test/TEST-35-LOGIN/test.sh | 11 +++-
test/TEST-35-LOGIN/testsuite.sh | 93 +++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 1 deletion(-)
diff --git a/test/TEST-35-LOGIN/test.sh b/test/TEST-35-LOGIN/test.sh
index 32410c8149..f83afcff49 100755
--- a/test/TEST-35-LOGIN/test.sh
+++ b/test/TEST-35-LOGIN/test.sh
@@ -14,14 +14,23 @@ test_setup() {
(
LOG_LEVEL=5
- eval $(udevadm info --export --query=env --name="${LOOPDEV}p2")
+ eval "$(udevadm info --export --query=env --name="${LOOPDEV}p2")"
setup_basic_environment
+ inst_binary awk
inst_binary pkill
inst_binary useradd
inst_binary userdel
+ if command -v expect >/dev/null && command -v tclsh >/dev/null ; then
+ # shellcheck disable=SC2016
+ version="$(tclsh <<< 'puts $tcl_version')"
+
+ dracut_install expect
+ inst_recursive /usr/lib64/tcl"$version" /usr/share/tcl"$version"
+ fi
+
# mask some services that we do not want to run in these tests
ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-hwdb-update.service
ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-journal-catalog-update.service
diff --git a/test/TEST-35-LOGIN/testsuite.sh b/test/TEST-35-LOGIN/testsuite.sh
index 9855b4bc80..e4d72beb74 100755
--- a/test/TEST-35-LOGIN/testsuite.sh
+++ b/test/TEST-35-LOGIN/testsuite.sh
@@ -3,7 +3,100 @@
set -eux
set -o pipefail
+setup_idle_action_lock() {
+ useradd testuser ||:
+
+ mkdir -p /run/systemd/logind.conf.d/
+ cat >/run/systemd/logind.conf.d/idle-action-lock.conf <<EOF
+[Login]
+IdleAction=lock
+IdleActionSec=1s
+EOF
+
+ mkdir -p /run/systemd/systemd-logind.service.d/
+ cat >/run/systemd/systemd-logind.service.d/debug.conf <<EOF
+[Service]
+Environment=SYSTEMD_LOG_LEVEL=debug
+EOF
+
+ systemctl restart systemd-logind.service
+}
+
+teardown_idle_action_lock() {(
+ set +ex
+ rm -f /run/systemd/logind.conf.d/idle-action-lock.conf
+ rm -f /run/systemd/systemd-logind.service.d/debug.conf
+ pkill -9 -u "$(id -u testuser)"
+ userdel -r testuser
+ systemctl restart systemd-logind.service
+)}
+
+test_lock_idle_action() {
+ if ! command -v expect >/dev/null ; then
+ echo >&2 "expect not installed, skiping test ${FUNCNAME[0]}"
+ return 0
+ fi
+
+ setup_idle_action_lock
+ trap teardown_idle_action_lock RETURN
+
+ if loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -q testuser ; then
+ echo >&2 "Session of the \'testuser\' is already present."
+ return 1
+ fi
+
+ # IdleActionSec is set 1s but the accuracy of associated timer is 30s so we
+ # need to sleep in worst case for 31s to make sure timer elapsed. We sleep
+ # here for 35s to accomodate for any possible scheudling delays.
+ cat > /tmp/test.exp <<EOF
+spawn systemd-run -G -t -p PAMName=login -p User=testuser bash
+send "sleep 35\r"
+send "echo foobar\r"
+send "sleep 35\r"
+send "exit\r"
+interact
+wait
+EOF
+
+ ts="$(date '+%H:%M:%S')"
+ busctl --match "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Session',member='Lock'" monitor > dbus.log &
+
+ expect /tmp/test.exp &
+
+ # Sleep a bit to give expect time to spawn systemd-run before we check for
+ # the presence of resulting session.
+ sleep 2
+ if [ "$(loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -c testuser)" != 1 ] ; then
+ echo >&2 "\'testuser\' is expected to have exactly one session running."
+ return 1
+ fi
+
+ wait %2
+ sleep 20
+ kill %1
+
+ # We slept for 35s , in that interval all sessions should have become idle
+ # and "Lock" signal should have been sent out. Then we wrote to tty to make
+ # session active again and next we slept for another 35s so sessions have
+ # become idle again. 'Lock' signal is sent out for each session, we have at
+ # least one session, so minimum of 2 "Lock" signals must have been sent.
+ if [ "$(grep -c Member=Lock dbus.log)" -lt 2 ]; then
+ echo >&2 "Too few 'Lock' D-Bus signal sent, expected at least 2."
+ return 1
+ fi
+
+ journalctl -b -u systemd-logind.service --since="$ts" > logind.log
+ if [ "$(grep -c 'System idle. Doing lock operation.' logind.log)" -lt 2 ]; then
+ echo >&2 "System haven't entered idle state at least 2 times."
+ return 1
+ fi
+
+ rm -f dbus.log logind.log
+}
+
: >/failed
+test_lock_idle_action
+
touch /testok
rm /failed

View File

@ -0,0 +1,86 @@
From 797b00e6a6f33d2b74beba02f678bf4d12e2146b Mon Sep 17 00:00:00 2001
From: Ludwig Nussel <ludwig.nussel@suse.de>
Date: Tue, 14 Dec 2021 17:27:05 +0100
Subject: [PATCH] systemctl: simplify halt_main()
The code at this point is not able to tell whether it was called as
halt/poweroff/reboot or shutdown with time "now".
The code also takes a shortcut to skip logind if called as root.
That however means asking shutdown for immediate action won't trigger a
wall message.
As per https://github.com/systemd/systemd/issues/8424#issuecomment-374677315
all commands should trigger a wall message.
That simplifies the code as we can try logind first always.
(cherry picked from commit adefc8789b63225662e50ceaa282f9553b5c64eb)
Resolves: #2053273
---
src/systemctl/systemctl.c | 44 ++++++++++++++++-----------------------
1 file changed, 18 insertions(+), 26 deletions(-)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index b967550b97..4bedb52f2a 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -8658,34 +8658,23 @@ static int logind_schedule_shutdown(void) {
static int halt_main(void) {
int r;
- r = logind_check_inhibitors(arg_action);
- if (r < 0)
- return r;
-
+ /* always try logind first */
if (arg_when > 0)
- return logind_schedule_shutdown();
-
- if (geteuid() != 0) {
- if (arg_dry_run || arg_force > 0) {
- (void) must_be_root();
- return -EPERM;
- }
+ r = logind_schedule_shutdown();
+ else {
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
- /* Try logind if we are a normal user and no special
- * mode applies. Maybe PolicyKit allows us to shutdown
- * the machine. */
- if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
- r = logind_reboot(arg_action);
- if (r >= 0)
- return r;
- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* requested operation is not
- * supported on the local system or
- * already in progress */
- return r;
- /* on all other errors, try low-level operation */
- }
+ r = logind_reboot(arg_action);
}
+ if (r >= 0)
+ return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* Requested operation is not supported on the local system or already in
+ * progress */
+ return r;
+ /* on all other errors, try low-level operation */
/* In order to minimize the difference between operation with and
* without logind, we explicitly enable non-blocking mode for this,
@@ -8695,7 +8684,10 @@ static int halt_main(void) {
if (!arg_dry_run && !arg_force)
return start_with_fallback();
- assert(geteuid() == 0);
+ if (geteuid() != 0) {
+ (void) must_be_root();
+ return -EPERM;
+ }
if (!arg_no_wtmp) {
if (sd_booted() > 0)

View File

@ -0,0 +1,51 @@
From 1d63577410cde215c04921d62f435259a6b258d7 Mon Sep 17 00:00:00 2001
From: Ludwig Nussel <ludwig.nussel@suse.de>
Date: Mon, 20 Dec 2021 18:05:50 +0100
Subject: [PATCH] systemctl: shutdown don't fallback on auth fail
For shutdowns don't fall back to starting the target directly if talking
to logind failed with auth failure. That would just lead to another
polkit auth attempt.
(cherry picked from commit 38d55bf2641f345445cb4e6a5e5e808555591db2)
Related: #2053273
---
src/systemctl/systemctl.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 4bedb52f2a..199f736f7f 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3675,8 +3675,8 @@ static int start_special(int argc, char *argv[], void *userdata) {
r = logind_reboot(a);
if (r >= 0)
return r;
- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* requested operation is not supported or already in progress */
+ if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
+ /* Requested operation requires auth, is not supported or already in progress */
return r;
/* On all other errors, try low-level operation. In order to minimize the difference between
@@ -8644,7 +8644,7 @@ static int logind_schedule_shutdown(void) {
action,
arg_when);
if (r < 0)
- return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
+ return log_warning_errno(r, "Failed to schedule shutdown: %s", bus_error_message(&error, r));
if (!arg_quiet)
log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
@@ -8670,8 +8670,8 @@ static int halt_main(void) {
}
if (r >= 0)
return r;
- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* Requested operation is not supported on the local system or already in
+ if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
+ /* Requested operation requires auth, is not supported on the local system or already in
* progress */
return r;
/* on all other errors, try low-level operation */

View File

@ -0,0 +1,82 @@
From d36295d7c1b110d150b7af6e3354c28af4c4884d Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 30 Jan 2023 14:27:24 +0100
Subject: [PATCH] systemctl: reintroduce the original halt_main()
RHEL-only
Related: #2053273
---
src/systemctl/systemctl.c | 59 +++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 199f736f7f..a26e4a913a 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -8655,6 +8655,65 @@ static int logind_schedule_shutdown(void) {
#endif
}
+static int halt_main_old(void) {
+ int r;
+
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
+
+ if (arg_when > 0)
+ return logind_schedule_shutdown();
+
+ if (geteuid() != 0) {
+ if (arg_dry_run || arg_force > 0) {
+ (void) must_be_root();
+ return -EPERM;
+ }
+
+ /* Try logind if we are a normal user and no special
+ * mode applies. Maybe PolicyKit allows us to shutdown
+ * the machine. */
+ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
+ r = logind_reboot(arg_action);
+ if (r >= 0)
+ return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* requested operation is not
+ * supported on the local system or
+ * already in progress */
+ return r;
+ /* on all other errors, try low-level operation */
+ }
+ }
+
+ /* In order to minimize the difference between operation with and
+ * without logind, we explicitly enable non-blocking mode for this,
+ * as logind's shutdown operations are always non-blocking. */
+ arg_no_block = true;
+
+ if (!arg_dry_run && !arg_force)
+ return start_with_fallback();
+
+ assert(geteuid() == 0);
+
+ if (!arg_no_wtmp) {
+ if (sd_booted() > 0)
+ log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
+ else {
+ r = utmp_put_shutdown();
+ if (r < 0)
+ log_warning_errno(r, "Failed to write utmp record: %m");
+ }
+ }
+
+ if (arg_dry_run)
+ return 0;
+
+ r = halt_now(arg_action);
+ return log_error_errno(r, "Failed to reboot: %m");
+}
+
static int halt_main(void) {
int r;

View File

@ -0,0 +1,44 @@
From 74632586b46c7e88b09c57eec50f9c4aed254b98 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 30 Jan 2023 14:31:23 +0100
Subject: [PATCH] systemctl: preserve old behavior unless requested
Currently, the legacy shutdown commands ignore inhibitors and reboot
immediately if run by root. Let's preserve that behavior in RHEL-8 by
default. The new behavior can be turned on by those who want it by
exporting SYSTEMD_NEW_SHUTDOWN=1 .
RHEL-only
Related: #2053273
---
src/systemctl/systemctl.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index a26e4a913a..1546119ce5 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -8714,7 +8714,7 @@ static int halt_main_old(void) {
return log_error_errno(r, "Failed to reboot: %m");
}
-static int halt_main(void) {
+static int halt_main_new(void) {
int r;
/* always try logind first */
@@ -8765,6 +8765,13 @@ static int halt_main(void) {
return log_error_errno(r, "Failed to reboot: %m");
}
+static int halt_main(void) {
+ if (getenv_bool("SYSTEMD_NEW_SHUTDOWN") > 0)
+ return halt_main_new();
+ else
+ return halt_main_old();
+}
+
static int runlevel_main(void) {
int r, runlevel, previous;

View File

@ -0,0 +1,43 @@
From ea3910e561f043f5a131a846862955c77169da1b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 19 Nov 2018 11:39:45 +0100
Subject: [PATCH] pam_systemd: suppress LOG_DEBUG log messages if debugging is
off
In the PAM module we need to suppress LOG_DEBUG messages manually, if
debug logging is not on, as PAM won't do this for us. We did this
correctly for most log messages already, but two were missing. Let's fix
those too.
Fixes: #10822
(cherry picked from commit 2675747f3cdd6f1e6236bbb2f79abfa53fb307f1)
Resolves: #2170084
---
src/login/pam_systemd.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 64e1b4d1bf..c87e980b18 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -476,7 +476,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
}
if (seat && !streq(seat, "seat0") && vtnr != 0) {
- pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat);
+ if (debug)
+ pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat);
vtnr = 0;
}
@@ -577,7 +578,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
- pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r));
+ if (debug)
+ pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r));
return PAM_SUCCESS;
} else {
pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r));

View File

@ -0,0 +1,50 @@
From 33351e103734188a4a30b88e7f2ea0613d628599 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 16 Feb 2023 15:56:52 +0100
Subject: [PATCH] udev/net_id: introduce naming scheme for RHEL-8.8
RHEL-only
Resolves: #2170499
---
man/systemd.net-naming-scheme.xml | 6 ++++++
src/udev/udev-builtin-net_id.c | 2 ++
2 files changed, 8 insertions(+)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index a567483995..3cc7719e99 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -328,6 +328,12 @@
for that, the limit is increased to now 65535.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>rhel-8.8</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.7</constant>.</para>
+ </varlistentry>
+
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known to this
particular version of systemd.</para>
</variablelist>
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index df84acf27c..ef2bb1b08e 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -141,6 +141,7 @@ typedef enum NamingSchemeFlags {
NAMING_RHEL_8_5 = NAMING_RHEL_8_4,
NAMING_RHEL_8_6 = NAMING_RHEL_8_4,
NAMING_RHEL_8_7 = NAMING_RHEL_8_4|NAMING_SLOT_FUNCTION_ID|NAMING_16BIT_INDEX,
+ NAMING_RHEL_8_8 = NAMING_RHEL_8_7,
_NAMING_SCHEME_FLAGS_INVALID = -1,
} NamingSchemeFlags;
@@ -161,6 +162,7 @@ static const NamingScheme naming_schemes[] = {
{ "rhel-8.5", NAMING_RHEL_8_5 },
{ "rhel-8.6", NAMING_RHEL_8_6 },
{ "rhel-8.7", NAMING_RHEL_8_7 },
+ { "rhel-8.8", NAMING_RHEL_8_8 },
/* … add more schemes here, as the logic to name devices is updated … */
};

View File

@ -0,0 +1,176 @@
From 8f0a91b5192b72eb8b0f06e04ef3515d0397fcb8 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 5 Apr 2019 18:20:25 +0200
Subject: [PATCH] journald: add API to move logging from /var to /run again
We now have this nice little Varlink API, let's beef it up a bit.
[dtardon: This diverges from the upstream commit in two ways: One is
that the new action is bound to a signal, as varlink is not available.
The other is that this introduces a new "flag" file
/run/systemd/journal/relinquished, which is essentially the opposite of
/run/systemd/journal/flushed (hence at most one of them may exist at any
time).]
(cherry picked from commit b4e26d1d8e582d78e67ed766177f10e8e194404c)
Related: #1873540
---
src/journal/journald-server.c | 64 ++++++++++++++++++++++++++++-------
1 file changed, 51 insertions(+), 13 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 7632e2d9d0..279a32768c 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -283,13 +283,14 @@ static bool flushed_flag_is_set(void) {
return access("/run/systemd/journal/flushed", F_OK) >= 0;
}
-static int system_journal_open(Server *s, bool flush_requested) {
+static int system_journal_open(Server *s, bool flush_requested, bool relinquish_requested) {
const char *fn;
int r = 0;
if (!s->system_journal &&
IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) &&
- (flush_requested || flushed_flag_is_set())) {
+ (flush_requested || flushed_flag_is_set()) &&
+ !relinquish_requested) {
/* If in auto mode: first try to create the machine
* path, but not the prefix.
@@ -331,7 +332,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
fn = strjoina(s->runtime_storage.path, "/system.journal");
- if (s->system_journal) {
+ if (s->system_journal && !relinquish_requested) {
/* Try to open the runtime journal, but only
* if it already exists, so that we can flush
@@ -386,7 +387,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
* else that's left the journals as NULL).
*
* Fixes https://github.com/systemd/systemd/issues/3968 */
- (void) system_journal_open(s, false);
+ (void) system_journal_open(s, false, false);
/* We split up user logs only on /var, not on /run. If the
* runtime file is open, we write to it exclusively, in order
@@ -964,7 +965,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
char ts[FORMAT_TIMESPAN_MAX];
usec_t start;
unsigned n = 0;
- int r;
+ int r, k;
assert(s);
@@ -977,7 +978,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
if (require_flag_file && !flushed_flag_is_set())
return 0;
- (void) system_journal_open(s, true);
+ (void) system_journal_open(s, true, false);
if (!s->system_journal)
return 0;
@@ -1056,6 +1057,13 @@ finish:
n),
NULL);
+ if (unlink("/run/systemd/journal/relinquished") < 0 && errno != ENOENT)
+ log_warning_errno(errno, "Failed to unlink /run/systemd/journal/relinquished, ignoring: %m");
+
+ k = touch("/run/systemd/journal/flushed");
+ if (k < 0)
+ log_warning_errno(k, "Failed to touch /run/systemd/journal/flushed, ignoring: %m");
+
return r;
}
@@ -1180,7 +1188,6 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Server *s = userdata;
- int r;
assert(s);
@@ -1190,10 +1197,6 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
server_sync(s);
server_vacuum(s, false);
- r = touch("/run/systemd/journal/flushed");
- if (r < 0)
- log_warning_errno(r, "Failed to touch /run/systemd/journal/flushed, ignoring: %m");
-
server_space_usage_message(s, NULL);
return 0;
}
@@ -1250,12 +1253,43 @@ static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo
return 0;
}
+
+static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
+ Server *s = userdata;
+ int r;
+
+ assert(s);
+
+ if (s->storage == STORAGE_NONE)
+ return 0;
+
+ if (s->runtime_journal && !s->system_journal)
+ return 0;
+
+ log_debug("Received request to relinquish /var from PID " PID_FMT, si->ssi_pid);
+
+ (void) system_journal_open(s, false, true);
+
+ s->system_journal = journal_file_close(s->system_journal);
+ ordered_hashmap_clear_with_destructor(s->user_journals, journal_file_close);
+ set_clear_with_destructor(s->deferred_closes, journal_file_close);
+
+ if (unlink("/run/systemd/journal/flushed") < 0 && errno != ENOENT)
+ log_warning_errno(errno, "Failed to unlink /run/systemd/journal/flushed, ignoring: %m") ;
+
+ r = write_timestamp_file_atomic("/run/systemd/journal/relinquished", now(CLOCK_MONOTONIC));
+ if (r < 0)
+ log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m");
+
+ return 0;
+}
+
static int setup_signals(Server *s) {
int r;
assert(s);
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+2, -1) >= 0);
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
if (r < 0)
@@ -1294,6 +1328,10 @@ static int setup_signals(Server *s) {
if (r < 0)
return r;
+ r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+2, dispatch_sigrtmin2, s);
+ if (r < 0)
+ return r;
+
r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15);
if (r < 0)
return r;
@@ -1876,7 +1914,7 @@ int server_init(Server *s) {
(void) client_context_acquire_default(s);
- return system_journal_open(s, false);
+ return system_journal_open(s, false, false);
}
void server_maybe_append_tags(Server *s) {

View File

@ -0,0 +1,242 @@
From fa93a97bdf18906d9517f4183802456986490c89 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 5 Apr 2019 18:21:02 +0200
Subject: [PATCH] journalctl: add new --relinquish and --smart-relinquish
options
The latter is identical to the former, but becomes a NOP if
/var/log/journal is on the same mount as /, and thus during shutdown
unmounting /var is not necessary and hence we can keep logging until the
very end.
[dtardon: The only divergence from the upstream commit is the impl. of
relinquish_var().]
(cherry picked from commit c0dfcb318c28d87e1176a8ad87ac7cc4ecc50305)
Related: #1873540
---
src/journal/journalctl.c | 161 +++++++++++++++++++++++++--------------
1 file changed, 103 insertions(+), 58 deletions(-)
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 228cfe7e49..6928c79a06 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -47,6 +47,7 @@
#include "log.h"
#include "logs-show.h"
#include "mkdir.h"
+#include "mount-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
@@ -162,6 +163,7 @@ static enum {
ACTION_UPDATE_CATALOG,
ACTION_LIST_BOOTS,
ACTION_FLUSH,
+ ACTION_RELINQUISH_VAR,
ACTION_SYNC,
ACTION_ROTATE,
ACTION_VACUUM,
@@ -358,6 +360,8 @@ static void help(void) {
" --vacuum-time=TIME Remove journal files older than specified time\n"
" --verify Verify journal file consistency\n"
" --sync Synchronize unwritten journal messages to disk\n"
+ " --relinquish-var Stop logging to disk, log to temporary file system\n"
+ " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
" --flush Flush all journal data from /run into /var\n"
" --rotate Request immediate rotation of the journal files\n"
" --header Show journal header information\n"
@@ -402,6 +406,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_UTC,
ARG_SYNC,
ARG_FLUSH,
+ ARG_RELINQUISH_VAR,
+ ARG_SMART_RELINQUISH_VAR,
ARG_ROTATE,
ARG_VACUUM_SIZE,
ARG_VACUUM_FILES,
@@ -411,64 +417,66 @@ static int parse_argv(int argc, char *argv[]) {
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version" , no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "pager-end", no_argument, NULL, 'e' },
- { "follow", no_argument, NULL, 'f' },
- { "force", no_argument, NULL, ARG_FORCE },
- { "output", required_argument, NULL, 'o' },
- { "all", no_argument, NULL, 'a' },
- { "full", no_argument, NULL, 'l' },
- { "no-full", no_argument, NULL, ARG_NO_FULL },
- { "lines", optional_argument, NULL, 'n' },
- { "no-tail", no_argument, NULL, ARG_NO_TAIL },
- { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
- { "quiet", no_argument, NULL, 'q' },
- { "merge", no_argument, NULL, 'm' },
- { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */
- { "boot", optional_argument, NULL, 'b' },
- { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
- { "dmesg", no_argument, NULL, 'k' },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "user", no_argument, NULL, ARG_USER },
- { "directory", required_argument, NULL, 'D' },
- { "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' },
- { "grep", required_argument, NULL, 'g' },
- { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE },
- { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
- { "interval", required_argument, NULL, ARG_INTERVAL },
- { "verify", no_argument, NULL, ARG_VERIFY },
- { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
- { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
- { "cursor", required_argument, NULL, 'c' },
- { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
- { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
- { "since", required_argument, NULL, 'S' },
- { "until", required_argument, NULL, 'U' },
- { "unit", required_argument, NULL, 'u' },
- { "user-unit", required_argument, NULL, ARG_USER_UNIT },
- { "field", required_argument, NULL, 'F' },
- { "fields", no_argument, NULL, 'N' },
- { "catalog", no_argument, NULL, 'x' },
- { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
- { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
- { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
- { "reverse", no_argument, NULL, 'r' },
- { "machine", required_argument, NULL, 'M' },
- { "utc", no_argument, NULL, ARG_UTC },
- { "flush", no_argument, NULL, ARG_FLUSH },
- { "sync", no_argument, NULL, ARG_SYNC },
- { "rotate", no_argument, NULL, ARG_ROTATE },
- { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
- { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
- { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
- { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
- { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
+ { "help", no_argument, NULL, 'h' },
+ { "version" , no_argument, NULL, ARG_VERSION },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "pager-end", no_argument, NULL, 'e' },
+ { "follow", no_argument, NULL, 'f' },
+ { "force", no_argument, NULL, ARG_FORCE },
+ { "output", required_argument, NULL, 'o' },
+ { "all", no_argument, NULL, 'a' },
+ { "full", no_argument, NULL, 'l' },
+ { "no-full", no_argument, NULL, ARG_NO_FULL },
+ { "lines", optional_argument, NULL, 'n' },
+ { "no-tail", no_argument, NULL, ARG_NO_TAIL },
+ { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, /* deprecated */
+ { "quiet", no_argument, NULL, 'q' },
+ { "merge", no_argument, NULL, 'm' },
+ { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */
+ { "boot", optional_argument, NULL, 'b' },
+ { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
+ { "dmesg", no_argument, NULL, 'k' },
+ { "system", no_argument, NULL, ARG_SYSTEM },
+ { "user", no_argument, NULL, ARG_USER },
+ { "directory", required_argument, NULL, 'D' },
+ { "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' },
+ { "grep", required_argument, NULL, 'g' },
+ { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE },
+ { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
+ { "interval", required_argument, NULL, ARG_INTERVAL },
+ { "verify", no_argument, NULL, ARG_VERIFY },
+ { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
+ { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
+ { "cursor", required_argument, NULL, 'c' },
+ { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
+ { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
+ { "since", required_argument, NULL, 'S' },
+ { "until", required_argument, NULL, 'U' },
+ { "unit", required_argument, NULL, 'u' },
+ { "user-unit", required_argument, NULL, ARG_USER_UNIT },
+ { "field", required_argument, NULL, 'F' },
+ { "fields", no_argument, NULL, 'N' },
+ { "catalog", no_argument, NULL, 'x' },
+ { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
+ { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
+ { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
+ { "reverse", no_argument, NULL, 'r' },
+ { "machine", required_argument, NULL, 'M' },
+ { "utc", no_argument, NULL, ARG_UTC },
+ { "flush", no_argument, NULL, ARG_FLUSH },
+ { "relinquish-var", no_argument, NULL, ARG_RELINQUISH_VAR },
+ { "smart-relinquish-var", no_argument, NULL, ARG_SMART_RELINQUISH_VAR },
+ { "sync", no_argument, NULL, ARG_SYNC },
+ { "rotate", no_argument, NULL, ARG_ROTATE },
+ { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
+ { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
+ { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
+ { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
+ { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
{}
};
@@ -893,6 +901,35 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_FLUSH;
break;
+ case ARG_SMART_RELINQUISH_VAR: {
+ int root_mnt_id, log_mnt_id;
+
+ /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
+ * if it's on the same mount as the root file system there's no point in
+ * relinquishing access and we can leave journald write to it until the very last
+ * moment. */
+
+ r = path_get_mnt_id("/", &root_mnt_id);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get root mount ID, ignoring: %m");
+ else {
+ r = path_get_mnt_id("/var/log/journal/", &log_mnt_id);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get journal directory mount ID, ignoring: %m");
+ else if (root_mnt_id == log_mnt_id) {
+ log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
+ return 0;
+ } else
+ log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
+ }
+
+ _fallthrough_;
+ }
+
+ case ARG_RELINQUISH_VAR:
+ arg_action = ACTION_RELINQUISH_VAR;
+ break;
+
case ARG_ROTATE:
arg_action = ACTION_ROTATE;
break;
@@ -2056,6 +2093,10 @@ static int send_signal_and_wait(int sig, const char *watch_path) {
return 0;
}
+static int relinquish_var(void) {
+ return send_signal_and_wait(SIGRTMIN+2, "/run/systemd/journal/relinquished");
+}
+
static int rotate(void) {
return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated");
}
@@ -2171,6 +2212,10 @@ int main(int argc, char *argv[]) {
r = flush_to_var();
goto finish;
+ case ACTION_RELINQUISH_VAR:
+ r = relinquish_var();
+ goto finish;
+
case ACTION_SYNC:
r = sync_journal();
goto finish;

View File

@ -0,0 +1,26 @@
From ce6531045b337c3f793d1d74f1e5641e658805bb Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 5 Apr 2019 18:22:31 +0200
Subject: [PATCH] units: automatically revert to /run logging on shutdown if
necessary
Fixes: #867
(cherry picked from commit 1e187d2dd52cbb4f0bb30e4d96acf7f72a145b91)
Resolves: #1873540
---
units/systemd-journal-flush.service.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/units/systemd-journal-flush.service.in b/units/systemd-journal-flush.service.in
index 439f5f3f76..653dcebe0e 100644
--- a/units/systemd-journal-flush.service.in
+++ b/units/systemd-journal-flush.service.in
@@ -19,6 +19,7 @@ RequiresMountsFor=/var/log/journal
[Service]
ExecStart=@rootbindir@/journalctl --flush
+ExecStop=@rootbindir@/journalctl --smart-relinquish-var
Type=oneshot
RemainAfterExit=yes
TimeoutSec=90s

View File

@ -0,0 +1,929 @@
From 2f75df5cd6dcd56775fec9e89fc79672e702d826 Mon Sep 17 00:00:00 2001
From: Eric DeVolder <eric.devolder@oracle.com>
Date: Thu, 16 May 2019 08:59:01 -0500
Subject: [PATCH] pstore: Tool to archive contents of pstore
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch introduces the systemd pstore service which will archive the
contents of the Linux persistent storage filesystem, pstore, to other storage,
thus preserving the existing information contained in the pstore, and clearing
pstore storage for future error events.
Linux provides a persistent storage file system, pstore[1], that can store
error records when the kernel dies (or reboots or powers-off). These records in
turn can be referenced to debug kernel problems (currently the kernel stuffs
the tail of the dmesg, which also contains a stack backtrace, into pstore).
The pstore file system supports a variety of backends that map onto persistent
storage, such as the ACPI ERST[2, Section 18.5 Error Serialization] and UEFI
variables[3 Appendix N Common Platform Error Record]. The pstore backends
typically offer a relatively small amount of persistent storage, e.g. 64KiB,
which can quickly fill up and thus prevent subsequent kernel crashes from
recording errors. Thus there is a need to monitor and extract the pstore
contents so that future kernel problems can also record information in the
pstore.
The pstore service is independent of the kdump service. In cloud environments
specifically, host and guest filesystems are on remote filesystems (eg. iSCSI
or NFS), thus kdump relies [implicitly and/or explicitly] upon proper operation
of networking software *and* hardware *and* infrastructure. Thus it may not be
possible to capture a kernel coredump to a file since writes over the network
may not be possible.
The pstore backend, on the other hand, is completely local and provides a path
to store error records which will survive a reboot and aid in post-mortem
debugging.
Usage Notes:
This tool moves files from /sys/fs/pstore into /var/lib/systemd/pstore.
To enable kernel recording of error records into pstore, one must either pass
crash_kexec_post_notifiers[4] to the kernel command line or enable via 'echo Y
> /sys/module/kernel/parameters/crash_kexec_post_notifiers'. This option
invokes the recording of errors into pstore *before* an attempt to kexec/kdump
on a kernel crash.
Optionally, to record reboots and shutdowns in the pstore, one can either pass
the printk.always_kmsg_dump[4] to the kernel command line or enable via 'echo Y >
/sys/module/printk/parameters/always_kmsg_dump'. This option enables code on the
shutdown path to record information via pstore.
This pstore service is a oneshot service. When run, the service invokes
systemd-pstore which is a tool that performs the following:
- reads the pstore.conf configuration file
- collects the lists of files in the pstore (eg. /sys/fs/pstore)
- for certain file types (eg. dmesg) a handler is invoked
- for all other files, the file is moved from pstore
- In the case of dmesg handler, final processing occurs as such:
- files processed in reverse lexigraphical order to faciliate
reconstruction of original dmesg
- the filename is examined to determine which dmesg it is a part
- the file is appended to the reconstructed dmesg
For example, the following pstore contents:
root@vm356:~# ls -al /sys/fs/pstore
total 0
drwxr-x--- 2 root root 0 May 9 09:50 .
drwxr-xr-x 7 root root 0 May 9 09:50 ..
-r--r--r-- 1 root root 1610 May 9 09:49 dmesg-efi-155741337601001
-r--r--r-- 1 root root 1778 May 9 09:49 dmesg-efi-155741337602001
-r--r--r-- 1 root root 1726 May 9 09:49 dmesg-efi-155741337603001
-r--r--r-- 1 root root 1746 May 9 09:49 dmesg-efi-155741337604001
-r--r--r-- 1 root root 1686 May 9 09:49 dmesg-efi-155741337605001
-r--r--r-- 1 root root 1690 May 9 09:49 dmesg-efi-155741337606001
-r--r--r-- 1 root root 1775 May 9 09:49 dmesg-efi-155741337607001
-r--r--r-- 1 root root 1811 May 9 09:49 dmesg-efi-155741337608001
-r--r--r-- 1 root root 1817 May 9 09:49 dmesg-efi-155741337609001
-r--r--r-- 1 root root 1795 May 9 09:49 dmesg-efi-155741337710001
-r--r--r-- 1 root root 1770 May 9 09:49 dmesg-efi-155741337711001
-r--r--r-- 1 root root 1796 May 9 09:49 dmesg-efi-155741337712001
-r--r--r-- 1 root root 1787 May 9 09:49 dmesg-efi-155741337713001
-r--r--r-- 1 root root 1808 May 9 09:49 dmesg-efi-155741337714001
-r--r--r-- 1 root root 1754 May 9 09:49 dmesg-efi-155741337715001
results in the following:
root@vm356:~# ls -al /var/lib/systemd/pstore/155741337/
total 92
drwxr-xr-x 2 root root 4096 May 9 09:50 .
drwxr-xr-x 4 root root 40 May 9 09:50 ..
-rw-r--r-- 1 root root 1610 May 9 09:50 dmesg-efi-155741337601001
-rw-r--r-- 1 root root 1778 May 9 09:50 dmesg-efi-155741337602001
-rw-r--r-- 1 root root 1726 May 9 09:50 dmesg-efi-155741337603001
-rw-r--r-- 1 root root 1746 May 9 09:50 dmesg-efi-155741337604001
-rw-r--r-- 1 root root 1686 May 9 09:50 dmesg-efi-155741337605001
-rw-r--r-- 1 root root 1690 May 9 09:50 dmesg-efi-155741337606001
-rw-r--r-- 1 root root 1775 May 9 09:50 dmesg-efi-155741337607001
-rw-r--r-- 1 root root 1811 May 9 09:50 dmesg-efi-155741337608001
-rw-r--r-- 1 root root 1817 May 9 09:50 dmesg-efi-155741337609001
-rw-r--r-- 1 root root 1795 May 9 09:50 dmesg-efi-155741337710001
-rw-r--r-- 1 root root 1770 May 9 09:50 dmesg-efi-155741337711001
-rw-r--r-- 1 root root 1796 May 9 09:50 dmesg-efi-155741337712001
-rw-r--r-- 1 root root 1787 May 9 09:50 dmesg-efi-155741337713001
-rw-r--r-- 1 root root 1808 May 9 09:50 dmesg-efi-155741337714001
-rw-r--r-- 1 root root 1754 May 9 09:50 dmesg-efi-155741337715001
-rw-r--r-- 1 root root 26754 May 9 09:50 dmesg.txt
where dmesg.txt is reconstructed from the group of related
dmesg-efi-155741337* files.
Configuration file:
The pstore.conf configuration file has four settings, described below.
- Storage : one of "none", "external", or "journal". With "none", this
tool leaves the contents of pstore untouched. With "external", the
contents of the pstore are moved into the /var/lib/systemd/pstore,
as well as logged into the journal. With "journal", the contents of
the pstore are recorded only in the systemd journal. The default is
"external".
- Unlink : is a boolean. When "true", the default, then files in the
pstore are removed once processed. When "false", processing of the
pstore occurs normally, but the pstore files remain.
References:
[1] "Persistent storage for a kernel's dying breath",
March 23, 2011.
https://lwn.net/Articles/434821/
[2] "Advanced Configuration and Power Interface Specification",
version 6.2, May 2017.
https://www.uefi.org/sites/default/files/resources/ACPI_6_2.pdf
[3] "Unified Extensible Firmware Interface Specification",
version 2.8, March 2019.
https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf
[4] "The kernels command-line parameters",
https://static.lwn.net/kerneldoc/admin-guide/kernel-parameters.html
(cherry picked from commit 9b4abc69b201e5d7295e1b0762883659f053e747)
Resolves: #2158832
---
man/pstore.conf.xml | 89 +++++++
man/rules/meson.build | 2 +
man/systemd-pstore.xml | 99 ++++++++
meson.build | 20 ++
meson_options.txt | 2 +
src/pstore/meson.build | 10 +
src/pstore/pstore.c | 395 ++++++++++++++++++++++++++++++++
src/pstore/pstore.conf | 16 ++
units/meson.build | 1 +
units/systemd-pstore.service.in | 24 ++
10 files changed, 658 insertions(+)
create mode 100644 man/pstore.conf.xml
create mode 100644 man/systemd-pstore.xml
create mode 100644 src/pstore/meson.build
create mode 100644 src/pstore/pstore.c
create mode 100644 src/pstore/pstore.conf
create mode 100644 units/systemd-pstore.service.in
diff --git a/man/pstore.conf.xml b/man/pstore.conf.xml
new file mode 100644
index 0000000000..b5cda47d02
--- /dev/null
+++ b/man/pstore.conf.xml
@@ -0,0 +1,89 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="pstore.conf" conditional="ENABLE_PSTORE"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>pstore.conf</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>pstore.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>pstore.conf</refname>
+ <refname>pstore.conf.d</refname>
+ <refpurpose>PStore configuration file</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/etc/systemd/pstore.conf</filename>
+ <filename>/etc/systemd/pstore.conf.d/*</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>This file configures the behavior of
+ <citerefentry><refentrytitle>systemd-pstore</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ a tool for archiving the contents of the persistent storage filesystem,
+ <ulink url="https://www.kernel.org/doc/Documentation/ABI/testing/pstore">pstore</ulink>.
+ </para>
+ </refsect1>
+
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>All options are configured in the
+ <literal>[PStore]</literal> section:</para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><varname>Storage=</varname></term>
+
+ <listitem><para>Controls where to archive (i.e. copy) files from the pstore filesystem. One of <literal>none</literal>,
+ <literal>external</literal>, and <literal>journal</literal>. When
+ <literal>none</literal>, the tool exits without processing files in the pstore filesystem.
+ When <literal>external</literal> (the default), files are archived into <filename>/var/lib/systemd/pstore/</filename>,
+ and logged into the journal.
+ When <literal>journal</literal>, pstore file contents are logged only in the journal.</para>
+ </listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>Unlink=</varname></term>
+
+ <listitem><para>Controls whether or not files are removed from pstore after processing.
+ Takes a boolean value. When true, a pstore file is removed from the pstore once it has been
+ archived (either to disk or into the journal). When false, processing of pstore files occurs
+ normally, but the files remain in the pstore.
+ The default is true in order to maintain the pstore in a nearly empty state, so that the pstore
+ has storage available for the next kernel error event.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>The defaults for all values are listed as comments in the
+ template <filename>/etc/systemd/pstore.conf</filename> file that
+ is installed by default.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/rules/meson.build b/man/rules/meson.build
index e6c0a99bbd..6295330c5e 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -44,6 +44,7 @@ manpages = [
['os-release', '5', [], ''],
['pam_systemd', '8', [], 'HAVE_PAM'],
['portablectl', '1', [], 'ENABLE_PORTABLED'],
+ ['pstore.conf', '5', ['pstore.conf.d'], 'ENABLE_PSTORE'],
['resolvectl', '1', ['resolvconf'], 'ENABLE_RESOLVE'],
['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'],
['runlevel', '8', [], 'ENABLE_UTMP'],
@@ -633,6 +634,7 @@ manpages = [
['systemd-nspawn', '1', [], ''],
['systemd-path', '1', [], ''],
['systemd-portabled.service', '8', ['systemd-portabled'], 'ENABLE_PORTABLED'],
+ ['systemd-pstore', '8', ['systemd-pstore.service'], 'ENABLE_PSTORE'],
['systemd-quotacheck.service',
'8',
['systemd-quotacheck'],
diff --git a/man/systemd-pstore.xml b/man/systemd-pstore.xml
new file mode 100644
index 0000000000..dd1aa5e83b
--- /dev/null
+++ b/man/systemd-pstore.xml
@@ -0,0 +1,99 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="systemd-pstore" conditional='ENABLE_PSTORE'
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>systemd-pstore</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd-pstore</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd-pstore</refname>
+ <refname>systemd-pstore.service</refname>
+ <refpurpose>Tool to archive contents of the persistent storage filesytem</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>/usr/lib/systemd/systemd-pstore</filename></para>
+ <para><filename>systemd-pstore.service</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para><filename>systemd-pstore.service</filename> is a system service that archives the
+ contents of the Linux persistent storage filesystem, pstore, to other storage,
+ thus preserving the existing information contained in the pstore, and clearing
+ pstore storage for future error events.</para>
+
+ <para>Linux provides a persistent storage file system, pstore, that can store
+ error records when the kernel dies (or reboots or powers-off). These records in
+ turn can be referenced to debug kernel problems (currently the kernel stuffs
+ the tail of the dmesg, which also contains a stack backtrace, into pstore).</para>
+
+ <para>The pstore file system supports a variety of backends that map onto persistent
+ storage, such as the ACPI ERST and UEFI variables. The pstore backends
+ typically offer a relatively small amount of persistent storage, e.g. 64KiB,
+ which can quickly fill up and thus prevent subsequent kernel crashes from
+ recording errors. Thus there is a need to monitor and extract the pstore
+ contents so that future kernel problems can also record information in the
+ pstore.</para>
+
+ <para>The pstore service is independent of the kdump service. In cloud environments
+ specifically, host and guest filesystems are on remote filesystems (eg. iSCSI
+ or NFS), thus kdump relies [implicitly and/or explicitly] upon proper operation
+ of networking software *and* hardware *and* infrastructure. Thus it may not be
+ possible to capture a kernel coredump to a file since writes over the network
+ may not be possible.</para>
+
+ <para>The pstore backend, on the other hand, is completely local and provides a path
+ to store error records which will survive a reboot and aid in post-mortem
+ debugging.</para>
+
+ <para>The <command>systemd-pstore</command> executable does the actual work. Upon starting,
+ the <filename>pstore.conf</filename> is read to obtain options, then the /sys/fs/pstore
+ directory contents are processed according to the options. Pstore files are written to the
+ journal, and optionally saved into /var/lib/systemd/pstore.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Configuration</title>
+
+ <para>The behavior of <command>systemd-pstore</command> is configured through the configuration file
+ <filename>/etc/systemd/pstore.conf</filename> and corresponding snippets
+ <filename>/etc/systemd/pstore.conf.d/*.conf</filename>, see
+ <citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+
+ <refsect2>
+ <title>Disabling pstore processing</title>
+
+ <para>To disable pstore processing by <command>systemd-pstore</command>,
+ set <programlisting>Storage=none</programlisting> in
+ <citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>Usage</title>
+ <para>Data stored in the journal can be viewed with
+ <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ as usual.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/meson.build b/meson.build
index af4cf331da..972a8fb6f7 100644
--- a/meson.build
+++ b/meson.build
@@ -1224,6 +1224,7 @@ foreach term : ['utmp',
'environment-d',
'binfmt',
'coredump',
+ 'pstore',
'resolve',
'logind',
'hostnamed',
@@ -1439,6 +1440,7 @@ subdir('src/network')
subdir('src/analyze')
subdir('src/journal-remote')
subdir('src/coredump')
+subdir('src/pstore')
subdir('src/hostname')
subdir('src/import')
subdir('src/kernel-install')
@@ -2151,6 +2153,23 @@ if conf.get('ENABLE_COREDUMP') == 1
public_programs += [exe]
endif
+if conf.get('ENABLE_PSTORE') == 1
+ executable('systemd-pstore',
+ systemd_pstore_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libacl,
+ libdw,
+ libxz,
+ liblz4],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += exe
+endif
+
if conf.get('ENABLE_BINFMT') == 1
exe = executable('systemd-binfmt',
'src/binfmt/binfmt.c',
@@ -3014,6 +3033,7 @@ foreach tuple : [
['resolve'],
['DNS-over-TLS'],
['coredump'],
+ ['pstore'],
['polkit'],
['legacy pkla', install_polkit_pkla],
['efi'],
diff --git a/meson_options.txt b/meson_options.txt
index 213079ac15..5624304bf4 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -76,6 +76,8 @@ option('binfmt', type : 'boolean',
description : 'support for custom binary formats')
option('coredump', type : 'boolean',
description : 'install the coredump handler')
+option('pstore', type : 'boolean',
+ description : 'install the pstore archival tool')
option('logind', type : 'boolean',
description : 'install the systemd-logind stack')
option('hostnamed', type : 'boolean',
diff --git a/src/pstore/meson.build b/src/pstore/meson.build
new file mode 100644
index 0000000000..adbac24b54
--- /dev/null
+++ b/src/pstore/meson.build
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
+systemd_pstore_sources = files('''
+ pstore.c
+'''.split())
+
+if conf.get('ENABLE_PSTORE') == 1
+ install_data('pstore.conf',
+ install_dir : pkgsysconfdir)
+endif
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
new file mode 100644
index 0000000000..f95e016eb6
--- /dev/null
+++ b/src/pstore/pstore.c
@@ -0,0 +1,395 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+/* Copyright © 2019 Oracle and/or its affiliates. */
+
+/* Generally speaking, the pstore contains a small number of files
+ * that in turn contain a small amount of data. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <sys/prctl.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include "sd-daemon.h"
+#include "sd-journal.h"
+#include "sd-login.h"
+#include "sd-messages.h"
+
+#include "acl-util.h"
+#include "alloc-util.h"
+#include "capability-util.h"
+#include "cgroup-util.h"
+#include "compress.h"
+#include "conf-parser.h"
+#include "copy.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "journal-importer.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "socket-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+
+/* Command line argument handling */
+typedef enum PStoreStorage {
+ PSTORE_STORAGE_NONE,
+ PSTORE_STORAGE_EXTERNAL,
+ PSTORE_STORAGE_JOURNAL,
+ _PSTORE_STORAGE_MAX,
+ _PSTORE_STORAGE_INVALID = -1
+} PStoreStorage;
+
+static const char* const pstore_storage_table[_PSTORE_STORAGE_MAX] = {
+ [PSTORE_STORAGE_NONE] = "none",
+ [PSTORE_STORAGE_EXTERNAL] = "external",
+ [PSTORE_STORAGE_JOURNAL] = "journal",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(pstore_storage, PStoreStorage);
+static DEFINE_CONFIG_PARSE_ENUM(config_parse_pstore_storage, pstore_storage, PStoreStorage, "Failed to parse storage setting");
+
+static PStoreStorage arg_storage = PSTORE_STORAGE_EXTERNAL;
+
+static bool arg_unlink = true;
+static const char *arg_sourcedir = "/sys/fs/pstore";
+static const char *arg_archivedir = "/var/lib/systemd/pstore";
+
+static int parse_config(void) {
+ static const ConfigTableItem items[] = {
+ { "PStore", "Unlink", config_parse_bool, 0, &arg_unlink },
+ { "PStore", "Storage", config_parse_pstore_storage, 0, &arg_storage },
+ {}
+ };
+
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/pstore.conf",
+ CONF_PATHS_NULSTR("systemd/pstore.conf.d"),
+ "PStore\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN, NULL);
+}
+
+/* File list handling - PStoreEntry is the struct and
+ * and PStoreEntry is the type that contains all info
+ * about a pstore entry. */
+typedef struct PStoreEntry {
+ struct dirent dirent;
+ bool is_binary;
+ bool handled;
+ char *content;
+ size_t content_size;
+} PStoreEntry;
+
+typedef struct PStoreList {
+ PStoreEntry *entries;
+ size_t n_entries;
+ size_t n_entries_allocated;
+} PStoreList;
+
+static void pstore_entries_reset(PStoreList *list) {
+ for (size_t i = 0; i < list->n_entries; i++)
+ free(list->entries[i].content);
+ free(list->entries);
+ list->n_entries = 0;
+}
+
+static int compare_pstore_entries(const void *_a, const void *_b) {
+ PStoreEntry *a = (PStoreEntry *)_a, *b = (PStoreEntry *)_b;
+ return strcmp(a->dirent.d_name, b->dirent.d_name);
+}
+
+static int move_file(PStoreEntry *pe, const char *subdir) {
+ _cleanup_free_ char *ifd_path = NULL;
+ _cleanup_free_ char *ofd_path = NULL;
+ int r = 0;
+ struct iovec iovec[2] = {};
+ int n_iovec = 0;
+ _cleanup_free_ void *field = NULL;
+ const char *suffix = NULL;
+ size_t field_size;
+
+ if (pe->handled)
+ return 0;
+
+ ifd_path = path_join(NULL, arg_sourcedir, pe->dirent.d_name);
+ if (!ifd_path)
+ return log_oom();
+
+ ofd_path = path_join(arg_archivedir, subdir, pe->dirent.d_name);
+ if (!ofd_path)
+ return log_oom();
+
+ /* Always log to the journal */
+ suffix = arg_storage == PSTORE_STORAGE_EXTERNAL ? strjoina(" moved to ", ofd_path) : (char *)".";
+ field = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(field);
+
+ field_size = strlen("FILE=") + pe->content_size;
+ field = malloc(field_size);
+ if (!field)
+ return log_oom();
+ memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size);
+ iovec[n_iovec++] = IOVEC_MAKE(field, field_size);
+
+ r = sd_journal_sendv(iovec, n_iovec);
+ if (r < 0)
+ return log_error_errno(r, "Failed to log pstore entry: %m");
+
+ if (arg_storage == PSTORE_STORAGE_EXTERNAL) {
+ /* Move file from pstore to external storage */
+ r = mkdir_parents(ofd_path, 0755);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create directoy %s: %m", ofd_path);
+ r = copy_file_atomic(ifd_path, ofd_path, 0600, 0, COPY_REPLACE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to copy_file_atomic: %s to %s", ifd_path, ofd_path);
+ }
+
+ /* If file copied properly, remove it from pstore */
+ if (arg_unlink)
+ (void) unlink(ifd_path);
+
+ pe->handled = true;
+
+ return 0;
+}
+
+static int write_dmesg(const char *dmesg, size_t size, const char *id) {
+ _cleanup_(unlink_and_freep) char *ofd_path = NULL;
+ _cleanup_free_ char *tmp_path = NULL;
+ _cleanup_close_ int ofd = -1;
+ ssize_t wr;
+ int r;
+
+ if (isempty(dmesg) || size == 0)
+ return 0;
+
+ /* log_info("Record ID %s", id); */
+
+ ofd_path = path_join(arg_archivedir, id, "dmesg.txt");
+ if (!ofd_path)
+ return log_oom();
+
+ ofd = open_tmpfile_linkable(ofd_path, O_CLOEXEC|O_CREAT|O_TRUNC|O_WRONLY, &tmp_path);
+ if (ofd < 0)
+ return log_error_errno(ofd, "Failed to open temporary file %s: %m", ofd_path);
+ wr = write(ofd, dmesg, size);
+ if (wr < 0)
+ return log_error_errno(errno, "Failed to store dmesg to %s: %m", ofd_path);
+ if (wr != (ssize_t)size)
+ return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, size - wr);
+ r = link_tmpfile(ofd, tmp_path, ofd_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path);
+ ofd_path = mfree(ofd_path);
+
+ return 0;
+}
+
+static void process_dmesg_files(PStoreList *list) {
+ /* Move files, reconstruct dmesg.txt */
+ PStoreEntry *pe;
+ _cleanup_free_ char *dmesg = NULL;
+ size_t dmesg_size = 0;
+ _cleanup_free_ char *dmesg_id = NULL;
+
+ /* Handle each dmesg file: files processed in reverse
+ * order so as to properly reconstruct original dmesg */
+ for (size_t n = list->n_entries; n > 0; n--) {
+ bool move_file_and_continue = false;
+ _cleanup_free_ char *pe_id = NULL;
+ char *p;
+ size_t plen;
+
+ pe = &list->entries[n-1];
+
+ if (pe->handled)
+ continue;
+ if (!startswith(pe->dirent.d_name, "dmesg-"))
+ continue;
+
+ if (endswith(pe->dirent.d_name, ".enc.z")) /* indicates a problem */
+ move_file_and_continue = true;
+ p = strrchr(pe->dirent.d_name, '-');
+ if (!p)
+ move_file_and_continue = true;
+
+ if (move_file_and_continue) {
+ /* A dmesg file on which we do NO additional processing */
+ (void) move_file(pe, NULL);
+ continue;
+ }
+
+ /* See if this file is one of a related group of files
+ * in order to reconstruct dmesg */
+
+ /* When dmesg is written into pstore, it is done so in
+ * small chunks, whatever the exchange buffer size is
+ * with the underlying pstore backend (ie. EFI may be
+ * ~2KiB), which means an example pstore with approximately
+ * 64KB of storage may have up to roughly 32 dmesg files
+ * that could be related, depending upon the size of the
+ * original dmesg.
+ *
+ * Here we look at the dmesg filename and try to discern
+ * if files are part of a related group, meaning the same
+ * original dmesg.
+ *
+ * The two known pstore backends are EFI and ERST. These
+ * backends store data in the Common Platform Error
+ * Record, CPER, format. The dmesg- filename contains the
+ * CPER record id, a 64bit number (in decimal notation).
+ * In Linux, the record id is encoded with two digits for
+ * the dmesg part (chunk) number and 3 digits for the
+ * count number. So allowing an additional digit to
+ * compensate for advancing time, this code ignores the
+ * last six digits of the filename in determining the
+ * record id.
+ *
+ * For the EFI backend, the record id encodes an id in the
+ * upper 32 bits, and a timestamp in the lower 32-bits.
+ * So ignoring the least significant 6 digits has proven
+ * to generally identify related dmesg entries. */
+#define PSTORE_FILENAME_IGNORE 6
+
+ /* determine common portion of record id */
+ ++p; /* move beyond dmesg- */
+ plen = strlen(p);
+ if (plen > PSTORE_FILENAME_IGNORE) {
+ pe_id = memdup_suffix0(p, plen - PSTORE_FILENAME_IGNORE);
+ if (!pe_id) {
+ log_oom();
+ return;
+ }
+ } else
+ pe_id = mfree(pe_id);
+
+ /* Now move file from pstore to archive storage */
+ move_file(pe, pe_id);
+
+ /* If the current record id is NOT the same as the
+ * previous record id, then start a new dmesg.txt file */
+ if (!pe_id || !dmesg_id || !streq(pe_id, dmesg_id)) {
+ /* Encountered a new dmesg group, close out old one, open new one */
+ if (dmesg) {
+ (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+ dmesg = mfree(dmesg);
+ dmesg_size = 0;
+ }
+
+ /* now point dmesg_id to storage of pe_id */
+ free_and_replace(dmesg_id, pe_id);
+ }
+
+ /* Reconstruction of dmesg is done as a useful courtesy, do not log errors */
+ dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1);
+ if (dmesg) {
+ dmesg_size += sprintf(&dmesg[dmesg_size], "%s:\n", pe->dirent.d_name);
+ if (pe->content) {
+ memcpy(&dmesg[dmesg_size], pe->content, pe->content_size);
+ dmesg_size += pe->content_size;
+ }
+ }
+
+ pe_id = mfree(pe_id);
+ }
+ if (dmesg)
+ (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+}
+
+static int list_files(PStoreList *list, const char *sourcepath) {
+ _cleanup_(closedirp) DIR *dirp = NULL;
+ struct dirent *de;
+ int r = 0;
+
+ dirp = opendir(sourcepath);
+ if (!dirp)
+ return log_error_errno(errno, "Failed to opendir %s: %m", sourcepath);
+
+ FOREACH_DIRENT(de, dirp, return log_error_errno(errno, "Failed to iterate through %s: %m", sourcepath)) {
+ _cleanup_free_ char *ifd_path = NULL;
+
+ ifd_path = path_join(NULL, sourcepath, de->d_name);
+ if (!ifd_path)
+ return log_oom();
+
+ _cleanup_free_ char *buf = NULL;
+ size_t buf_size;
+
+ /* Now read contents of pstore file */
+ r = read_full_file(ifd_path, &buf, &buf_size);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to read file %s: %m", ifd_path);
+ continue;
+ }
+
+ if (!GREEDY_REALLOC(list->entries, list->n_entries_allocated, list->n_entries + 1))
+ return log_oom();
+
+ list->entries[list->n_entries++] = (PStoreEntry) {
+ .dirent = *de,
+ .content = TAKE_PTR(buf),
+ .content_size = buf_size,
+ .is_binary = true,
+ .handled = false,
+ };
+ }
+
+ return r;
+}
+
+static int run(int argc, char *argv[]) {
+ _cleanup_(pstore_entries_reset) PStoreList list = {};
+ int r;
+
+ log_open();
+
+ /* Ignore all parse errors */
+ (void) parse_config();
+
+ log_debug("Selected storage '%s'.", pstore_storage_to_string(arg_storage));
+ log_debug("Selected Unlink '%d'.", arg_unlink);
+
+ if (arg_storage == PSTORE_STORAGE_NONE)
+ /* Do nothing, intentionally, leaving pstore untouched */
+ return 0;
+
+ /* Obtain list of files in pstore */
+ r = list_files(&list, arg_sourcedir);
+ if (r < 0)
+ return r;
+
+ /* Handle each pstore file */
+ /* Sort files lexigraphically ascending, generally needed by all */
+ qsort_safe(list.entries, list.n_entries, sizeof(PStoreEntry), compare_pstore_entries);
+
+ /* Process known file types */
+ process_dmesg_files(&list);
+
+ /* Move left over files out of pstore */
+ for (size_t n = 0; n < list.n_entries; n++)
+ move_file(&list.entries[n], NULL);
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ r = run(argc, argv);
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/pstore/pstore.conf b/src/pstore/pstore.conf
new file mode 100644
index 0000000000..93a8b6707c
--- /dev/null
+++ b/src/pstore/pstore.conf
@@ -0,0 +1,16 @@
+# 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.
+#
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
+#
+# See pstore.conf(5) for details.
+
+[PStore]
+#Storage=external
+#Unlink=yes
diff --git a/units/meson.build b/units/meson.build
index a74fa95195..e8e64eb30a 100644
--- a/units/meson.build
+++ b/units/meson.build
@@ -136,6 +136,7 @@ in_units = [
['systemd-binfmt.service', 'ENABLE_BINFMT',
'sysinit.target.wants/'],
['systemd-coredump@.service', 'ENABLE_COREDUMP'],
+ ['systemd-pstore.service', 'ENABLE_PSTORE'],
['systemd-firstboot.service', 'ENABLE_FIRSTBOOT',
'sysinit.target.wants/'],
['systemd-fsck-root.service', ''],
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
new file mode 100644
index 0000000000..fec2b1aebf
--- /dev/null
+++ b/units/systemd-pstore.service.in
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# 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=Platform Persistent Storage Archival
+Documentation=man:systemd-pstore(8)
+DefaultDependencies=no
+Wants=systemd-remount-fs.service
+After=systemd-remount-fs.service
+
+[Service]
+Type=oneshot
+ExecStart=@rootlibexecdir@/systemd-pstore
+RemainAfterExit=yes
+StateDirectory=systemd/pstore
+
+[Install]
+WantedBy=systemd-remount-fs.service

View File

@ -0,0 +1,27 @@
From c95ba53ab720dfbd7f692e0a87d7f5d4f89ea36b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 10:46:53 +0900
Subject: [PATCH] meson: drop redundant line
Found by @mattiasb.
(cherry picked from commit 3f708e7f6909faad307bdb60ed0f8d68e84f6584)
Related: #2158832
---
meson.build | 2 --
1 file changed, 2 deletions(-)
diff --git a/meson.build b/meson.build
index 972a8fb6f7..673800a1a7 100644
--- a/meson.build
+++ b/meson.build
@@ -2166,8 +2166,6 @@ if conf.get('ENABLE_PSTORE') == 1
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
-
- public_programs += exe
endif
if conf.get('ENABLE_BINFMT') == 1

View File

@ -0,0 +1,48 @@
From 7e4b7cc35af0e3b3afbf32fa0fd9961cd01ad9a9 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 10:52:12 +0900
Subject: [PATCH] pstore: drop unnecessary initializations
(cherry picked from commit 2e4effd129343d22bfed34e94810d3f87c8f0e85)
Related: #2158832
---
src/pstore/pstore.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index f95e016eb6..e6a342fc50 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -113,14 +113,12 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
}
static int move_file(PStoreEntry *pe, const char *subdir) {
- _cleanup_free_ char *ifd_path = NULL;
- _cleanup_free_ char *ofd_path = NULL;
- int r = 0;
- struct iovec iovec[2] = {};
- int n_iovec = 0;
+ _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
_cleanup_free_ void *field = NULL;
- const char *suffix = NULL;
+ struct iovec iovec[2];
+ const char *suffix;
size_t field_size;
+ int n_iovec = 0, r;
if (pe->handled)
return 0;
@@ -202,10 +200,9 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
static void process_dmesg_files(PStoreList *list) {
/* Move files, reconstruct dmesg.txt */
- PStoreEntry *pe;
- _cleanup_free_ char *dmesg = NULL;
+ _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL;
size_t dmesg_size = 0;
- _cleanup_free_ char *dmesg_id = NULL;
+ PStoreEntry *pe;
/* Handle each dmesg file: files processed in reverse
* order so as to properly reconstruct original dmesg */

View File

@ -0,0 +1,46 @@
From a0485b96118d3d2ac439f510e404ffb3db03e23f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 10:55:10 +0900
Subject: [PATCH] pstopre: fix return value of list_files()
Previously, the return value of the last read_full_file() is returned.
This makes the error in read_full_file() is always ignored.
(cherry picked from commit 337874a45fff46a80e4974c681a5e651f3a0fac9)
Related: #2158832
---
src/pstore/pstore.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index e6a342fc50..2fbef48543 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -311,7 +311,7 @@ static void process_dmesg_files(PStoreList *list) {
static int list_files(PStoreList *list, const char *sourcepath) {
_cleanup_(closedirp) DIR *dirp = NULL;
struct dirent *de;
- int r = 0;
+ int r;
dirp = opendir(sourcepath);
if (!dirp)
@@ -330,7 +330,7 @@ static int list_files(PStoreList *list, const char *sourcepath) {
/* Now read contents of pstore file */
r = read_full_file(ifd_path, &buf, &buf_size);
if (r < 0) {
- log_warning_errno(r, "Failed to read file %s: %m", ifd_path);
+ log_warning_errno(r, "Failed to read file %s, skipping: %m", ifd_path);
continue;
}
@@ -346,7 +346,7 @@ static int list_files(PStoreList *list, const char *sourcepath) {
};
}
- return r;
+ return 0;
}
static int run(int argc, char *argv[]) {

View File

@ -0,0 +1,36 @@
From 58000dc7dd93ff6e8357de64154b0849d3c17c5d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 11:01:43 +0900
Subject: [PATCH] pstore: remove temporary file on failure
(cherry picked from commit 03c5f6cc02648eeff3179b2b762d46b9e1889bb1)
Related: #2158832
---
src/pstore/pstore.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 2fbef48543..ce8080ceed 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -167,8 +167,8 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
}
static int write_dmesg(const char *dmesg, size_t size, const char *id) {
- _cleanup_(unlink_and_freep) char *ofd_path = NULL;
- _cleanup_free_ char *tmp_path = NULL;
+ _cleanup_(unlink_and_freep) char *tmp_path = NULL;
+ _cleanup_free_ char *ofd_path = NULL;
_cleanup_close_ int ofd = -1;
ssize_t wr;
int r;
@@ -193,7 +193,7 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
r = link_tmpfile(ofd, tmp_path, ofd_path);
if (r < 0)
return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path);
- ofd_path = mfree(ofd_path);
+ tmp_path = mfree(tmp_path);
return 0;
}

View File

@ -0,0 +1,57 @@
From 5006e4bd9aecea40ca3d907adc692c4c8001a6c1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 11:08:06 +0900
Subject: [PATCH] pstore: do not add FILE= journal entry if content_size == 0
(cherry picked from commit 6bf18debddbe1b231f783617e054cc194bb36d1e)
Related: #2158832
---
src/pstore/pstore.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index ce8080ceed..eb251d61c8 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -114,10 +114,8 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
static int move_file(PStoreEntry *pe, const char *subdir) {
_cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
- _cleanup_free_ void *field = NULL;
+ const char *suffix, *message;
struct iovec iovec[2];
- const char *suffix;
- size_t field_size;
int n_iovec = 0, r;
if (pe->handled)
@@ -133,15 +131,20 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
/* Always log to the journal */
suffix = arg_storage == PSTORE_STORAGE_EXTERNAL ? strjoina(" moved to ", ofd_path) : (char *)".";
- field = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix);
- iovec[n_iovec++] = IOVEC_MAKE_STRING(field);
+ message = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(message);
- field_size = strlen("FILE=") + pe->content_size;
- field = malloc(field_size);
- if (!field)
- return log_oom();
- memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size);
- iovec[n_iovec++] = IOVEC_MAKE(field, field_size);
+ if (pe->content_size > 0) {
+ _cleanup_free_ void *field = NULL;
+ size_t field_size;
+
+ field_size = strlen("FILE=") + pe->content_size;
+ field = malloc(field_size);
+ if (!field)
+ return log_oom();
+ memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size);
+ iovec[n_iovec++] = IOVEC_MAKE(field, field_size);
+ }
r = sd_journal_sendv(iovec, n_iovec);
if (r < 0)

View File

@ -0,0 +1,24 @@
From a7247899f156761934bcb4b380861b3d3ec5449f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 14:09:12 +0900
Subject: [PATCH] pstore: run only when /sys/fs/pstore is not empty
(cherry picked from commit 6d4f213b1f6afb2901f0d97cec0e28e20809b713)
Related: #2158832
---
units/systemd-pstore.service.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index fec2b1aebf..dde21bc33e 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -10,6 +10,7 @@
[Unit]
Description=Platform Persistent Storage Archival
Documentation=man:systemd-pstore(8)
+ConditionDirectoryNotEmpty=/sys/fs/pstore
DefaultDependencies=no
Wants=systemd-remount-fs.service
After=systemd-remount-fs.service

View File

@ -0,0 +1,34 @@
From 7f5bfbd5485e1cb779d7568cabb5783651fd9da3 Mon Sep 17 00:00:00 2001
From: Michael Olbrich <m.olbrich@pengutronix.de>
Date: Fri, 6 Sep 2019 15:04:01 +0200
Subject: [PATCH] pstore: fix use after free
The memory is still needed in the sd_journal_sendv() after the 'if' block.
(cherry picked from commit 1e19f5ac0d680a63eccae7ef1fc6ce225dca0bbf)
Related: #2158832
---
src/pstore/pstore.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index eb251d61c8..cafb1804c6 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -114,6 +114,7 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
static int move_file(PStoreEntry *pe, const char *subdir) {
_cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
+ _cleanup_free_ void *field = NULL;
const char *suffix, *message;
struct iovec iovec[2];
int n_iovec = 0, r;
@@ -135,7 +136,6 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
iovec[n_iovec++] = IOVEC_MAKE_STRING(message);
if (pe->content_size > 0) {
- _cleanup_free_ void *field = NULL;
size_t field_size;
field_size = strlen("FILE=") + pe->content_size;

View File

@ -0,0 +1,29 @@
From a35a90322f8587f650aeb72bfbe1ebcc93e503aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 22 Jul 2019 10:43:19 +0200
Subject: [PATCH] pstore: refuse to run if arguments are specified
(This is why the --help chech passed.)
(cherry picked from commit 22d6bea8820612e6a1483d8b6cfd820f1417ae6b)
Related: #2158832
---
src/pstore/pstore.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index cafb1804c6..b0b21dedd4 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -358,6 +358,10 @@ static int run(int argc, char *argv[]) {
log_open();
+ if (argc > 1)
+ return log_error_errno(-EINVAL,
+ "This program takes no arguments.");
+
/* Ignore all parse errors */
(void) parse_config();

View File

@ -0,0 +1,44 @@
From 76fe0974f62f0a2beb2d3d8e224e80a57c0ebd09 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 4 Oct 2019 16:14:47 +0200
Subject: [PATCH] pstore: allow specifying src and dst dirs are arguments
This makes it much easier to debug the program as a normal user, since we
don't need to set up fake input under /sys/fs/pstore/.
Also, let's make the debug output a bit nicer.
(cherry picked from commit e05a72d7587ff916a983588f8393af624d330dd0)
Related: #2158832
---
src/pstore/pstore.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index b0b21dedd4..7353e83a81 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -358,15 +358,18 @@ static int run(int argc, char *argv[]) {
log_open();
- if (argc > 1)
+ if (argc == 3) {
+ arg_sourcedir = argv[1];
+ arg_archivedir = argv[2];
+ } else if (argc > 1)
return log_error_errno(-EINVAL,
- "This program takes no arguments.");
+ "This program takes zero or two arguments.");
/* Ignore all parse errors */
(void) parse_config();
- log_debug("Selected storage '%s'.", pstore_storage_to_string(arg_storage));
- log_debug("Selected Unlink '%d'.", arg_unlink);
+ log_debug("Selected storage: %s.", pstore_storage_to_string(arg_storage));
+ log_debug("Selected unlink: %s.", yes_no(arg_unlink));
if (arg_storage == PSTORE_STORAGE_NONE)
/* Do nothing, intentionally, leaving pstore untouched */

View File

@ -0,0 +1,133 @@
From a2ba34a79de3748f51d57541c54dbe22e1d03a9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 4 Oct 2019 16:17:27 +0200
Subject: [PATCH] pstore: rework memory handling for dmesg
Semmle Security Reports report:
> The problem occurs on the way realloc is being used. When a size
> bigger than the chunk that wants to be reallocated is passed, realloc
> try to malloc a bigger size, however in the case that malloc fails
> (for example, by forcing a big allocation) realloc will return NULL.
>
> According to the man page:
> "The realloc() function returns a pointer to the newly allocated
> memory, which is suitably aligned for any built-in type and may be
> different from ptr, or NULL if the request fails. If size was
> equal to 0, either NULL or a pointer suitable to be passed to free()
> is returned. If realloc() fails, the original block is left
> untouched; it is not freed or moved."
>
> The problem occurs when the memory ptr passed to the first argument of
> realloc is the same as the one used for the result, for example in
> this case:
>
> dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) +
> strlen(":\n") + pe->content_size + 1);
>
> https://lgtm.com/projects/g/systemd/systemd/snapshot/f8bcb81955f9e93a4787627e28f43fffb2a84836/files/src/pstore/pstore.c?sort=name&dir=A
> SC&mode=heatmap#L300
>
> If the malloc inside that realloc fails, then the original memory
> chunk will never be free but since realloc will return NULL, the
> pointer to that memory chunk will be lost and a memory leak will
> occur.
>
> In case you are curious, this is the query we used to find this problem:
> https://lgtm.com/query/8650323308193591473/
Let's use a more standard pattern: allocate memory using greedy_realloc, and
instead of freeing it when we wrote out a chunk, let's just move the cursor
back to the beginning and reuse the memory we allocated previously.
If we fail to allocate the memory for dmesg contents, don't write the dmesg
entry, but let's still process the files to move them out of pstore.
(cherry picked from commit 8198c3e42b0614b6bd1db6f38813b842c8577304)
Related: #2158832
---
src/pstore/pstore.c | 43 ++++++++++++++++++++++++++-----------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 7353e83a81..d70e142b4d 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -176,9 +176,11 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
ssize_t wr;
int r;
- if (isempty(dmesg) || size == 0)
+ if (size == 0)
return 0;
+ assert(dmesg);
+
/* log_info("Record ID %s", id); */
ofd_path = path_join(arg_archivedir, id, "dmesg.txt");
@@ -204,7 +206,8 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
static void process_dmesg_files(PStoreList *list) {
/* Move files, reconstruct dmesg.txt */
_cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL;
- size_t dmesg_size = 0;
+ size_t dmesg_size = 0, dmesg_allocated = 0;
+ bool dmesg_bad = false;
PStoreEntry *pe;
/* Handle each dmesg file: files processed in reverse
@@ -281,33 +284,39 @@ static void process_dmesg_files(PStoreList *list) {
/* Now move file from pstore to archive storage */
move_file(pe, pe_id);
+ if (dmesg_bad)
+ continue;
+
/* If the current record id is NOT the same as the
* previous record id, then start a new dmesg.txt file */
- if (!pe_id || !dmesg_id || !streq(pe_id, dmesg_id)) {
+ if (!streq_ptr(pe_id, dmesg_id)) {
/* Encountered a new dmesg group, close out old one, open new one */
- if (dmesg) {
- (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
- dmesg = mfree(dmesg);
- dmesg_size = 0;
- }
+ (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+ dmesg_size = 0;
/* now point dmesg_id to storage of pe_id */
free_and_replace(dmesg_id, pe_id);
}
- /* Reconstruction of dmesg is done as a useful courtesy, do not log errors */
- dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1);
- if (dmesg) {
- dmesg_size += sprintf(&dmesg[dmesg_size], "%s:\n", pe->dirent.d_name);
- if (pe->content) {
- memcpy(&dmesg[dmesg_size], pe->content, pe->content_size);
- dmesg_size += pe->content_size;
- }
+ /* Reconstruction of dmesg is done as a useful courtesy: do not fail, but don't write garbled
+ * output either. */
+ size_t needed = strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1;
+ if (!GREEDY_REALLOC(dmesg, dmesg_allocated, dmesg_size + needed)) {
+ log_warning_errno(ENOMEM, "Failed to write dmesg file: %m");
+ dmesg_bad = true;
+ continue;
+ }
+
+ dmesg_size += sprintf(dmesg + dmesg_size, "%s:\n", pe->dirent.d_name);
+ if (pe->content) {
+ memcpy(dmesg + dmesg_size, pe->content, pe->content_size);
+ dmesg_size += pe->content_size;
}
pe_id = mfree(pe_id);
}
- if (dmesg)
+
+ if (!dmesg_bad)
(void) write_dmesg(dmesg, dmesg_size, dmesg_id);
}

View File

@ -0,0 +1,504 @@
From 5ac15c7dc49476e7cd7cc3a4b507282c9f78d528 Mon Sep 17 00:00:00 2001
From: Eric DeVolder <eric.devolder@oracle.com>
Date: Mon, 21 Nov 2022 11:27:27 -0500
Subject: [PATCH] pstore: fixes for dmesg.txt reconstruction
This patch fixes problems with the re-assembly of the dmesg
from the records stored in pstore.
The current code simply ignores the last 6 characters of the
file name to form a base record id, which then groups any
pstore files with this base id into the reconstructed dmesg.txt.
This approach fails when the following oops generated the
following in pstore:
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286101001
-rw-------. 1 root root 1341 Oct 27 22:07 dmesg-efi-166692286101002
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286102001
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286102002
-rw-------. 1 root root 1807 Oct 27 22:07 dmesg-efi-166692286103001
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286103002
-rw-------. 1 root root 1773 Oct 27 22:07 dmesg-efi-166692286104001
-rw-------. 1 root root 1801 Oct 27 22:07 dmesg-efi-166692286104002
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286105001
-rw-------. 1 root root 1809 Oct 27 22:07 dmesg-efi-166692286105002
-rw-------. 1 root root 1804 Oct 27 22:07 dmesg-efi-166692286106001
-rw-------. 1 root root 1817 Oct 27 22:07 dmesg-efi-166692286106002
-rw-------. 1 root root 1792 Oct 27 22:07 dmesg-efi-166692286107001
-rw-------. 1 root root 1810 Oct 27 22:07 dmesg-efi-166692286107002
-rw-------. 1 root root 1717 Oct 27 22:07 dmesg-efi-166692286108001
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286108002
-rw-------. 1 root root 1764 Oct 27 22:07 dmesg-efi-166692286109001
-rw-------. 1 root root 1765 Oct 27 22:07 dmesg-efi-166692286109002
-rw-------. 1 root root 1796 Oct 27 22:07 dmesg-efi-166692286110001
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286110002
-rw-------. 1 root root 1793 Oct 27 22:07 dmesg-efi-166692286111001
-rw-------. 1 root root 1751 Oct 27 22:07 dmesg-efi-166692286111002
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286112001
-rw-------. 1 root root 1786 Oct 27 22:07 dmesg-efi-166692286112002
-rw-------. 1 root root 1754 Oct 27 22:07 dmesg-efi-166692286113001
-rw-------. 1 root root 1752 Oct 27 22:07 dmesg-efi-166692286113002
-rw-------. 1 root root 1803 Oct 27 22:07 dmesg-efi-166692286114001
-rw-------. 1 root root 1759 Oct 27 22:07 dmesg-efi-166692286114002
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286115001
-rw-------. 1 root root 1787 Oct 27 22:07 dmesg-efi-166692286115002
-rw-------. 1 root root 1815 Oct 27 22:07 dmesg-efi-166692286116001
-rw-------. 1 root root 1771 Oct 27 22:07 dmesg-efi-166692286116002
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286117002
-rw-------. 1 root root 1388 Oct 27 22:07 dmesg-efi-166692286701003
-rw-------. 1 root root 1824 Oct 27 22:07 dmesg-efi-166692286702003
-rw-------. 1 root root 1795 Oct 27 22:07 dmesg-efi-166692286703003
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286704003
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286705003
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286706003
-rw-------. 1 root root 1814 Oct 27 22:07 dmesg-efi-166692286707003
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286708003
-rw-------. 1 root root 1769 Oct 27 22:07 dmesg-efi-166692286709003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286710003
-rw-------. 1 root root 1755 Oct 27 22:07 dmesg-efi-166692286711003
-rw-------. 1 root root 1790 Oct 27 22:07 dmesg-efi-166692286712003
-rw-------. 1 root root 1756 Oct 27 22:07 dmesg-efi-166692286713003
-rw-------. 1 root root 1763 Oct 27 22:07 dmesg-efi-166692286714003
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286715003
-rw-------. 1 root root 1775 Oct 27 22:07 dmesg-efi-166692286716003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286717003
The "reconstructed" dmesg.txt that resulted from the above contained
the following (ignoring actual contents, just providing the Part info):
Emergency#3 Part17
Emergency#3 Part16
Emergency#3 Part15
Emergency#3 Part14
Emergency#3 Part13
Emergency#3 Part12
Emergency#3 Part11
Emergency#3 Part10
Emergency#3 Part9
Emergency#3 Part8
Emergency#3 Part7
Emergency#3 Part6
Emergency#3 Part5
Emergency#3 Part4
Emergency#3 Part3
Emergency#3 Part2
Emergency#3 Part1
Panic#2 Part17
Panic#2 Part16
Oops#1 Part16
Panic#2 Part15
Oops#1 Part15
Panic#2 Part14
Oops#1 Part14
Panic#2 Part13
Oops#1 Part13
Panic#2 Part12
Oops#1 Part12
Panic#2 Part11
Oops#1 Part11
Panic#2 Part10
Oops#1 Part10
Panic#2 Part9
Oops#1 Part9
Panic#2 Part8
Oops#1 Part8
Panic#2 Part7
Oops#1 Part7
Panic#2 Part6
Oops#1 Part6
Panic#2 Part5
Oops#1 Part5
Panic#2 Part4
Oops#1 Part4
Panic#2 Part3
Oops#1 Part3
Panic#2 Part2
Oops#1 Part2
Panic#2 Part1
Oops#1 Part1
The above is a interleaved mess of three dmesg dumps.
This patch fixes the above problems, and simplifies the dmesg
reconstruction process. The code now distinguishes between
records on EFI vs ERST, which have differently formatted
record identifiers. Using knowledge of the format of the
record ids allows vastly improved reconstruction process.
With this change in place, the above pstore records now
result in the following:
# ls -alR /var/lib/systemd/pstore
1666922861:
total 8
drwxr-xr-x. 4 root root 28 Nov 18 14:58 .
drwxr-xr-x. 7 root root 144 Nov 18 14:58 ..
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 001
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 002
1666922861/001:
total 100
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 .
drwxr-xr-x. 4 root root 28 Nov 18 14:58 ..
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286101001
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286102001
-rw-------. 1 root root 1807 Oct 27 22:07 dmesg-efi-166692286103001
-rw-------. 1 root root 1773 Oct 27 22:07 dmesg-efi-166692286104001
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286105001
-rw-------. 1 root root 1804 Oct 27 22:07 dmesg-efi-166692286106001
-rw-------. 1 root root 1792 Oct 27 22:07 dmesg-efi-166692286107001
-rw-------. 1 root root 1717 Oct 27 22:07 dmesg-efi-166692286108001
-rw-------. 1 root root 1764 Oct 27 22:07 dmesg-efi-166692286109001
-rw-------. 1 root root 1796 Oct 27 22:07 dmesg-efi-166692286110001
-rw-------. 1 root root 1793 Oct 27 22:07 dmesg-efi-166692286111001
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286112001
-rw-------. 1 root root 1754 Oct 27 22:07 dmesg-efi-166692286113001
-rw-------. 1 root root 1803 Oct 27 22:07 dmesg-efi-166692286114001
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286115001
-rw-------. 1 root root 1815 Oct 27 22:07 dmesg-efi-166692286116001
-rw-r-----. 1 root root 28677 Nov 18 14:58 dmesg.txt
1666922861/002:
total 104
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 .
drwxr-xr-x. 4 root root 28 Nov 18 14:58 ..
-rw-------. 1 root root 1341 Oct 27 22:07 dmesg-efi-166692286101002
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286102002
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286103002
-rw-------. 1 root root 1801 Oct 27 22:07 dmesg-efi-166692286104002
-rw-------. 1 root root 1809 Oct 27 22:07 dmesg-efi-166692286105002
-rw-------. 1 root root 1817 Oct 27 22:07 dmesg-efi-166692286106002
-rw-------. 1 root root 1810 Oct 27 22:07 dmesg-efi-166692286107002
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286108002
-rw-------. 1 root root 1765 Oct 27 22:07 dmesg-efi-166692286109002
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286110002
-rw-------. 1 root root 1751 Oct 27 22:07 dmesg-efi-166692286111002
-rw-------. 1 root root 1786 Oct 27 22:07 dmesg-efi-166692286112002
-rw-------. 1 root root 1752 Oct 27 22:07 dmesg-efi-166692286113002
-rw-------. 1 root root 1759 Oct 27 22:07 dmesg-efi-166692286114002
-rw-------. 1 root root 1787 Oct 27 22:07 dmesg-efi-166692286115002
-rw-------. 1 root root 1771 Oct 27 22:07 dmesg-efi-166692286116002
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286117002
-rw-r-----. 1 root root 30000 Nov 18 14:58 dmesg.txt
1666922867:
total 4
drwxr-xr-x. 3 root root 17 Nov 18 14:58 .
drwxr-xr-x. 7 root root 144 Nov 18 14:58 ..
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 003
1666922867/003:
total 104
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 .
drwxr-xr-x. 3 root root 17 Nov 18 14:58 ..
-rw-------. 1 root root 1388 Oct 27 22:07 dmesg-efi-166692286701003
-rw-------. 1 root root 1824 Oct 27 22:07 dmesg-efi-166692286702003
-rw-------. 1 root root 1795 Oct 27 22:07 dmesg-efi-166692286703003
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286704003
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286705003
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286706003
-rw-------. 1 root root 1814 Oct 27 22:07 dmesg-efi-166692286707003
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286708003
-rw-------. 1 root root 1769 Oct 27 22:07 dmesg-efi-166692286709003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286710003
-rw-------. 1 root root 1755 Oct 27 22:07 dmesg-efi-166692286711003
-rw-------. 1 root root 1790 Oct 27 22:07 dmesg-efi-166692286712003
-rw-------. 1 root root 1756 Oct 27 22:07 dmesg-efi-166692286713003
-rw-------. 1 root root 1763 Oct 27 22:07 dmesg-efi-166692286714003
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286715003
-rw-------. 1 root root 1775 Oct 27 22:07 dmesg-efi-166692286716003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286717003
-rw-r-----. 1 root root 30111 Nov 18 14:58 dmesg.txt
Furthemore, pstore records on ERST are now able to accurately
identify the change in timestamp sequence in order to start a
new dmesg.txt, as needed.
(cherry picked from commit 5fbaa757077bde2db8d33b1c358518c41b990339)
Related: #2158832
---
src/pstore/pstore.c | 216 +++++++++++++++++++-------------------------
1 file changed, 92 insertions(+), 124 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index d70e142b4d..9f61e8f7f8 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -112,8 +112,8 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
return strcmp(a->dirent.d_name, b->dirent.d_name);
}
-static int move_file(PStoreEntry *pe, const char *subdir) {
- _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
+static int move_file(PStoreEntry *pe, const char *subdir1, const char *subdir2) {
+ _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL, *ofd_path_base = NULL;
_cleanup_free_ void *field = NULL;
const char *suffix, *message;
struct iovec iovec[2];
@@ -126,7 +126,11 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
if (!ifd_path)
return log_oom();
- ofd_path = path_join(arg_archivedir, subdir, pe->dirent.d_name);
+ ofd_path_base = path_join(arg_archivedir, subdir1, subdir2);
+ if (!ofd_path_base)
+ return log_oom();
+
+ ofd_path = path_join(NULL, ofd_path_base, pe->dirent.d_name);
if (!ofd_path)
return log_oom();
@@ -169,155 +173,119 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
return 0;
}
-static int write_dmesg(const char *dmesg, size_t size, const char *id) {
- _cleanup_(unlink_and_freep) char *tmp_path = NULL;
- _cleanup_free_ char *ofd_path = NULL;
+static int append_dmesg(PStoreEntry *pe, const char *subdir1, const char *subdir2) {
+ /* Append dmesg chunk to end, create if needed */
+ _cleanup_free_ char *ofd_path = NULL, *ofd_path_base = NULL;
_cleanup_close_ int ofd = -1;
ssize_t wr;
- int r;
- if (size == 0)
- return 0;
+ assert(pe);
- assert(dmesg);
+ if (pe->content_size == 0)
+ return 0;
- /* log_info("Record ID %s", id); */
+ ofd_path_base = path_join(arg_archivedir, subdir1, subdir2);
+ if (!ofd_path_base)
+ return log_oom();
- ofd_path = path_join(arg_archivedir, id, "dmesg.txt");
+ ofd_path = path_join(NULL, ofd_path_base, "dmesg.txt");
if (!ofd_path)
return log_oom();
- ofd = open_tmpfile_linkable(ofd_path, O_CLOEXEC|O_CREAT|O_TRUNC|O_WRONLY, &tmp_path);
+ ofd = open(ofd_path, O_CREAT|O_NOFOLLOW|O_NOCTTY|O_CLOEXEC|O_APPEND|O_WRONLY, 0640);
if (ofd < 0)
- return log_error_errno(ofd, "Failed to open temporary file %s: %m", ofd_path);
- wr = write(ofd, dmesg, size);
+ return log_error_errno(ofd, "Failed to open file %s: %m", ofd_path);
+ wr = write(ofd, pe->content, pe->content_size);
if (wr < 0)
return log_error_errno(errno, "Failed to store dmesg to %s: %m", ofd_path);
- if (wr != (ssize_t)size)
- return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, size - wr);
- r = link_tmpfile(ofd, tmp_path, ofd_path);
- if (r < 0)
- return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path);
- tmp_path = mfree(tmp_path);
+ if ((size_t)wr != pe->content_size)
+ return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, pe->content_size - wr);
return 0;
}
-static void process_dmesg_files(PStoreList *list) {
+static int process_dmesg_files(PStoreList *list) {
/* Move files, reconstruct dmesg.txt */
- _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL;
- size_t dmesg_size = 0, dmesg_allocated = 0;
- bool dmesg_bad = false;
- PStoreEntry *pe;
+ _cleanup_free_ char *erst_subdir = NULL;
+ uint64_t last_record_id = 0;
+
+ /* When dmesg is written into pstore, it is done so in small chunks, whatever the exchange buffer
+ * size is with the underlying pstore backend (ie. EFI may be ~2KiB), which means an example
+ * pstore with approximately 64KB of storage may have up to roughly 32 dmesg files, some likely
+ * related.
+ *
+ * Here we look at the dmesg filename and try to discern if files are part of a related group,
+ * meaning the same original dmesg.
+ *
+ * The dmesg- filename contains the backend-type and the Common Platform Error Record, CPER,
+ * record id, a 64-bit number.
+ *
+ * Files are processed in reverse lexigraphical order so as to properly reconstruct original dmesg.*/
- /* Handle each dmesg file: files processed in reverse
- * order so as to properly reconstruct original dmesg */
for (size_t n = list->n_entries; n > 0; n--) {
- bool move_file_and_continue = false;
- _cleanup_free_ char *pe_id = NULL;
+ PStoreEntry *pe;
char *p;
- size_t plen;
pe = &list->entries[n-1];
if (pe->handled)
continue;
- if (!startswith(pe->dirent.d_name, "dmesg-"))
- continue;
-
if (endswith(pe->dirent.d_name, ".enc.z")) /* indicates a problem */
- move_file_and_continue = true;
- p = strrchr(pe->dirent.d_name, '-');
- if (!p)
- move_file_and_continue = true;
-
- if (move_file_and_continue) {
- /* A dmesg file on which we do NO additional processing */
- (void) move_file(pe, NULL);
continue;
- }
-
- /* See if this file is one of a related group of files
- * in order to reconstruct dmesg */
-
- /* When dmesg is written into pstore, it is done so in
- * small chunks, whatever the exchange buffer size is
- * with the underlying pstore backend (ie. EFI may be
- * ~2KiB), which means an example pstore with approximately
- * 64KB of storage may have up to roughly 32 dmesg files
- * that could be related, depending upon the size of the
- * original dmesg.
- *
- * Here we look at the dmesg filename and try to discern
- * if files are part of a related group, meaning the same
- * original dmesg.
- *
- * The two known pstore backends are EFI and ERST. These
- * backends store data in the Common Platform Error
- * Record, CPER, format. The dmesg- filename contains the
- * CPER record id, a 64bit number (in decimal notation).
- * In Linux, the record id is encoded with two digits for
- * the dmesg part (chunk) number and 3 digits for the
- * count number. So allowing an additional digit to
- * compensate for advancing time, this code ignores the
- * last six digits of the filename in determining the
- * record id.
- *
- * For the EFI backend, the record id encodes an id in the
- * upper 32 bits, and a timestamp in the lower 32-bits.
- * So ignoring the least significant 6 digits has proven
- * to generally identify related dmesg entries. */
-#define PSTORE_FILENAME_IGNORE 6
-
- /* determine common portion of record id */
- ++p; /* move beyond dmesg- */
- plen = strlen(p);
- if (plen > PSTORE_FILENAME_IGNORE) {
- pe_id = memdup_suffix0(p, plen - PSTORE_FILENAME_IGNORE);
- if (!pe_id) {
- log_oom();
- return;
- }
- } else
- pe_id = mfree(pe_id);
-
- /* Now move file from pstore to archive storage */
- move_file(pe, pe_id);
-
- if (dmesg_bad)
+ if (!startswith(pe->dirent.d_name, "dmesg-"))
continue;
- /* If the current record id is NOT the same as the
- * previous record id, then start a new dmesg.txt file */
- if (!streq_ptr(pe_id, dmesg_id)) {
- /* Encountered a new dmesg group, close out old one, open new one */
- (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
- dmesg_size = 0;
-
- /* now point dmesg_id to storage of pe_id */
- free_and_replace(dmesg_id, pe_id);
- }
-
- /* Reconstruction of dmesg is done as a useful courtesy: do not fail, but don't write garbled
- * output either. */
- size_t needed = strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1;
- if (!GREEDY_REALLOC(dmesg, dmesg_allocated, dmesg_size + needed)) {
- log_warning_errno(ENOMEM, "Failed to write dmesg file: %m");
- dmesg_bad = true;
- continue;
- }
-
- dmesg_size += sprintf(dmesg + dmesg_size, "%s:\n", pe->dirent.d_name);
- if (pe->content) {
- memcpy(dmesg + dmesg_size, pe->content, pe->content_size);
- dmesg_size += pe->content_size;
- }
-
- pe_id = mfree(pe_id);
+ if ((p = startswith(pe->dirent.d_name, "dmesg-efi-"))) {
+ /* For the EFI backend, the 3 least significant digits of record id encodes a
+ * "count" number, the next 2 least significant digits for the dmesg part
+ * (chunk) number, and the remaining digits as the timestamp. See
+ * linux/drivers/firmware/efi/efi-pstore.c in efi_pstore_write(). */
+ _cleanup_free_ char *subdir1 = NULL, *subdir2 = NULL;
+ size_t plen = strlen(p);
+
+ if (plen < 6)
+ continue;
+
+ /* Extract base record id */
+ subdir1 = strndup(p, plen - 5);
+ if (!subdir1)
+ return log_oom();
+ /* Extract "count" field */
+ subdir2 = strndup(p + plen - 3, 3);
+ if (!subdir2)
+ return log_oom();
+
+ /* Now move file from pstore to archive storage */
+ (void) move_file(pe, subdir1, subdir2);
+
+ /* Append to the dmesg */
+ (void) append_dmesg(pe, subdir1, subdir2);
+ } else if ((p = startswith(pe->dirent.d_name, "dmesg-erst-"))) {
+ /* For the ERST backend, the record is a monotonically increasing number, seeded as
+ * a timestamp. See linux/drivers/acpi/apei/erst.c in erst_writer(). */
+ uint64_t record_id;
+
+ if (safe_atou64(p, &record_id) < 0)
+ continue;
+ if (last_record_id - 1 != record_id)
+ /* A discontinuity in the number has been detected, this current record id
+ * will become the directory name for all pieces of the dmesg in this
+ * series. */
+ if (free_and_strdup(&erst_subdir, p) < 0)
+ return log_oom();
+
+ /* Now move file from pstore to archive storage */
+ (void) move_file(pe, erst_subdir, NULL);
+
+ /* Append to the dmesg */
+ (void) append_dmesg(pe, erst_subdir, NULL);
+
+ /* Update, but keep erst_subdir for next file */
+ last_record_id = record_id;
+ } else
+ log_debug("Unknown backend, ignoring \"%s\".", pe->dirent.d_name);
}
-
- if (!dmesg_bad)
- (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+ return 0;
}
static int list_files(PStoreList *list, const char *sourcepath) {
@@ -394,11 +362,11 @@ static int run(int argc, char *argv[]) {
qsort_safe(list.entries, list.n_entries, sizeof(PStoreEntry), compare_pstore_entries);
/* Process known file types */
- process_dmesg_files(&list);
+ (void) process_dmesg_files(&list);
/* Move left over files out of pstore */
for (size_t n = 0; n < list.n_entries; n++)
- move_file(&list.entries[n], NULL);
+ (void) move_file(&list.entries[n], NULL, NULL);
return 0;
}

View File

@ -0,0 +1,27 @@
From 653a635086cfeaf0af12da3a722b0ebe2029b927 Mon Sep 17 00:00:00 2001
From: Balint Reczey <balint.reczey@canonical.com>
Date: Mon, 16 Dec 2019 19:03:19 +0100
Subject: [PATCH] pstore: Don't start systemd-pstore.service in containers
Usually it is not useful and can also fail making
boot-and-services autopkgtest fail.
(cherry picked from commit 287f506c32f3f4a48ba020408f964cb0f964d752)
Related: #2158832
---
units/systemd-pstore.service.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index dde21bc33e..89f34afe34 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -11,6 +11,7 @@
Description=Platform Persistent Storage Archival
Documentation=man:systemd-pstore(8)
ConditionDirectoryNotEmpty=/sys/fs/pstore
+ConditionVirtualization=!container
DefaultDependencies=no
Wants=systemd-remount-fs.service
After=systemd-remount-fs.service

View File

@ -0,0 +1,36 @@
From c7e65774a4ccc8a431f63c5a12ab776b24ee1190 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 8 Apr 2020 16:12:00 +0200
Subject: [PATCH] units: pull in systemd-pstore.service from sysinit.target
sysinit.target is the target our early boot services are generally
pulled in from, make systemd-pstore.service not an exception of that.
Effectively this doesn't mean much, either way our unit is part of the
initial transaction.
(cherry picked from commit 167241912f51fbc0d7d0869b9af34c15b5ecc4b6)
Related: #2158832
---
units/systemd-pstore.service.in | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 89f34afe34..37fcf878f0 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -15,6 +15,7 @@ ConditionVirtualization=!container
DefaultDependencies=no
Wants=systemd-remount-fs.service
After=systemd-remount-fs.service
+Before=sysinit.target
[Service]
Type=oneshot
@@ -23,4 +24,4 @@ RemainAfterExit=yes
StateDirectory=systemd/pstore
[Install]
-WantedBy=systemd-remount-fs.service
+WantedBy=sysinit.target

View File

@ -0,0 +1,36 @@
From bc6f273a0475a1fa7ab56bc1e498ee62c96aa660 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 8 Apr 2020 16:10:38 +0200
Subject: [PATCH] units: drop dependency on systemd-remount-fs.service from
systemd-pstore.service
This dependency is now generated automatically given we use
StateDirectory=. Moreover the combination of Wants= and After= was too
strong anway, as whether remount-fs is pulled in or not should not be up
to systemd-pstore.service, and in fact is part of the initial
transaction anyway.
[dtardon: This only removes Wants=, not After=, because I haven't
backported the auto-generation code the description talks about. The
code is simple, but it's just an optimisation allowing for slightly
shorter unit files, hence I don't think we really need it.]
(cherry picked from commit 0c978faa16fa9ecf92f0bbb5c7cc709dc472d115)
Related: #2158832
---
units/systemd-pstore.service.in | 1 -
1 file changed, 1 deletion(-)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 37fcf878f0..9a86f3145c 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -13,7 +13,6 @@ Documentation=man:systemd-pstore(8)
ConditionDirectoryNotEmpty=/sys/fs/pstore
ConditionVirtualization=!container
DefaultDependencies=no
-Wants=systemd-remount-fs.service
After=systemd-remount-fs.service
Before=sysinit.target

View File

@ -0,0 +1,29 @@
From 818ddd1efd751ef50f9960920284465befe9d704 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 8 Apr 2020 16:25:03 +0200
Subject: [PATCH] units: make sure systemd-pstore stops at shutdown
This doesn't matter too much given that the service doesn't do anything
on shutdown, but let's still stop it to make things cleaner.
(cherry picked from commit b0c1a07654c80d3cbbbcc52f860d4206707c0b08)
Related: #2158832
---
units/systemd-pstore.service.in | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 9a86f3145c..8cbf264a99 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -14,7 +14,8 @@ ConditionDirectoryNotEmpty=/sys/fs/pstore
ConditionVirtualization=!container
DefaultDependencies=no
After=systemd-remount-fs.service
-Before=sysinit.target
+Conflicts=shutdown.target
+Before=sysinit.target shutdown.target
[Service]
Type=oneshot

View File

@ -0,0 +1,45 @@
From 9cc6ee46e0083bc36b53d19e14fb637f7a1542dd Mon Sep 17 00:00:00 2001
From: Alexander Graf <graf@amazon.com>
Date: Thu, 9 Jun 2022 16:20:43 +0200
Subject: [PATCH] pstore: Run after modules are loaded
The systemd-pstore service takes pstore files on boot and transfers them
to disk. It only does it once on boot and only if it finds any. The typical
location of the pstore on modern systems is the UEFI variable store.
Most distributions ship with CONFIG_EFI_VARS_PSTORE=m. That means, the
UEFI variable store is only available on boot after the respective module
is loaded.
In most situations, the pstore service gets loaded before the UEFI pstore,
so we don't get to transfer logs. Instead, they accumulate, filling up the
pstore over time, potentially breaking the UEFI variable store.
Let's add a service dependency on any kernel module that can provide a
pstore to ensure we only scan for pstate after we can actually see pstate.
I have seen live occurences of systems breaking because we did not erase
the pstates and ran out of UEFI nvram space.
Fixes https://github.com/systemd/systemd/issues/18540
(cherry picked from commit 70e74a5997ae2ce7ba72a74ac949c3b2dad1a1d6)
Related: #2158832
---
units/systemd-pstore.service.in | 2 ++
1 file changed, 2 insertions(+)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 8cbf264a99..1983a9738f 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -16,6 +16,8 @@ DefaultDependencies=no
After=systemd-remount-fs.service
Conflicts=shutdown.target
Before=sysinit.target shutdown.target
+After=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service
+Wants=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service
[Service]
Type=oneshot

View File

@ -0,0 +1,48 @@
From 6a6f108b59e47581d93cbc6bdc604ee84f1bb791 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Wed, 7 Sep 2022 13:25:13 -0400
Subject: [PATCH] pstore: do not try to load all known pstore modules
Commit 70e74a5997 ("pstore: Run after modules are loaded") added After=
and Wants= entries for all known kernel modules providing a pstore.
While adding these dependencies on systems where one of the modules is
not present, or not configured, should not have a real affect on the
system, it can produce annoying error messages in the kernel log. E.g.
"mtd device must be supplied (device name is empty)" when the mtdpstore
module is not configured correctly.
Since dependencies cannot be removed with drop-ins, if a distro wants to
remove some of these modules from systemd-pstore.service, they need to
patch units/systemd-pstore.service.in. On the other hand, if they want
to append to the dependencies this can be done by shipping a drop-in.
Since the original intent of the previous commit was to fix [1], which
only requires the efi_pstore module, remove all other kernel module
dependencies from systemd-pstore.service, and let distros ship drop-ins
to add dependencies if needed.
[1] https://github.com/systemd/systemd/issues/18540
(cherry picked from commit 8b8bd621e1d16808678fc3afed257df1fa03a281)
Related: #2158832
---
units/systemd-pstore.service.in | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 1983a9738f..19ffa8d4e8 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -16,8 +16,8 @@ DefaultDependencies=no
After=systemd-remount-fs.service
Conflicts=shutdown.target
Before=sysinit.target shutdown.target
-After=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service
-Wants=modprobe@efi_pstore.service modprobe@mtdpstore.service modprobe@chromeos_pstore.service modprobe@ramoops.service modprobe@pstore_zone.service modprobe@pstore_blk.service
+After=modprobe@efi_pstore.service
+Wants=modprobe@efi_pstore.service
[Service]
Type=oneshot

View File

@ -0,0 +1,26 @@
From b18e19f2262e7ed95c25d53268d12427fe77102d Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Tue, 21 Feb 2023 10:41:47 +0100
Subject: [PATCH] logind-session: make stopping of idle session visible to
admins
(cherry picked from commit 6269ffe7ee8a659df7336a2582054ecd9eecf4b1)
Resolves: #2156780
---
src/login/logind-session.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 18a07efcdb..916202a65a 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -673,7 +673,7 @@ static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, vo
idle = session_get_idle_hint(s, &ts);
if (idle) {
- log_debug("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->name);
+ log_info("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->name);
return session_stop(s, /* force */ true);
}

View File

@ -0,0 +1,32 @@
From a0b52398692f3e4bda18520db9e2397f7b2c80dd Mon Sep 17 00:00:00 2001
From: Benjamin Robin <dev@benjarobin.fr>
Date: Sun, 3 May 2020 18:37:21 +0200
Subject: [PATCH] journald: Increase stdout buffer size sooner, when almost
full
If the previous received buffer length is almost equal to the allocated
buffer size, before this change the next read can only receive a couple
of bytes (in the worst case only 1 byte), which is not efficient.
(cherry picked from commit 034e9719ac1ba88a36b05da38c7aa98761d42c77)
Related: #2029426
---
src/journal/journald-stream.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 302a82d3d7..c8de984335 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -507,8 +507,8 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
goto terminate;
}
- /* If the buffer is full already (discounting the extra NUL we need), add room for another 1K */
- if (s->length + 1 >= s->allocated) {
+ /* If the buffer is almost full, add room for another 1K */
+ if (s->length + 512 >= s->allocated) {
if (!GREEDY_REALLOC(s->buffer, s->allocated, s->length + 1 + 1024)) {
log_oom();
goto terminate;

View File

@ -0,0 +1,77 @@
From d8fabe7a6839eeb0d5d0504471f2d18b07545238 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 12 May 2020 18:53:35 +0200
Subject: [PATCH] journald: rework end of line marker handling to use a field
table
(cherry picked from commit 549b7379ba404c33fd448d2bca46a57f6529b00b)
Related: #2029426
---
src/journal/journald-stream.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index c8de984335..58752a5a24 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -54,6 +54,8 @@ typedef enum LineBreak {
LINE_BREAK_NUL,
LINE_BREAK_LINE_MAX,
LINE_BREAK_EOF,
+ _LINE_BREAK_MAX,
+ _LINE_BREAK_INVALID = -1,
} LineBreak;
struct StdoutStream {
@@ -233,7 +235,11 @@ fail:
return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
}
-static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) {
+static int stdout_stream_log(
+ StdoutStream *s,
+ const char *p,
+ LineBreak line_break) {
+
struct iovec *iovec;
int priority;
char syslog_priority[] = "PRIORITY=\0";
@@ -245,6 +251,9 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea
assert(s);
assert(p);
+ assert(line_break >= 0);
+ assert(line_break < _LINE_BREAK_MAX);
+
if (s->context)
(void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY);
else if (pid_is_valid(s->ucred.pid)) {
@@ -296,17 +305,19 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea
iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier);
}
- if (line_break != LINE_BREAK_NEWLINE) {
- const char *c;
+ static const char * const line_break_field_table[_LINE_BREAK_MAX] = {
+ [LINE_BREAK_NEWLINE] = NULL, /* Do not add field if traditional newline */
+ [LINE_BREAK_NUL] = "_LINE_BREAK=nul",
+ [LINE_BREAK_LINE_MAX] = "_LINE_BREAK=line-max",
+ [LINE_BREAK_EOF] = "_LINE_BREAK=eof",
+ };
- /* If this log message was generated due to an uncommon line break then mention this in the log
- * entry */
+ const char *c = line_break_field_table[line_break];
- c = line_break == LINE_BREAK_NUL ? "_LINE_BREAK=nul" :
- line_break == LINE_BREAK_LINE_MAX ? "_LINE_BREAK=line-max" :
- "_LINE_BREAK=eof";
+ /* If this log message was generated due to an uncommon line break then mention this in the log
+ * entry */
+ if (c)
iovec[n++] = IOVEC_MAKE_STRING(c);
- }
message = strappend("MESSAGE=", p);
if (message)

View File

@ -0,0 +1,27 @@
From cd85a657c932725ac7c1b506dc6dd4270d1dc068 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 12 May 2020 19:15:38 +0200
Subject: [PATCH] journald: use the fact that client_context_release() returns
NULL
(cherry picked from commit 020b4a023c2c6dda83afb9a82a62e640569c40c1)
Related: #2029426
---
src/journal/journald-stream.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 58752a5a24..ab1a855943 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -570,8 +570,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
goto terminate;
s->ucred = *ucred;
- client_context_release(s->server, s->context);
- s->context = NULL;
+ s->context = client_context_release(s->server, s->context);
}
s->length += l;

View File

@ -0,0 +1,219 @@
From 538bd9b42dabf1145cf7ab77f32347d516b01e88 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 12 May 2020 18:56:34 +0200
Subject: [PATCH] journald: rework pid change handling
Let's introduce an explicit line ending marker for line endings due to
pid change.
Let's also make sure we don't get confused with buffer management.
Fixes: #15654
(cherry picked from commit 45ba1ea5e9264d385fa565328fe957ef1d78caa1)
Resolves: #2029426
---
src/journal/journald-stream.c | 99 +++++++++++++++++++++++------------
1 file changed, 66 insertions(+), 33 deletions(-)
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index ab1a855943..5be5b0939c 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -54,6 +54,7 @@ typedef enum LineBreak {
LINE_BREAK_NUL,
LINE_BREAK_LINE_MAX,
LINE_BREAK_EOF,
+ LINE_BREAK_PID_CHANGE,
_LINE_BREAK_MAX,
_LINE_BREAK_INVALID = -1,
} LineBreak;
@@ -310,6 +311,7 @@ static int stdout_stream_log(
[LINE_BREAK_NUL] = "_LINE_BREAK=nul",
[LINE_BREAK_LINE_MAX] = "_LINE_BREAK=line-max",
[LINE_BREAK_EOF] = "_LINE_BREAK=eof",
+ [LINE_BREAK_PID_CHANGE] = "_LINE_BREAK=pid-change",
};
const char *c = line_break_field_table[line_break];
@@ -431,21 +433,43 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
assert_not_reached("Unknown stream state");
}
-static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
- char *p;
- size_t remaining;
+static int stdout_stream_found(
+ StdoutStream *s,
+ char *p,
+ size_t l,
+ LineBreak line_break) {
+
+ char saved;
int r;
assert(s);
+ assert(p);
+
+ /* Let's NUL terminate the specified buffer for this call, and revert back afterwards */
+ saved = p[l];
+ p[l] = 0;
+ r = stdout_stream_line(s, p, line_break);
+ p[l] = saved;
- p = s->buffer;
- remaining = s->length;
+ return r;
+}
+
+static int stdout_stream_scan(
+ StdoutStream *s,
+ char *p,
+ size_t remaining,
+ LineBreak force_flush,
+ size_t *ret_consumed) {
- /* XXX: This function does nothing if (s->length == 0) */
+ size_t consumed = 0;
+ int r;
+
+ assert(s);
+ assert(p);
for (;;) {
LineBreak line_break;
- size_t skip;
+ size_t skip, found;
char *end1, *end2;
end1 = memchr(p, '\n', remaining);
@@ -453,43 +477,40 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
if (end2) {
/* We found a NUL terminator */
- skip = end2 - p + 1;
+ found = end2 - p;
+ skip = found + 1;
line_break = LINE_BREAK_NUL;
} else if (end1) {
/* We found a \n terminator */
- *end1 = 0;
- skip = end1 - p + 1;
+ found = end1 - p;
+ skip = found + 1;
line_break = LINE_BREAK_NEWLINE;
} else if (remaining >= s->server->line_max) {
/* Force a line break after the maximum line length */
- *(p + s->server->line_max) = 0;
- skip = remaining;
+ found = skip = s->server->line_max;
line_break = LINE_BREAK_LINE_MAX;
} else
break;
- r = stdout_stream_line(s, p, line_break);
+ r = stdout_stream_found(s, p, found, line_break);
if (r < 0)
return r;
- remaining -= skip;
p += skip;
+ consumed += skip;
+ remaining -= skip;
}
- if (force_flush && remaining > 0) {
- p[remaining] = 0;
- r = stdout_stream_line(s, p, LINE_BREAK_EOF);
+ if (force_flush >= 0 && remaining > 0) {
+ r = stdout_stream_found(s, p, remaining, force_flush);
if (r < 0)
return r;
- p += remaining;
- remaining = 0;
+ consumed += remaining;
}
- if (p > s->buffer) {
- memmove(s->buffer, p, remaining);
- s->length = remaining;
- }
+ if (ret_consumed)
+ *ret_consumed = consumed;
return 0;
}
@@ -497,11 +518,12 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
StdoutStream *s = userdata;
+ size_t limit, consumed;
struct ucred *ucred = NULL;
struct cmsghdr *cmsg;
struct iovec iovec;
- size_t limit;
ssize_t l;
+ char *p;
int r;
struct msghdr msghdr = {
@@ -529,7 +551,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
/* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also,
* always leave room for a terminating NUL we might need to add. */
limit = MIN(s->allocated - 1, s->server->line_max);
-
+ assert(s->length <= limit);
iovec = IOVEC_MAKE(s->buffer + s->length, limit - s->length);
l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
@@ -543,7 +565,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
cmsg_close_all(&msghdr);
if (l == 0) {
- stdout_stream_scan(s, true);
+ (void) stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_EOF, NULL);
goto terminate;
}
@@ -562,22 +584,33 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
* in the meantime.
*/
if (ucred && ucred->pid != s->ucred.pid) {
- /* force out any previously half-written lines from a
- * different process, before we switch to the new ucred
- * structure for everything we just added */
- r = stdout_stream_scan(s, true);
+ /* Force out any previously half-written lines from a different process, before we switch to
+ * the new ucred structure for everything we just added */
+ r = stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_PID_CHANGE, NULL);
if (r < 0)
goto terminate;
- s->ucred = *ucred;
s->context = client_context_release(s->server, s->context);
+
+ p = s->buffer + s->length;
+ } else {
+ p = s->buffer;
+ l += s->length;
}
- s->length += l;
- r = stdout_stream_scan(s, false);
+ /* Always copy in the new credentials */
+ if (ucred)
+ s->ucred = *ucred;
+
+ r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed);
if (r < 0)
goto terminate;
+ /* Move what wasn't consumed to the front of the buffer */
+ assert(consumed <= (size_t) l);
+ s->length = l - consumed;
+ memmove(s->buffer, p + consumed, s->length);
+
return 1;
terminate:

View File

@ -0,0 +1,34 @@
From e019afeefb396ea42d03f4c3f9713e262aff6450 Mon Sep 17 00:00:00 2001
From: Benjamin Robin <dev@benjarobin.fr>
Date: Wed, 6 May 2020 23:28:02 +0200
Subject: [PATCH] test: Add a test case for #15654
(cherry picked from commit c11d8fd1dab3bc3f0abbc861ba5eb34518cec1da)
Related: #2029426
---
test/TEST-04-JOURNAL/test-journal.sh | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh
index a3db1a7472..bdf137cd69 100755
--- a/test/TEST-04-JOURNAL/test-journal.sh
+++ b/test/TEST-04-JOURNAL/test-journal.sh
@@ -76,6 +76,17 @@ journalctl -b -o export -t "$ID" --output-fields=_PID | grep '^_PID=' >/output
grep -q "^_PID=$PID" /output
grep -vq "^_PID=$PID" /output
+# https://github.com/systemd/systemd/issues/15654
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf "This will\nusually fail\nand be truncated\n">/expected
+systemd-cat -t "$ID" /bin/sh -c 'env echo -n "This will";echo;env echo -n "usually fail";echo;env echo -n "and be truncated";echo;'
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+# Add new tests before here, the journald restarts below
+# may make tests flappy.
+
# Don't lose streams on restart
systemctl start forever-print-hola
sleep 3

View File

@ -0,0 +1,32 @@
From afcfb65ce7514bf32e59e0b9d212ae18d023a4b5 Mon Sep 17 00:00:00 2001
From: Benjamin Robin <dev@benjarobin.fr>
Date: Sat, 9 May 2020 12:01:07 +0200
Subject: [PATCH] test: Stricter test case for #15654 (Add more checks)
Check:
- There is only 3 messages logged with type stdout
- Check all messages logged does not have new line: LINE_BREAK=eof
- Check that the 3 messages are logged from a different PID
- Check the 3 MESSAGE= content
(cherry picked from commit d38b3b74dbde2d65b23e5963354c3db96acd3420)
Related: #2029426
---
test/TEST-04-JOURNAL/test-journal.sh | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh
index bdf137cd69..641259ce24 100755
--- a/test/TEST-04-JOURNAL/test-journal.sh
+++ b/test/TEST-04-JOURNAL/test-journal.sh
@@ -83,6 +83,10 @@ systemd-cat -t "$ID" /bin/sh -c 'env echo -n "This will";echo;env echo -n "usual
journalctl --sync
journalctl -b -o cat -t "$ID" >/output
cmp /expected /output
+[[ $(journalctl -b -o export -t "$ID" --output-fields=_TRANSPORT | grep -Pc "^_TRANSPORT=stdout$") -eq 3 ]]
+[[ $(journalctl -b -o export -t "$ID" --output-fields=_LINE_BREAK | grep -Pc "^_LINE_BREAK=pid-change$") -eq 3 ]]
+[[ $(journalctl -b -o export -t "$ID" --output-fields=_PID | sort -u | grep -c "^_PID=.*$") -eq 3 ]]
+[[ $(journalctl -b -o export -t "$ID" --output-fields=MESSAGE | grep -Pc "^MESSAGE=(This will|usually fail|and be truncated)$") -eq 3 ]]
# Add new tests before here, the journald restarts below
# may make tests flappy.

View File

@ -0,0 +1,42 @@
From 2f55aeadef3dcdf65c61f24a41178148c3544ac3 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 13 May 2020 00:09:43 +0200
Subject: [PATCH] man: document the new _LINE_BREAK= type
(cherry picked from commit a3d9aee14fa2f7df429dc401582877176206b7fd)
Related: #2029426
---
man/systemd.journal-fields.xml | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml
index 0c95c4cd95..ad2b94dbd5 100644
--- a/man/systemd.journal-fields.xml
+++ b/man/systemd.journal-fields.xml
@@ -326,15 +326,16 @@
<varlistentry>
<term><varname>_LINE_BREAK=</varname></term>
<listitem>
- <para>Only applies to <literal>_TRANSPORT=stdout</literal> records: indicates that the log message in the
- standard output/error stream was not terminated with a normal newline character (<literal>\n</literal>,
- i.e. ASCII 10). Specifically, when set this field is one of <option>nul</option> (in case the line was
- terminated by a NUL byte), <option>line-max</option> (in case the maximum log line length was reached, as
- configured with <varname>LineMax=</varname> in
- <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or
- <option>eof</option> (if this was the last log record of a stream and the stream ended without a final
- newline character). Note that this record is not generated when a normal newline character was used for
- marking the log line end.</para>
+ <para>Only applies to <literal>_TRANSPORT=stdout</literal> records: indicates that the log message
+ in the standard output/error stream was not terminated with a normal newline character
+ (<literal>\n</literal>, i.e. ASCII 10). Specifically, when set this field is one of
+ <option>nul</option> (in case the line was terminated by a NUL byte), <option>line-max</option> (in
+ case the maximum log line length was reached, as configured with <varname>LineMax=</varname> in
+ <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+ <option>eof</option> (if this was the last log record of a stream and the stream ended without a
+ final newline character), or <option>pid-change</option> (if the process which generated the log
+ output changed in the middle of a line). Note that this record is not generated when a normal
+ newline character was used for marking the log line end.</para>
</listitem>
</varlistentry>
</variablelist>

View File

@ -0,0 +1,38 @@
From 0491902d0eff9f4480ce873decc5dd29e5e189d7 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 13 Mar 2023 14:22:28 +0100
Subject: [PATCH] journald-server: always create state file in signal handler
`journalctl --flush` waits on that file, so we must create if even if
nothing has really happened.
RHEL-only
Resolves: #2176892
---
src/journal/journald-server.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 279a32768c..c72cb68095 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1188,6 +1188,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Server *s = userdata;
+ int r;
assert(s);
@@ -1197,6 +1198,10 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
server_sync(s);
server_vacuum(s, false);
+ r = touch("/run/systemd/journal/flushed");
+ if (r < 0)
+ log_warning_errno(r, "Failed to touch /run/systemd/journal/flushed, ignoring: %m");
+
server_space_usage_message(s, NULL);
return 0;
}

View File

@ -0,0 +1,62 @@
From 62c8e07498c9dd13aa79371fc169bb51652ef3a9 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 13 Mar 2023 14:31:38 +0100
Subject: [PATCH] journald-server: move relinquish code into function
No functional change, just refactoring.
RHEL-only
Related: #2176892
---
src/journal/journald-server.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index c72cb68095..aa70db95cc 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1258,20 +1258,16 @@ static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo
return 0;
}
-
-static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
- Server *s = userdata;
+static void relinquish_var(Server *s) {
int r;
assert(s);
if (s->storage == STORAGE_NONE)
- return 0;
+ return;
if (s->runtime_journal && !s->system_journal)
- return 0;
-
- log_debug("Received request to relinquish /var from PID " PID_FMT, si->ssi_pid);
+ return;
(void) system_journal_open(s, false, true);
@@ -1286,6 +1282,19 @@ static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo
if (r < 0)
log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m");
+ return;
+}
+
+static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
+ Server *s = userdata;
+
+ assert(s);
+ assert(si);
+
+ log_debug("Received request to relinquish /var from PID " PID_FMT, si->ssi_pid);
+
+ relinquish_var(s);
+
return 0;
}

View File

@ -0,0 +1,58 @@
From 05a06e34ac8a38c1cff2a08ba071386141e0b78d Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 13 Mar 2023 14:32:20 +0100
Subject: [PATCH] journald-server: always touch state file in signal handler
`journalctl --relinquish-var` waits on that file, so we must create if
even if nothing has really happened.
RHEL-only
Related: #2176892
---
src/journal/journald-server.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index aa70db95cc..4788ff78bb 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1259,8 +1259,6 @@ static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo
}
static void relinquish_var(Server *s) {
- int r;
-
assert(s);
if (s->storage == STORAGE_NONE)
@@ -1278,15 +1276,15 @@ static void relinquish_var(Server *s) {
if (unlink("/run/systemd/journal/flushed") < 0 && errno != ENOENT)
log_warning_errno(errno, "Failed to unlink /run/systemd/journal/flushed, ignoring: %m") ;
- r = write_timestamp_file_atomic("/run/systemd/journal/relinquished", now(CLOCK_MONOTONIC));
- if (r < 0)
- log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m");
+ /* NOTE: We don't create our own state file here, because dispatch_sigrtmin2() has to do it anyway.
+ * But if this function is ever called from another place, the creation must be done here too. */
return;
}
static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Server *s = userdata;
+ int r;
assert(s);
assert(si);
@@ -1295,6 +1293,10 @@ static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo
relinquish_var(s);
+ r = write_timestamp_file_atomic("/run/systemd/journal/relinquished", now(CLOCK_MONOTONIC));
+ if (r < 0)
+ log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m");
+
return 0;
}

View File

@ -0,0 +1,299 @@
From 96e69cb655c703d5312c4aa44912e6ce90b4f76f Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Wed, 29 Mar 2023 22:38:55 +0200
Subject: [PATCH] test: make TEST-35-LOGIN stable again
The expect stuff was anything but expected, so let's just backport
the upstream test case and tweak it a bit to account for the missing
parts in our downstream testing infrastructure.
Follow-up to 638c2418e7.
Related: #2179309
rhel-only
---
test/TEST-35-LOGIN/testsuite.sh | 225 ++++++++++++++++++++++++--------
test/test-functions | 2 +-
2 files changed, 175 insertions(+), 52 deletions(-)
diff --git a/test/TEST-35-LOGIN/testsuite.sh b/test/TEST-35-LOGIN/testsuite.sh
index e4d72beb74..149b2354a1 100755
--- a/test/TEST-35-LOGIN/testsuite.sh
+++ b/test/TEST-35-LOGIN/testsuite.sh
@@ -3,6 +3,141 @@
set -eux
set -o pipefail
+cleanup_test_user() (
+ set +ex
+
+ pkill -u "$(id -u logind-test-user)"
+ sleep 1
+ pkill -KILL -u "$(id -u logind-test-user)"
+ userdel -r logind-test-user
+
+ return 0
+)
+
+setup_test_user() {
+ mkdir -p /var/spool/cron /var/spool/mail /var/run/console
+ useradd -m -s /bin/bash logind-test-user
+ trap cleanup_test_user EXIT
+}
+
+test_enable_debug() {
+ mkdir -p /run/systemd/system/systemd-logind.service.d
+ cat >/run/systemd/system/systemd-logind.service.d/debug.conf <<EOF
+[Service]
+Environment=SYSTEMD_LOG_LEVEL=debug
+EOF
+ systemctl daemon-reload
+ systemctl stop systemd-logind.service
+}
+
+check_session() (
+ set +ex
+
+ local seat session leader_pid
+
+ if [[ $(loginctl --no-legend | grep -c "logind-test-user") != 1 ]]; then
+ echo "no session or multiple sessions for logind-test-user." >&2
+ return 1
+ fi
+
+ seat=$(loginctl --no-legend | grep 'logind-test-user *seat' | awk '{ print $4 }')
+ if [[ -z "$seat" ]]; then
+ echo "no seat found for user logind-test-user" >&2
+ return 1
+ fi
+
+ session=$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1 }')
+ if [[ -z "$session" ]]; then
+ echo "no session found for user logind-test-user" >&2
+ return 1
+ fi
+
+ if ! loginctl session-status "$session" | grep -q "Unit: session-${session}\.scope"; then
+ echo "cannot find scope unit for session $session" >&2
+ return 1
+ fi
+
+ leader_pid=$(loginctl session-status "$session" | awk '$1 == "Leader:" { print $2 }')
+ if [[ -z "$leader_pid" ]]; then
+ echo "cannot found leader process for session $session" >&2
+ return 1
+ fi
+
+ # cgroup v1: "1:name=systemd:/user.slice/..."; unified hierarchy: "0::/user.slice"
+ if ! grep -q -E '(name=systemd|^0:):.*session.*scope' /proc/"$leader_pid"/cgroup; then
+ echo "FAIL: process $leader_pid is not in the session cgroup" >&2
+ cat /proc/self/cgroup
+ return 1
+ fi
+)
+
+create_session() {
+ # login with the test user to start a session
+ mkdir -p /run/systemd/system/getty@tty2.service.d
+ cat >/run/systemd/system/getty@tty2.service.d/override.conf <<EOF
+[Service]
+Type=simple
+ExecStart=
+ExecStart=-/sbin/agetty --autologin logind-test-user --noclear %I $TERM
+Restart=no
+EOF
+ systemctl daemon-reload
+
+ systemctl restart getty@tty2.service
+
+ # check session
+ for ((i = 0; i < 30; i++)); do
+ (( i != 0 )) && sleep 1
+ check_session && break
+ done
+ check_session
+ [[ "$(loginctl --no-legend | awk '$3=="logind-test-user" { print $5 }')" == "tty2" ]]
+}
+
+cleanup_session() (
+ set +ex
+
+ local uid s
+
+ uid=$(id -u logind-test-user)
+
+ loginctl disable-linger logind-test-user
+
+ systemctl stop getty@tty2.service
+
+ for s in $(loginctl --no-legend list-sessions | awk '$3 == "logind-test-user" { print $1 }'); do
+ echo "INFO: stopping session $s"
+ loginctl terminate-session "$s"
+ done
+
+ loginctl terminate-user logind-test-user
+
+ if ! timeout 30 bash -c "while loginctl --no-legend | grep -q logind-test-user; do sleep 1; done"; then
+ echo "WARNING: session for logind-test-user still active, ignoring."
+ fi
+
+ pkill -u "$uid"
+ sleep 1
+ pkill -KILL -u "$uid"
+
+ if ! timeout 30 bash -c "while systemctl is-active --quiet user@${uid}.service; do sleep 1; done"; then
+ echo "WARNING: user@${uid}.service is still active, ignoring."
+ fi
+
+ if ! timeout 30 bash -c "while systemctl is-active --quiet user-runtime-dir@${uid}.service; do sleep 1; done"; then
+ echo "WARNING: user-runtime-dir@${uid}.service is still active, ignoring."
+ fi
+
+ if ! timeout 30 bash -c "while systemctl is-active --quiet user-${uid}.slice; do sleep 1; done"; then
+ echo "WARNING: user-${uid}.slice is still active, ignoring."
+ fi
+
+ rm -rf /run/systemd/system/getty@tty2.service.d
+ systemctl daemon-reload
+
+ return 0
+)
+
setup_idle_action_lock() {
useradd testuser ||:
@@ -19,83 +154,71 @@ EOF
Environment=SYSTEMD_LOG_LEVEL=debug
EOF
+ systemd-analyze cat-config --no-pager systemd/logind.conf
systemctl restart systemd-logind.service
}
-teardown_idle_action_lock() {(
- set +ex
+teardown_lock_idle_action() (
+ set +eux
+
rm -f /run/systemd/logind.conf.d/idle-action-lock.conf
- rm -f /run/systemd/systemd-logind.service.d/debug.conf
- pkill -9 -u "$(id -u testuser)"
- userdel -r testuser
systemctl restart systemd-logind.service
-)}
-test_lock_idle_action() {
- if ! command -v expect >/dev/null ; then
- echo >&2 "expect not installed, skiping test ${FUNCNAME[0]}"
- return 0
- fi
+ cleanup_session
- setup_idle_action_lock
- trap teardown_idle_action_lock RETURN
+ return 0
+)
- if loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -q testuser ; then
- echo >&2 "Session of the \'testuser\' is already present."
- return 1
+test_lock_idle_action() {
+ local ts
+
+ if [[ ! -c /dev/tty2 ]]; then
+ echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}."
+ return
fi
- # IdleActionSec is set 1s but the accuracy of associated timer is 30s so we
- # need to sleep in worst case for 31s to make sure timer elapsed. We sleep
- # here for 35s to accomodate for any possible scheudling delays.
- cat > /tmp/test.exp <<EOF
-spawn systemd-run -G -t -p PAMName=login -p User=testuser bash
-send "sleep 35\r"
-send "echo foobar\r"
-send "sleep 35\r"
-send "exit\r"
-interact
-wait
-EOF
+ if loginctl --no-legend | grep -q logind-test-user; then
+ echo >&2 "Session of the \'logind-test-user\' is already present."
+ exit 1
+ fi
- ts="$(date '+%H:%M:%S')"
- busctl --match "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Session',member='Lock'" monitor > dbus.log &
+ trap teardown_lock_idle_action RETURN
- expect /tmp/test.exp &
+ create_session
- # Sleep a bit to give expect time to spawn systemd-run before we check for
- # the presence of resulting session.
- sleep 2
- if [ "$(loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -c testuser)" != 1 ] ; then
- echo >&2 "\'testuser\' is expected to have exactly one session running."
- return 1
- fi
+ ts="$(date '+%H:%M:%S')"
- wait %2
- sleep 20
- kill %1
+ mkdir -p /run/systemd/logind.conf.d
+ cat >/run/systemd/logind.conf.d/idle-action-lock.conf <<EOF
+[Login]
+IdleAction=lock
+IdleActionSec=1s
+EOF
+ systemctl restart systemd-logind.service
- # We slept for 35s , in that interval all sessions should have become idle
+ # Wait for 35s, in that interval all sessions should have become idle
# and "Lock" signal should have been sent out. Then we wrote to tty to make
# session active again and next we slept for another 35s so sessions have
# become idle again. 'Lock' signal is sent out for each session, we have at
# least one session, so minimum of 2 "Lock" signals must have been sent.
- if [ "$(grep -c Member=Lock dbus.log)" -lt 2 ]; then
- echo >&2 "Too few 'Lock' D-Bus signal sent, expected at least 2."
- return 1
- fi
+ timeout 35 bash -c "while [[ \"\$(journalctl -b -u systemd-logind.service --since=$ts | grep -c 'Sent message type=signal .* member=Lock')\" -lt 1 ]]; do sleep 1; done"
+
+ # Wakeup
+ touch /dev/tty2
+
+ # Wait again
+ timeout 35 bash -c "while [[ \"\$(journalctl -b -u systemd-logind.service --since=$ts | grep -c 'Sent message type=signal .* member=Lock')\" -lt 2 ]]; do sleep 1; done"
- journalctl -b -u systemd-logind.service --since="$ts" > logind.log
- if [ "$(grep -c 'System idle. Doing lock operation.' logind.log)" -lt 2 ]; then
+ if [[ "$(journalctl -b -u systemd-logind.service --since="$ts" | grep -c 'System idle. Doing lock operation.')" -lt 2 ]]; then
echo >&2 "System haven't entered idle state at least 2 times."
- return 1
+ exit 1
fi
-
- rm -f dbus.log logind.log
}
: >/failed
+setup_test_user
+test_enable_debug
test_lock_idle_action
touch /testok
diff --git a/test/test-functions b/test/test-functions
index 9606a1b085..e5d4d28a5f 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -23,7 +23,7 @@ fi
PATH_TO_INIT=$ROOTLIBDIR/systemd
-BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env mktemp mountpoint useradd userdel"
+BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env mktemp mountpoint useradd userdel timeout"
DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find"
STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"

View File

@ -0,0 +1,113 @@
From c971d99ffc43df89ca4e15cd81f9e44f4139ba91 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 31 Aug 2020 19:37:13 +0200
Subject: [PATCH] pager: set $LESSSECURE whenver we invoke a pager
Some extra safety when invoked via "sudo". With this we address a
genuine design flaw of sudo, and we shouldn't need to deal with this.
But it's still a good idea to disable this surface given how exotic it
is.
Prompted by #5666
(cherry picked from commit 612ebf6c913dd0e4197c44909cb3157f5c51a2f0)
Related: #2175624
---
man/less-variables.xml | 8 ++++++++
man/systemctl.xml | 1 +
man/systemd.xml | 2 ++
src/basic/pager.c | 23 +++++++++++++++++++++--
4 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/man/less-variables.xml b/man/less-variables.xml
index a3faa38997..9dad4247da 100644
--- a/man/less-variables.xml
+++ b/man/less-variables.xml
@@ -36,5 +36,13 @@
the invoking terminal is determined to be UTF-8 compatible).</para></listitem>
</varlistentry>
+ <varlistentry id='lesssecure'>
+ <term><varname>$SYSTEMD_LESSSECURE</varname></term>
+
+ <listitem><para>Takes a boolean argument. Overrides the <varname>$LESSSECURE</varname> environment
+ variable when invoking the pager, which controls the "secure" mode of less (which disables commands
+ such as <literal>|</literal> which allow to easily shell out to external command lines). By default
+ less secure mode is enabled, with this setting it may be disabled.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/man/systemctl.xml b/man/systemctl.xml
index a71e6c7c4f..abc386e6fb 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -2010,6 +2010,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<xi:include href="less-variables.xml" xpointer="pager"/>
<xi:include href="less-variables.xml" xpointer="less"/>
<xi:include href="less-variables.xml" xpointer="lesscharset"/>
+ <xi:include href="less-variables.xml" xpointer="lesssecure"/>
</refsect1>
<refsect1>
diff --git a/man/systemd.xml b/man/systemd.xml
index 17ab59beb5..66ae4d841d 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -862,6 +862,8 @@
</listitem>
</varlistentry>
+ <xi:include href="less-variables.xml" xpointer="lesssecure"/>
+
<varlistentry>
<term><varname>$LISTEN_PID</varname></term>
<term><varname>$LISTEN_FDS</varname></term>
diff --git a/src/basic/pager.c b/src/basic/pager.c
index f241261119..4efb01c483 100644
--- a/src/basic/pager.c
+++ b/src/basic/pager.c
@@ -11,6 +11,7 @@
#include <unistd.h>
#include "copy.h"
+#include "env-util.h"
#include "fd-util.h"
#include "locale-util.h"
#include "log.h"
@@ -94,8 +95,7 @@ int pager_open(bool no_pager, bool jump_to_end) {
if (setenv("LESS", less_opts, 1) < 0)
_exit(EXIT_FAILURE);
- /* Initialize a good charset for less. This is
- * particularly important if we output UTF-8
+ /* Initialize a good charset for less. This is particularly important if we output UTF-8
* characters. */
less_charset = getenv("SYSTEMD_LESSCHARSET");
if (!less_charset && is_locale_utf8())
@@ -104,6 +104,25 @@ int pager_open(bool no_pager, bool jump_to_end) {
setenv("LESSCHARSET", less_charset, 1) < 0)
_exit(EXIT_FAILURE);
+ /* People might invoke us from sudo, don't needlessly allow less to be a way to shell out
+ * privileged stuff. */
+ r = getenv_bool("SYSTEMD_LESSSECURE");
+ if (r == 0) { /* Remove env var if off */
+ if (unsetenv("LESSSECURE") < 0) {
+ log_error_errno(errno, "Failed to uset environment variable LESSSECURE: %m");
+ _exit(EXIT_FAILURE);
+ }
+ } else {
+ /* Set env var otherwise */
+ if (r < 0)
+ log_warning_errno(r, "Unable to parse $SYSTEMD_LESSSECURE, ignoring: %m");
+
+ if (setenv("LESSSECURE", "1", 1) < 0) {
+ log_error_errno(errno, "Failed to set environment variable LESSSECURE: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+
if (pager) {
execlp(pager, pager, NULL);
execl("/bin/sh", "sh", "-c", pager, NULL);

View File

@ -0,0 +1,264 @@
From a45636228c7000aef000e45d9853585e51bfb9ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 12 Oct 2020 18:57:32 +0200
Subject: [PATCH] test-login: always test sd_pid_get_owner_uid(), modernize
A long time some function only worked when in a session, and the test
didn't execute them when sd_pid_get_session() failed. Let's always call
them to increase coverage.
While at it, let's test for ==0 not >=0 where we don't expect the function
to return anything except 0 or error.
(cherry picked from commit 1b5b507cd2d1d7a2b053151abb548475ad9c5c3b)
Related: #2175624
---
src/libsystemd/sd-login/test-login.c | 132 ++++++++++++++-------------
1 file changed, 71 insertions(+), 61 deletions(-)
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index ccb1905a46..60ef889ec0 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -8,20 +8,22 @@
#include "sd-login.h"
#include "alloc-util.h"
+#include "errno-list.h"
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
#include "string-util.h"
#include "strv.h"
-#include "util.h"
+#include "time-util.h"
+#include "user-util.h"
static char* format_uids(char **buf, uid_t* uids, int count) {
- int pos = 0, k, inc;
+ int pos = 0, inc;
size_t size = (DECIMAL_STR_MAX(uid_t) + 1) * count + 1;
assert_se(*buf = malloc(size));
- for (k = 0; k < count; k++) {
+ for (int k = 0; k < count; k++) {
sprintf(*buf + pos, "%s"UID_FMT"%n", k > 0 ? " " : "", uids[k], &inc);
pos += inc;
}
@@ -32,6 +34,10 @@ static char* format_uids(char **buf, uid_t* uids, int count) {
return *buf;
}
+static const char *e(int r) {
+ return r == 0 ? "OK" : errno_to_name(r);
+}
+
static void test_login(void) {
_cleanup_close_pair_ int pair[2] = { -1, -1 };
_cleanup_free_ char *pp = NULL, *qq = NULL,
@@ -41,65 +47,71 @@ static void test_login(void) {
*seat = NULL, *session = NULL,
*unit = NULL, *user_unit = NULL, *slice = NULL;
int r;
- uid_t u, u2;
- char *t, **seats, **sessions;
+ uid_t u, u2 = UID_INVALID;
+ char *t, **seats = NULL, **sessions = NULL;
r = sd_pid_get_unit(0, &unit);
- assert_se(r >= 0 || r == -ENODATA);
- log_info("sd_pid_get_unit(0, …) → \"%s\"", strna(unit));
+ log_info("sd_pid_get_unit(0, …) → %s / \"%s\"", e(r), strnull(unit));
+ assert_se(IN_SET(r, 0, -ENODATA));
r = sd_pid_get_user_unit(0, &user_unit);
- assert_se(r >= 0 || r == -ENODATA);
- log_info("sd_pid_get_user_unit(0, …) → \"%s\"", strna(user_unit));
+ log_info("sd_pid_get_user_unit(0, …) → %s / \"%s\"", e(r), strnull(user_unit));
+ assert_se(IN_SET(r, 0, -ENODATA));
r = sd_pid_get_slice(0, &slice);
- assert_se(r >= 0 || r == -ENODATA);
- log_info("sd_pid_get_slice(0, …) → \"%s\"", strna(slice));
+ log_info("sd_pid_get_slice(0, …) → %s / \"%s\"", e(r), strnull(slice));
+ assert_se(IN_SET(r, 0, -ENODATA));
+
+ r = sd_pid_get_owner_uid(0, &u2);
+ log_info("sd_pid_get_owner_uid(0, …) → %s / "UID_FMT, e(r), u2);
+ assert_se(IN_SET(r, 0, -ENODATA));
r = sd_pid_get_session(0, &session);
- if (r < 0) {
- log_warning_errno(r, "sd_pid_get_session(0, …): %m");
- if (r == -ENODATA)
- log_info("Seems we are not running in a session, skipping some tests.");
- } else {
- log_info("sd_pid_get_session(0, …) → \"%s\"", session);
-
- assert_se(sd_pid_get_owner_uid(0, &u2) == 0);
- log_info("sd_pid_get_owner_uid(0, …) → "UID_FMT, u2);
-
- assert_se(sd_pid_get_cgroup(0, &cgroup) == 0);
- log_info("sd_pid_get_cgroup(0, …) → \"%s\"", cgroup);
-
- r = sd_uid_get_display(u2, &display_session);
- assert_se(r >= 0 || r == -ENODATA);
- log_info("sd_uid_get_display("UID_FMT", …) → \"%s\"",
- u2, strnull(display_session));
-
- assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0);
- sd_peer_get_session(pair[0], &pp);
- sd_peer_get_session(pair[1], &qq);
- assert_se(streq_ptr(pp, qq));
-
- r = sd_uid_get_sessions(u2, false, &sessions);
+ log_info("sd_pid_get_session(0, …) → %s / \"%s\"", e(r), strnull(session));
+
+ r = sd_pid_get_cgroup(0, &cgroup);
+ log_info("sd_pid_get_cgroup(0, …) → %s / \"%s\"", e(r), strnull(cgroup));
+ assert_se(r == 0);
+
+ r = sd_uid_get_display(u2, &display_session);
+ log_info("sd_uid_get_display("UID_FMT", …) → %s / \"%s\"", u2, e(r), strnull(display_session));
+ if (u2 == UID_INVALID)
+ assert_se(r == -EINVAL);
+ else
+ assert_se(IN_SET(r, 0, -ENODATA));
+
+ assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0);
+ sd_peer_get_session(pair[0], &pp);
+ sd_peer_get_session(pair[1], &qq);
+ assert_se(streq_ptr(pp, qq));
+
+ r = sd_uid_get_sessions(u2, false, &sessions);
+ assert_se(t = strv_join(sessions, " "));
+ log_info("sd_uid_get_sessions("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
+ if (u2 == UID_INVALID)
+ assert_se(r == -EINVAL);
+ else {
assert_se(r >= 0);
assert_se(r == (int) strv_length(sessions));
- assert_se(t = strv_join(sessions, " "));
- strv_free(sessions);
- log_info("sd_uid_get_sessions("UID_FMT", …) → [%i] \"%s\"", u2, r, t);
- free(t);
+ }
+ sessions = strv_free(sessions);
+ free(t);
- assert_se(r == sd_uid_get_sessions(u2, false, NULL));
+ assert_se(r == sd_uid_get_sessions(u2, false, NULL));
- r = sd_uid_get_seats(u2, false, &seats);
+ r = sd_uid_get_seats(u2, false, &seats);
+ assert_se(t = strv_join(seats, " "));
+ log_info("sd_uid_get_seats("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
+ if (u2 == UID_INVALID)
+ assert_se(r == -EINVAL);
+ else {
assert_se(r >= 0);
assert_se(r == (int) strv_length(seats));
- assert_se(t = strv_join(seats, " "));
- strv_free(seats);
- log_info("sd_uid_get_seats("UID_FMT", …) → [%i] \"%s\"", u2, r, t);
- free(t);
-
- assert_se(r == sd_uid_get_seats(u2, false, NULL));
}
+ seats = strv_free(seats);
+ free(t);
+
+ assert_se(r == sd_uid_get_seats(u2, false, NULL));
if (session) {
r = sd_session_is_active(session);
@@ -111,7 +123,7 @@ static void test_login(void) {
log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r));
r = sd_session_get_state(session, &state);
- assert_se(r >= 0);
+ assert_se(r == 0);
log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state);
assert_se(sd_session_get_uid(session, &u) >= 0);
@@ -125,16 +137,16 @@ static void test_login(void) {
log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class);
r = sd_session_get_display(session, &display);
- assert_se(r >= 0 || r == -ENODATA);
+ assert_se(IN_SET(r, 0, -ENODATA));
log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display));
r = sd_session_get_remote_user(session, &remote_user);
- assert_se(r >= 0 || r == -ENODATA);
+ assert_se(IN_SET(r, 0, -ENODATA));
log_info("sd_session_get_remote_user(\"%s\") → \"%s\"",
session, strna(remote_user));
r = sd_session_get_remote_host(session, &remote_host);
- assert_se(r >= 0 || r == -ENODATA);
+ assert_se(IN_SET(r, 0, -ENODATA));
log_info("sd_session_get_remote_host(\"%s\") → \"%s\"",
session, strna(remote_host));
@@ -160,7 +172,7 @@ static void test_login(void) {
assert_se(r == -ENODATA);
}
- assert_se(sd_uid_get_state(u, &state2) >= 0);
+ assert_se(sd_uid_get_state(u, &state2) == 0);
log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
}
@@ -172,11 +184,11 @@ static void test_login(void) {
assert_se(sd_uid_is_on_seat(u, 0, seat) > 0);
r = sd_seat_get_active(seat, &session2, &u2);
- assert_se(r >= 0);
+ assert_se(r == 0);
log_info("sd_seat_get_active(\"%s\", …) → \"%s\", "UID_FMT, seat, session2, u2);
r = sd_uid_is_on_seat(u, 1, seat);
- assert_se(r >= 0);
+ assert_se(IN_SET(r, 0, 1));
assert_se(!!r == streq(session, session2));
r = sd_seat_get_sessions(seat, &sessions, &uids, &n);
@@ -184,8 +196,8 @@ static void test_login(void) {
assert_se(r == (int) strv_length(sessions));
assert_se(t = strv_join(sessions, " "));
strv_free(sessions);
- log_info("sd_seat_get_sessions(\"%s\", …) → %i, \"%s\", [%i] {%s}",
- seat, r, t, n, format_uids(&buf, uids, n));
+ log_info("sd_seat_get_sessions(\"%s\", …) → %s, \"%s\", [%u] {%s}",
+ seat, e(r), t, n, format_uids(&buf, uids, n));
free(t);
assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r);
@@ -203,7 +215,7 @@ static void test_login(void) {
r = sd_seat_get_active(NULL, &t, NULL);
assert_se(IN_SET(r, 0, -ENODATA));
- log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s", strnull(t));
+ log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s / \"%s\"", e(r), strnull(t));
free(t);
r = sd_get_sessions(&sessions);
@@ -243,13 +255,11 @@ static void test_login(void) {
static void test_monitor(void) {
sd_login_monitor *m = NULL;
- unsigned n;
int r;
- r = sd_login_monitor_new("session", &m);
- assert_se(r >= 0);
+ assert_se(sd_login_monitor_new("session", &m) == 0);
- for (n = 0; n < 5; n++) {
+ for (unsigned n = 0; n < 5; n++) {
struct pollfd pollfd = {};
usec_t timeout, nw;

View File

@ -0,0 +1,198 @@
From 7955f053c498a70616ac6c4d57c0fd47dfa8e5ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 7 Oct 2020 11:15:05 +0200
Subject: [PATCH] pager: make pager secure when under euid is changed or
explicitly requested
The variable is renamed to SYSTEMD_PAGERSECURE (because it's not just about
less now), and we automatically enable secure mode in certain cases, but not
otherwise.
This approach is more nuanced, but should provide a better experience for
users:
- Previusly we would set LESSSECURE=1 and trust the pager to make use of
it. But this has an effect only on less. We need to not start pagers which
are insecure when in secure mode. In particular more is like that and is a
very popular pager.
- We don't enable secure mode always, which means that those other pagers can
reasonably used.
- We do the right thing by default, but the user has ultimate control by
setting SYSTEMD_PAGERSECURE.
Fixes #5666.
v2:
- also check $PKEXEC_UID
v3:
- use 'sd_pid_get_owner_uid() != geteuid()' as the condition
(cherry picked from commit 0a42426d797406b4b01a0d9c13bb759c2629d108)
Resolves: #2175624
---
man/less-variables.xml | 28 ++++++++++++++---
meson.build | 3 +-
src/basic/pager.c | 69 +++++++++++++++++++++++++++---------------
3 files changed, 69 insertions(+), 31 deletions(-)
diff --git a/man/less-variables.xml b/man/less-variables.xml
index 9dad4247da..5f3a53c8dd 100644
--- a/man/less-variables.xml
+++ b/man/less-variables.xml
@@ -37,12 +37,30 @@
</varlistentry>
<varlistentry id='lesssecure'>
- <term><varname>$SYSTEMD_LESSSECURE</varname></term>
+ <term><varname>$SYSTEMD_PAGERSECURE</varname></term>
- <listitem><para>Takes a boolean argument. Overrides the <varname>$LESSSECURE</varname> environment
- variable when invoking the pager, which controls the "secure" mode of less (which disables commands
- such as <literal>|</literal> which allow to easily shell out to external command lines). By default
- less secure mode is enabled, with this setting it may be disabled.</para></listitem>
+ <listitem><para>Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if
+ false, disabled. If <varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, secure mode is enabled
+ if the effective UID is not the same as the owner of the login session, see <citerefentry
+ project='man-pages'><refentrytitle>geteuid</refentrytitle><manvolnum>2</manvolnum></citerefentry> and
+ <citerefentry><refentrytitle>sd_pid_get_owner_uid</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ In secure mode, <option>LESSSECURE=1</option> will be set when invoking the pager, and the pager shall
+ disable commands that open or create new files or start new subprocesses. When
+ <varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, pagers which are not known to implement
+ secure mode will not be used. (Currently only
+ <citerefentry><refentrytitle>less</refentrytitle><manvolnum>1</manvolnum></citerefentry> implements
+ secure mode.)</para>
+
+ <para>Note: when commands are invoked with elevated privileges, for example under <citerefentry
+ project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
+ <citerefentry
+ project='die-net'><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry>, care
+ must be taken to ensure that unintended interactive features are not enabled. "Secure" mode for the
+ pager may be enabled automatically as describe above. Setting <varname>SYSTEMD_PAGERSECURE=0</varname>
+ or not removing it from the inherited environment allows the user to invoke arbitrary commands. Note
+ that if the <varname>$SYSTEMD_PAGER</varname> or <varname>$PAGER</varname> variables are to be
+ honoured, <varname>$SYSTEMD_PAGERSECURE</varname> must be set too. It might be reasonable to completly
+ disable the pager using <option>--no-pager</option> instead.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
diff --git a/meson.build b/meson.build
index 673800a1a7..d986dd24ac 100644
--- a/meson.build
+++ b/meson.build
@@ -1467,7 +1467,8 @@ test_dlopen = executable(
'test-dlopen',
test_dlopen_c,
include_directories : includes,
- link_with : [libbasic],
+ link_with : [libsystemd_static,
+ libbasic],
dependencies : [libdl])
foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
diff --git a/src/basic/pager.c b/src/basic/pager.c
index 4efb01c483..c7e101235d 100644
--- a/src/basic/pager.c
+++ b/src/basic/pager.c
@@ -10,6 +10,8 @@
#include <sys/prctl.h>
#include <unistd.h>
+#include "sd-login.h"
+
#include "copy.h"
#include "env-util.h"
#include "fd-util.h"
@@ -79,7 +81,7 @@ int pager_open(bool no_pager, bool jump_to_end) {
if (r < 0)
return r;
if (r == 0) {
- const char* less_opts, *less_charset;
+ const char* less_opts, *less_charset, *exe;
/* In the child start the pager */
@@ -105,39 +107,56 @@ int pager_open(bool no_pager, bool jump_to_end) {
_exit(EXIT_FAILURE);
/* People might invoke us from sudo, don't needlessly allow less to be a way to shell out
- * privileged stuff. */
- r = getenv_bool("SYSTEMD_LESSSECURE");
- if (r == 0) { /* Remove env var if off */
- if (unsetenv("LESSSECURE") < 0) {
- log_error_errno(errno, "Failed to uset environment variable LESSSECURE: %m");
- _exit(EXIT_FAILURE);
- }
- } else {
- /* Set env var otherwise */
+ * privileged stuff. If the user set $SYSTEMD_PAGERSECURE, trust their configuration of the
+ * pager. If they didn't, use secure mode when under euid is changed. If $SYSTEMD_PAGERSECURE
+ * wasn't explicitly set, and we autodetect the need for secure mode, only use the pager we
+ * know to be good. */
+ int use_secure_mode = getenv_bool("SYSTEMD_PAGERSECURE");
+ bool trust_pager = use_secure_mode >= 0;
+ if (use_secure_mode == -ENXIO) {
+ uid_t uid;
+
+ r = sd_pid_get_owner_uid(0, &uid);
if (r < 0)
- log_warning_errno(r, "Unable to parse $SYSTEMD_LESSSECURE, ignoring: %m");
+ log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m");
+
+ use_secure_mode = r < 0 || uid != geteuid();
+
+ } else if (use_secure_mode < 0) {
+ log_warning_errno(use_secure_mode, "Unable to parse $SYSTEMD_PAGERSECURE, assuming true: %m");
+ use_secure_mode = true;
+ }
- if (setenv("LESSSECURE", "1", 1) < 0) {
- log_error_errno(errno, "Failed to set environment variable LESSSECURE: %m");
- _exit(EXIT_FAILURE);
- }
+ /* We generally always set variables used by less, even if we end up using a different pager.
+ * They shouldn't hurt in any case, and ideally other pagers would look at them too. */
+ if (use_secure_mode)
+ r = setenv("LESSSECURE", "1", 1);
+ else
+ r = unsetenv("LESSSECURE");
+ if (r < 0) {
+ log_error_errno(errno, "Failed to adjust environment variable LESSSECURE: %m");
+ _exit(EXIT_FAILURE);
}
- if (pager) {
+ if (trust_pager && pager) { /* The pager config might be set globally, and we cannot
+ * know if the user adjusted it to be appropriate for the
+ * secure mode. Thus, start the pager specified through
+ * envvars only when $SYSTEMD_PAGERSECURE was explicitly set
+ * as well. */
execlp(pager, pager, NULL);
execl("/bin/sh", "sh", "-c", pager, NULL);
}
- /* Debian's alternatives command for pagers is
- * called 'pager'. Note that we do not call
- * sensible-pagers here, since that is just a
- * shell script that implements a logic that
- * is similar to this one anyway, but is
- * Debian-specific. */
- execlp("pager", "pager", NULL);
+ /* Debian's alternatives command for pagers is called 'pager'. Note that we do not call
+ * sensible-pagers here, since that is just a shell script that implements a logic that is
+ * similar to this one anyway, but is Debian-specific. */
+ FOREACH_STRING(exe, "pager", "less", "more") {
+ /* Only less implements secure mode right now. */
+ if (use_secure_mode && !streq(exe, "less"))
+ continue;
- execlp("less", "less", NULL);
- execlp("more", "more", NULL);
+ execlp(exe, exe, NULL);
+ }
pager_fallback();
/* not reached */

View File

@ -0,0 +1,49 @@
From c4c9126b1d64fbe77ef1a74b464646711ced8f83 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 30 Mar 2023 17:16:44 +0200
Subject: [PATCH] ci: trigger differential-shellcheck workflow on push
Fixes: redhat-plumbers-in-action/differential-shellcheck#215
rhel-only
Related: #2179309
---
.github/workflows/differential-shellcheck.yml | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml
index 4399f0bc64..19634c07b3 100644
--- a/.github/workflows/differential-shellcheck.yml
+++ b/.github/workflows/differential-shellcheck.yml
@@ -3,9 +3,13 @@
name: Differential ShellCheck
on:
+ push:
+ branches:
+ - main
+ - rhel-8.*.0
pull_request:
branches:
- - master
+ - main
- rhel-8.*.0
permissions:
@@ -18,7 +22,6 @@ jobs:
permissions:
security-events: write
- pull-requests: write
steps:
- name: Repository checkout
@@ -27,6 +30,6 @@ jobs:
fetch-depth: 0
- name: Differential ShellCheck
- uses: redhat-plumbers-in-action/differential-shellcheck@v3
+ uses: redhat-plumbers-in-action/differential-shellcheck@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -0,0 +1,34 @@
From 5e5c1425db0982c9d5e5d51e164895aa780f76b2 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 30 Mar 2023 17:18:17 +0200
Subject: [PATCH] ci: codeql `master` -> `main`
rhel-only
Related: #2179309
---
.github/workflows/codeql.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index c5426d5686..cc4fcf4754 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -7,7 +7,7 @@ name: "CodeQL"
on:
pull_request:
branches:
- - master
+ - main
- rhel-*
paths:
- '**/meson.build'
@@ -17,7 +17,7 @@ on:
- 'tools/**'
push:
branches:
- - master
+ - main
- rhel-*
permissions:

View File

@ -0,0 +1,30 @@
From d9e2735b88513e3b3af9ab468f4d2ba0f6bec64d Mon Sep 17 00:00:00 2001
From: Dan Streetman <ddstreet@canonical.com>
Date: Fri, 23 Oct 2020 15:50:28 -0400
Subject: [PATCH] test: ignore ENOMEDIUM error from sd_pid_get_cgroup()
Ubuntu builds on the Launchpad infrastructure run inside a chroot that does
not have the sysfs cgroup dirs mounted, so this call will return ENOMEDIUM
from cg_unified_cached() during the build-time testing, for example when
building the package in a Launchpad PPA.
(cherry picked from commit 352ab9d74049b4ac694fdba1a6e67339f12ded93)
Resolves: #2175622
---
src/libsystemd/sd-login/test-login.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index 60ef889ec0..d24a04ccc8 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -71,7 +71,7 @@ static void test_login(void) {
r = sd_pid_get_cgroup(0, &cgroup);
log_info("sd_pid_get_cgroup(0, …) → %s / \"%s\"", e(r), strnull(cgroup));
- assert_se(r == 0);
+ assert_se(IN_SET(r, 0, -ENOMEDIUM));
r = sd_uid_get_display(u2, &display_session);
log_info("sd_uid_get_display("UID_FMT", …) → %s / \"%s\"", u2, e(r), strnull(display_session));

View File

@ -0,0 +1,42 @@
From d0e8ca2dcc1467a9e28c569e0dc608e5426bae79 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Mon, 24 Apr 2023 15:25:02 +0200
Subject: [PATCH] ci(Mergify): drop requirements on linting workflows
CodeQL and DifferentialShellCheck workflows aren't run for all PRs on all branches.
This results in Mergify incorrectly labeling PRs with `needs-ci` label.
Lets drop the requirements on these workflows.
rhel-only
Related: #2179309
---
.mergify.yml | 8 --------
1 file changed, 8 deletions(-)
diff --git a/.mergify.yml b/.mergify.yml
index a5eed6a82a..624eb7291d 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -11,10 +11,6 @@ pull_request_rules:
- -check-success=build (stream8, GCC_ASAN)
# CentOS Stream CI
- -check-success=CentOS CI (CentOS Stream 8)
- # CodeQL
- - -check-success=CodeQL
- # Other
- - -check-success=Differential ShellCheck
actions:
label:
add:
@@ -30,10 +26,6 @@ pull_request_rules:
- check-success=build (stream8, GCC_ASAN)
# CentOS Stream CI
- check-success=CentOS CI (CentOS Stream 8)
- # CodeQL
- - check-success=CodeQL
- # Other
- - check-success=Differential ShellCheck
actions:
label:
remove:

View File

@ -0,0 +1,51 @@
From a81ace51e1efa2313fcad18f2ef5c6c6cd167240 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Mon, 24 Apr 2023 15:13:08 +0200
Subject: [PATCH] ci: workflow for gathering metadata for source-git automation
Workflow gathers metadata like pull request numbers and information about commits.
This metadata is used for commit validation and other actions.
This workflow also triggers for rest of the source-git automation workflows.
rhel-only
Related: #2179309
---
.github/workflows/gather-metadata.yml | 28 +++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 .github/workflows/gather-metadata.yml
diff --git a/.github/workflows/gather-metadata.yml b/.github/workflows/gather-metadata.yml
new file mode 100644
index 0000000000..f432f41811
--- /dev/null
+++ b/.github/workflows/gather-metadata.yml
@@ -0,0 +1,28 @@
+name: Gather Pull Request Metadata
+on:
+ pull_request:
+ types: [ opened, reopened, synchronize ]
+ branches:
+ - main
+ - rhel-8.*.0
+
+permissions:
+ contents: read
+
+jobs:
+ gather-metadata:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Repository checkout
+ uses: actions/checkout@v3
+
+ - id: Metadata
+ name: Gather Pull Request Metadata
+ uses: redhat-plumbers-in-action/gather-pull-request-metadata@v1
+
+ - name: Upload artifact with gathered metadata
+ uses: actions/upload-artifact@v3
+ with:
+ name: pr-metadata
+ path: ${{ steps.Metadata.outputs.metadata-file }}

View File

@ -0,0 +1,103 @@
From 7e0eb456a99229d19b8e42491c1ddb7b8050903f Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Mon, 24 Apr 2023 15:15:00 +0200
Subject: [PATCH] ci: first part of the source-git automation - commit linter
Add a GitHub Workflow that is triggered on `workflow_run` events.
It uses metadata provided by `redhat-plumbers-in-action/gather-pull-request-metadata`
GitHub Action to get the PR number and the commit metadata.
The commit metadata is then used to check if the commit message contains
all required information (tracker and upstream reference). GitHub Action
responsible for commit verification `redhat-plumbers-in-action/advanced-commit-linter`
is configured via the `advanced-commit-linter.yml` file.
rhel-only
Related: #2179309
---
.github/advanced-commit-linter.yml | 23 +++++++++++
.github/workflows/source-git-automation.yml | 45 +++++++++++++++++++++
2 files changed, 68 insertions(+)
create mode 100644 .github/advanced-commit-linter.yml
create mode 100644 .github/workflows/source-git-automation.yml
diff --git a/.github/advanced-commit-linter.yml b/.github/advanced-commit-linter.yml
new file mode 100644
index 0000000000..491836abbb
--- /dev/null
+++ b/.github/advanced-commit-linter.yml
@@ -0,0 +1,23 @@
+policy:
+ cherry-pick:
+ upstream:
+ - github: systemd/systemd
+ - github: systemd/systemd-stable
+ exception:
+ note:
+ - rhel-only
+ tracker:
+ - keyword:
+ - 'Resolves: #?'
+ - 'Related: #?'
+ - 'Reverts: #?'
+ issue-format:
+ - '\d+$'
+ url: 'https://bugzilla.redhat.com/show_bug.cgi?id='
+ - keyword:
+ - 'Resolves: '
+ - 'Related: '
+ - 'Reverts: '
+ issue-format:
+ - 'RHEL-\d+$'
+ url: 'https://issues.redhat.com/browse/'
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
new file mode 100644
index 0000000000..140f21b116
--- /dev/null
+++ b/.github/workflows/source-git-automation.yml
@@ -0,0 +1,45 @@
+name: Source git Automation
+on:
+ workflow_run:
+ workflows: [ Gather Pull Request Metadata ]
+ types:
+ - completed
+
+permissions:
+ contents: read
+
+jobs:
+ download-metadata:
+ if: >
+ github.event.workflow_run.event == 'pull_request' &&
+ github.event.workflow_run.conclusion == 'success'
+ runs-on: ubuntu-latest
+
+ outputs:
+ pr-metadata: ${{ steps.Artifact.outputs.pr-metadata-json }}
+
+ steps:
+ - id: Artifact
+ name: Download Artifact
+ uses: redhat-plumbers-in-action/download-artifact@v1
+ with:
+ name: pr-metadata
+
+ commit-linter:
+ needs: [ download-metadata ]
+ runs-on: ubuntu-latest
+
+ outputs:
+ validated-pr-metadata: ${{ steps.commit-linter.outputs.validated-pr-metadata }}
+
+ permissions:
+ statuses: write
+ pull-requests: write
+
+ steps:
+ - id: commit-linter
+ name: Lint Commits
+ uses: redhat-plumbers-in-action/advanced-commit-linter@v1
+ with:
+ pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
+ token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -0,0 +1,31 @@
From f86a51500b5aa9288dbb2800e0a1f63ad863bd8f Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 26 Apr 2023 20:07:10 +0200
Subject: [PATCH] pstore: fix crash and forward dummy arguments instead of NULL
[msekleta: in our version of systemd "const char path*" argument of
path_join() can't be NULL. Here we don't really want any subdirs paths
passed into move_file(), but we can't just pass NULL pointers because
they will be forwarded to path_join(). Hence, let's just pass "/"
instead.]
rhel-only
Related: #2190151
---
src/pstore/pstore.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 9f61e8f7f8..5335c9f92d 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -366,7 +366,7 @@ static int run(int argc, char *argv[]) {
/* Move left over files out of pstore */
for (size_t n = 0; n < list.n_entries; n++)
- (void) move_file(&list.entries[n], NULL, NULL);
+ (void) move_file(&list.entries[n], "/", "/");
return 0;
}

View File

@ -0,0 +1,45 @@
From 6fdc5f71ee28829bdedb159e7d138f7a1b447fb2 Mon Sep 17 00:00:00 2001
From: Filipe Brandenburger <filbranden@gmail.com>
Date: Wed, 13 Nov 2019 10:46:08 -0800
Subject: [PATCH] test: Disable LUKS devices from initramfs in QEMU tests
We currently use the host's kernel and initramfs in our QEMU tests.
If the host is running on an encrypted LUKS partition, then the initramfs
will have a crypttab setup looking for the particular root disk it needs to
encrypt before booting into the system.
However, this disk obviously doesn't exist in our QEMU VM, so it turns out
our tests end up waiting for this device to become available, which will
never actually happen, and boot hangs for 90s until that service times out.
[*** ] A start job is running for /dev/disk/by-uuid/01234567-abcd-1234-abcd-0123456789ab (20s / 1min 30s)
In order to prevent this issue, let's pass "rd.luks=0" to disable LUKS in
the initramfs only as part of our default kernel command-line in our QEMU
tests.
This is enough to disable this behavior and prevent the timeout, while at
the same time doesn't conflict with our tests that actually check for LUKS
behavior in the systemd running under test (such as TEST-02-CRYPTSETUP).
Tested: `sudo make -C TEST-02-CRYPTSETUP/ clean setup run`
(cherry picked from commit 14e0259b499c188de09040f2e5857a0193094d5a)
Related: #2190151
---
test/test-functions | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/test-functions b/test/test-functions
index e5d4d28a5f..a7b18991f4 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -154,6 +154,7 @@ fi
KERNEL_APPEND="$PARAMS \
root=/dev/sda1 \
raid=noautodetect \
+rd.luks=0 \
loglevel=2 \
init=$PATH_TO_INIT \
console=ttyS0 \

View File

@ -0,0 +1,37 @@
From 3aefa216bf5e8bcfaf5a628e9e06672e786ce9ea Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Fri, 28 Apr 2023 11:09:22 +0200
Subject: [PATCH] pstore: explicitly set the base when converting record ID
(cherry picked from commit a95d96a2430db171b40fc2e50589807236f8f746)
Related: #2190151
---
src/pstore/pstore.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 5335c9f92d..073fedb7d2 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -207,7 +207,7 @@ static int append_dmesg(PStoreEntry *pe, const char *subdir1, const char *subdir
static int process_dmesg_files(PStoreList *list) {
/* Move files, reconstruct dmesg.txt */
_cleanup_free_ char *erst_subdir = NULL;
- uint64_t last_record_id = 0;
+ unsigned long long last_record_id = 0;
/* When dmesg is written into pstore, it is done so in small chunks, whatever the exchange buffer
* size is with the underlying pstore backend (ie. EFI may be ~2KiB), which means an example
@@ -263,9 +263,9 @@ static int process_dmesg_files(PStoreList *list) {
} else if ((p = startswith(pe->dirent.d_name, "dmesg-erst-"))) {
/* For the ERST backend, the record is a monotonically increasing number, seeded as
* a timestamp. See linux/drivers/acpi/apei/erst.c in erst_writer(). */
- uint64_t record_id;
+ unsigned long long record_id;
- if (safe_atou64(p, &record_id) < 0)
+ if (safe_atollu_full(p, 10, &record_id) < 0)
continue;
if (last_record_id - 1 != record_id)
/* A discontinuity in the number has been detected, this current record id

View File

@ -0,0 +1,68 @@
From 7a76b2a073b5df72e9afc39dc6c0cce388e0a733 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Fri, 28 Apr 2023 11:50:33 +0200
Subject: [PATCH] pstore: avoid opening the dmesg.txt file if not requested
Even with Storage=journal we would still attempt to open the final
dmesg.txt file which causes a lot of noise in the journal:
```
[ 5.764111] H testsuite-82.sh[658]: + systemctl start systemd-pstore
[ 5.806385] H systemd[1]: Starting modprobe@efi_pstore.service...
[ 5.808656] H systemd[1]: modprobe@efi_pstore.service: Deactivated successfully.
[ 5.808971] H systemd[1]: Finished modprobe@efi_pstore.service.
[ 5.818845] H kernel: audit: type=1130 audit(1682630623.637:114): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=kernel msg='unit=modprobe@efi_pstore comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? termin>
[ 5.818865] H kernel: audit: type=1131 audit(1682630623.637:115): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=kernel msg='unit=modprobe@efi_pstore comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? termin>
[ 5.816052] H systemd[1]: Starting systemd-pstore.service...
[ 5.840703] H systemd-pstore[806]: PStore dmesg-efi-168263062313014.
[ 5.841239] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.841428] H systemd-pstore[806]: PStore dmesg-efi-168263062312014.
[ 5.841575] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.841712] H systemd-pstore[806]: PStore dmesg-efi-168263062311014.
[ 5.841839] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.841989] H systemd-pstore[806]: PStore dmesg-efi-168263062310014.
[ 5.842141] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.842274] H systemd-pstore[806]: PStore dmesg-efi-168263062309014.
[ 5.842423] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.842589] H systemd-pstore[806]: PStore dmesg-efi-168263062308014.
[ 5.842722] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.842865] H systemd-pstore[806]: PStore dmesg-efi-168263062307014.
[ 5.843003] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.843153] H systemd-pstore[806]: PStore dmesg-efi-168263062306014.
[ 5.843280] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.843434] H systemd-pstore[806]: PStore dmesg-efi-168263062305014.
[ 5.843570] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.843702] H systemd-pstore[806]: PStore dmesg-efi-168263062304014.
[ 5.843831] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.843958] H systemd-pstore[806]: PStore dmesg-efi-168263062303014.
[ 5.844093] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.844250] H systemd-pstore[806]: PStore dmesg-efi-168263062302014.
[ 5.844412] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.844619] H systemd-pstore[806]: PStore dmesg-efi-168263062301014.
[ 5.844781] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.844956] H systemd-pstore[806]: PStore dmesg-efi-168263062300014.
[ 5.845168] H systemd-pstore[806]: Failed to open file /var/lib/systemd/pstore/1682630623/014/dmesg.txt: Operation not permitted
[ 5.851101] H systemd[1]: Finished systemd-pstore.service.
```
(cherry picked from commit ad5980803adac8dc1cf980447a07cb18962c238b)
Related: #2190151
---
src/pstore/pstore.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 073fedb7d2..9367071833 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -181,6 +181,9 @@ static int append_dmesg(PStoreEntry *pe, const char *subdir1, const char *subdir
assert(pe);
+ if (arg_storage != PSTORE_STORAGE_EXTERNAL)
+ return 0;
+
if (pe->content_size == 0)
return 0;

View File

@ -0,0 +1,341 @@
From 06b0704a8bb41fa9a496f5671e191dc7b6c7ed9b Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Wed, 3 May 2023 15:25:18 +0200
Subject: [PATCH] test: add a couple of tests for systemd-pstore
Based on:
- 6858e32d730fd5574eaa3d7fbf4cb12aacaea336
- edea0d6ac57610b7af603b833b19a846327e3638
Related: #2190151
---
test/TEST-74-AUX-UTILS/Makefile | 1 +
test/TEST-74-AUX-UTILS/test.sh | 48 +++++
test/TEST-74-AUX-UTILS/testsuite.pstore.sh | 218 +++++++++++++++++++++
test/TEST-74-AUX-UTILS/testsuite.sh | 14 ++
test/test-functions | 2 +-
5 files changed, 282 insertions(+), 1 deletion(-)
create mode 120000 test/TEST-74-AUX-UTILS/Makefile
create mode 100755 test/TEST-74-AUX-UTILS/test.sh
create mode 100755 test/TEST-74-AUX-UTILS/testsuite.pstore.sh
create mode 100755 test/TEST-74-AUX-UTILS/testsuite.sh
diff --git a/test/TEST-74-AUX-UTILS/Makefile b/test/TEST-74-AUX-UTILS/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-74-AUX-UTILS/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-74-AUX-UTILS/test.sh b/test/TEST-74-AUX-UTILS/test.sh
new file mode 100755
index 0000000000..fead257337
--- /dev/null
+++ b/test/TEST-74-AUX-UTILS/test.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+set -e
+TEST_DESCRIPTION="Tests for auxiliary utilities"
+
+. $TEST_BASE_DIR/test-functions
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/bin/bash -x /testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+ cp testsuite*.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-74-AUX-UTILS/testsuite.pstore.sh b/test/TEST-74-AUX-UTILS/testsuite.pstore.sh
new file mode 100755
index 0000000000..3a61b8f8f8
--- /dev/null
+++ b/test/TEST-74-AUX-UTILS/testsuite.pstore.sh
@@ -0,0 +1,218 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+if systemd-detect-virt -cq; then
+ echo "Running in a container, skipping the systemd-pstore test..."
+ exit 0
+fi
+
+DUMMY_DMESG_1="$(mktemp)"
+cat >"$DUMMY_DMESG_1" <<\EOF
+6,17159,5340096332127,-;usb 1-4: USB disconnect, device number 124
+6,17160,5340109662397,-;input: WH-1000XM3 (AVRCP) as /devices/virtual/input/input293
+6,17161,5343126458360,-;loop0: detected capacity change from 0 to 3145728
+6,17162,5343126766065,-; loop0: p1 p2
+6,17163,5343126815038,-;EXT4-fs (loop0p1): mounted filesystem with ordered data mode. Quota mode: none.
+6,17164,5343158037334,-;EXT4-fs (loop0p1): unmounting filesystem.
+6,17165,5343158072598,-;loop0: detected capacity change from 0 to 3145728
+6,17166,5343158073563,-; loop0: p1 p2
+6,17167,5343158074325,-; loop0: p1 p2
+6,17168,5343158140859,-;EXT4-fs (loop0p1): mounted filesystem with ordered data mode. Quota mode: none.
+6,17169,5343158182977,-;EXT4-fs (loop0p1): unmounting filesystem.
+6,17170,5343158700241,-;loop0: detected capacity change from 0 to 3145728
+6,17171,5343158700439,-; loop0: p1 p2
+6,17172,5343158701120,-; loop0: p1 p2
+EOF
+
+DUMMY_DMESG_2="$(mktemp)"
+cat >"$DUMMY_DMESG_2" <<\EOF
+Nechť již hříšné saxofony ďáblů rozezvučí síň úděsnými tóny waltzu, tanga a quickstepu.
+Příliš žluťoučký kůň úpěl ďábelské ódy.
+Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů.
+Vyciď křišťálový nůž, ó učiň úděsné líbivým!
+Loď čeří kýlem tůň obzvlášť v Grónské úžině
+Ó, náhlý déšť již zvířil prach a čilá laň teď běží s houfcem gazel k úkrytům.
+Vypätá dcéra grófa Maxwella s IQ nižším ako kôň núti čeľaď hrýzť hŕbu jabĺk.
+Kŕdeľ šťastných ďatľov učí pri ústí Váhu mĺkveho koňa obhrýzať kôru a žrať čerstvé mäso.
+Stróż pchnął kość w quiz gędźb vel fax myjń.
+Portez ce vieux whisky au juge blond qui fume!
+EOF
+
+file_count() { find "${1:?}" -type f | wc -l; }
+file_size() { wc -l <"${1:?}"; }
+random_efi_timestamp() { printf "%0.10d" "$((1000000000 + RANDOM))"; }
+
+# The dmesg- filename contains the backend-type and the Common Platform Error Record, CPER,
+# record id, a 64-bit number.
+#
+# Files are processed in reverse lexigraphical order so as to properly reconstruct original dmesg.
+
+prepare_efi_logs() {
+ local file="${1:?}"
+ local timestamp="${2:?}"
+ local chunk count filename
+
+ # For the EFI backend, the 3 least significant digits of record id encodes a
+ # "count" number, the next 2 least significant digits for the dmesg part
+ # (chunk) number, and the remaining digits as the timestamp. See
+ # linux/drivers/firmware/efi/efi-pstore.c in efi_pstore_write().
+ count="$(file_size "$file")"
+ chunk=0
+ # The sed in the process substitution below just reverses the file
+ while read -r line; do
+ filename="$(printf "dmesg-efi-%0.10d%0.2d%0.3d" "$timestamp" "$chunk" "$count")"
+ echo "$line" >"/sys/fs/pstore/$filename"
+ chunk=$((chunk + 1))
+ done < <(sed '1!G;h;$!d' "$file")
+
+ if [[ "$chunk" -eq 0 ]]; then
+ echo >&2 "No dmesg-efi files were created"
+ exit 1
+ fi
+}
+
+prepare_erst_logs() {
+ local file="${1:?}"
+ local start_id="${2:?}"
+ local id filename
+
+ # For the ERST backend, the record is a monotonically increasing number, seeded as
+ # a timestamp. See linux/drivers/acpi/apei/erst.c in erst_writer().
+ id="$start_id"
+ # The sed in the process substitution below just reverses the file
+ while read -r line; do
+ filename="$(printf "dmesg-erst-%0.16d" "$id")"
+ echo "$line" >"/sys/fs/pstore/$filename"
+ id=$((id + 1))
+ done < <(sed '1!G;h;$!d' "$file")
+
+ if [[ "$id" -eq "$start_id" ]]; then
+ echo >&2 "No dmesg-erst files were created"
+ exit 1
+ fi
+
+ # ID of the last dmesg file will be the ID of the erst subfolder
+ echo "$((id - 1))"
+}
+
+prepare_pstore_config() {
+ local storage="${1:?}"
+ local unlink="${2:?}"
+
+ systemctl stop systemd-pstore
+
+ rm -fr /sys/fs/pstore/* /var/lib/systemd/pstore/*
+
+ mkdir -p /run/systemd/pstore.conf.d
+ cat >"/run/systemd/pstore.conf.d/99-test.conf" <<EOF
+[PStore]
+Storage=$storage
+Unlink=$unlink
+EOF
+
+ systemd-analyze cat-config systemd/pstore.conf | grep "$storage"
+ systemd-analyze cat-config systemd/pstore.conf | grep "$unlink"
+}
+
+start_pstore() {
+ JOURNAL_CURSOR="$(journalctl -q -n 0 --show-cursor | awk '{ print $3 }')"
+ systemctl start systemd-pstore
+ journalctl --sync
+}
+
+# To avoid having to depend on the VM providing the pstore, let's simulate
+# it using a simple bind mount
+PSTORE_DIR="$(mktemp -d)"
+mount --bind "${PSTORE_DIR:?}" "/sys/fs/pstore"
+
+# systemd-pstore is a no-op with Storage=none
+for unlink in yes no; do
+ : "Backend: N/A; Storage: none; Unlink: $unlink"
+ timestamp="$(random_efi_timestamp)"
+ prepare_pstore_config "none" "$unlink"
+ prepare_efi_logs "$DUMMY_DMESG_1" "$timestamp"
+ old_count="$(file_count /sys/fs/pstore/)"
+ start_pstore
+ [[ "$(file_count /sys/fs/pstore)" -ge "$old_count" ]]
+ [[ "$(file_count /var/lib/systemd/pstore/)" -eq 0 ]]
+
+ : "Backend: EFI; Storage: external; Unlink: $unlink"
+ timestamp="$(random_efi_timestamp)"
+ prepare_pstore_config "external" "$unlink"
+ prepare_efi_logs "$DUMMY_DMESG_1" "$timestamp"
+ [[ "$unlink" == yes ]] && exp_count=0 || exp_count="$(file_count /sys/fs/pstore/)"
+ start_pstore
+ [[ "$(file_count /sys/fs/pstore)" -ge "$exp_count" ]]
+ [[ "$(file_count /var/lib/systemd/pstore/)" -ne 0 ]]
+ # We always log to journal
+ diff "$DUMMY_DMESG_1" <(journalctl -o json --after-cursor="${JOURNAL_CURSOR:?}" | jq -r 'select(.FILE) | .FILE' | sed '/^$/d')
+ filename="$(printf "/var/lib/systemd/pstore/%s/%0.3d/dmesg.txt" "$timestamp" "$(file_size "$DUMMY_DMESG_1")")"
+ diff "$DUMMY_DMESG_1" "$filename"
+
+ : "Backend: EFI; Storage: external; Unlink: $unlink; multiple dmesg files"
+ timestamp_1="$(random_efi_timestamp)"
+ timestamp_2="$((timestamp_1 + 1))"
+ prepare_pstore_config "external" "$unlink"
+ prepare_efi_logs "$DUMMY_DMESG_1" "$timestamp_1"
+ prepare_efi_logs "$DUMMY_DMESG_2" "$timestamp_2"
+ # Add one "random" (non-dmesg) file as well
+ echo "hello world" >/sys/fs/pstore/foo.bar
+ [[ "$unlink" == yes ]] && exp_count=0 || exp_count="$(file_count /sys/fs/pstore/)"
+ start_pstore
+ [[ "$(file_count /sys/fs/pstore)" -ge "$exp_count" ]]
+ [[ "$(file_count /var/lib/systemd/pstore/)" -ne 0 ]]
+ filename_1="$(printf "/var/lib/systemd/pstore/%s/%0.3d/dmesg.txt" "$timestamp_1" "$(file_size "$DUMMY_DMESG_1")")"
+ diff "$DUMMY_DMESG_1" "$filename_1"
+ filename_2="$(printf "/var/lib/systemd/pstore/%s/%0.3d/dmesg.txt" "$timestamp_2" "$(file_size "$DUMMY_DMESG_2")")"
+ diff "$DUMMY_DMESG_2" "$filename_2"
+ grep "hello world" "/var/lib/systemd/pstore/foo.bar"
+
+ : "Backend: EFI; Storage: journal; Unlink: $unlink"
+ timestamp="$(random_efi_timestamp)"
+ prepare_pstore_config "journal" "$unlink"
+ prepare_efi_logs "$DUMMY_DMESG_1" "$timestamp"
+ [[ "$unlink" == yes ]] && exp_count=0 || exp_count="$(file_count /sys/fs/pstore/)"
+ start_pstore
+ [[ "$(file_count /sys/fs/pstore)" -ge "$exp_count" ]]
+ [[ "$(file_count /var/lib/systemd/pstore/)" -eq 0 ]]
+ diff "$DUMMY_DMESG_1" <(journalctl -o json --after-cursor="${JOURNAL_CURSOR:?}" | jq -r 'select(.FILE) | .FILE' | sed '/^$/d')
+
+ : "Backend: ERST; Storage: external; Unlink: $unlink"
+ prepare_pstore_config "external" "$unlink"
+ last_id="$(prepare_erst_logs "$DUMMY_DMESG_1" 0)"
+ [[ "$unlink" == yes ]] && exp_count=0 || exp_count="$(file_count /sys/fs/pstore/)"
+ start_pstore
+ [[ "$(file_count /sys/fs/pstore)" -ge "$exp_count" ]]
+ [[ "$(file_count /var/lib/systemd/pstore/)" -ne 0 ]]
+ # We always log to journal
+ diff "$DUMMY_DMESG_1" <(journalctl -o json --after-cursor="${JOURNAL_CURSOR:?}" | jq -r 'select(.FILE) | .FILE' | sed '/^$/d')
+ filename="$(printf "/var/lib/systemd/pstore/%0.16d/dmesg.txt" "$last_id")"
+ diff "$DUMMY_DMESG_1" "$filename"
+
+ : "Backend: ERST; Storage: external; Unlink: $unlink; multiple dmesg files"
+ prepare_pstore_config "external" "$unlink"
+ last_id_1="$(prepare_erst_logs "$DUMMY_DMESG_1" 0)"
+ last_id_2="$(prepare_erst_logs "$DUMMY_DMESG_2" "$((last_id_1 + 10))")"
+ # Add one "random" (non-dmesg) file as well
+ echo "hello world" >/sys/fs/pstore/foo.bar
+ [[ "$unlink" == yes ]] && exp_count=0 || exp_count="$(file_count /sys/fs/pstore/)"
+ start_pstore
+ [[ "$(file_count /sys/fs/pstore)" -ge "$exp_count" ]]
+ [[ "$(file_count /var/lib/systemd/pstore/)" -ne 0 ]]
+ filename_1="$(printf "/var/lib/systemd/pstore/%0.16d/dmesg.txt" "$last_id_1")"
+ diff "$DUMMY_DMESG_1" "$filename_1"
+ filename_2="$(printf "/var/lib/systemd/pstore/%0.16d/dmesg.txt" "$last_id_2")"
+ diff "$DUMMY_DMESG_2" "$filename_2"
+ grep "hello world" "/var/lib/systemd/pstore/foo.bar"
+
+ : "Backend: ERST; Storage: journal; Unlink: $unlink"
+ prepare_pstore_config "journal" "$unlink"
+ last_id="$(prepare_erst_logs "$DUMMY_DMESG_1" 0)"
+ [[ "$unlink" == yes ]] && exp_count=0 || exp_count="$(file_count /sys/fs/pstore/)"
+ start_pstore
+ [[ "$(file_count /sys/fs/pstore)" -ge "$exp_count" ]]
+ [[ "$(file_count /var/lib/systemd/pstore/)" -eq 0 ]]
+ diff "$DUMMY_DMESG_1" <(journalctl -o json --after-cursor="${JOURNAL_CURSOR:?}" | jq -r 'select(.FILE) | .FILE' | sed '/^$/d')
+done
diff --git a/test/TEST-74-AUX-UTILS/testsuite.sh b/test/TEST-74-AUX-UTILS/testsuite.sh
new file mode 100755
index 0000000000..13c767e490
--- /dev/null
+++ b/test/TEST-74-AUX-UTILS/testsuite.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+: >/failed
+
+for script in "${0%.sh}".*.sh; do
+ echo "Running $script"
+ "./$script"
+done
+
+touch /testok
+rm /failed
diff --git a/test/test-functions b/test/test-functions
index a7b18991f4..f0cf6f8575 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -23,7 +23,7 @@ fi
PATH_TO_INIT=$ROOTLIBDIR/systemd
-BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env mktemp mountpoint useradd userdel timeout"
+BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env mktemp mountpoint useradd userdel timeout jq wc awk diff"
DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find"
STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"

View File

@ -0,0 +1,29 @@
From ab5a221daca2783b73fd286f5410dbec905cabfa Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 19 May 2023 16:42:03 +0200
Subject: [PATCH] ci: update permissions for source-git automation workflows
The new version of `redhat-plumbers-in-action/advanced-commit-linter` requires new permission: `checks: write`.
https://github.com/redhat-plumbers-in-action/advanced-commit-linter/commit/f1bb35fcdeff83d40eb67b5e7c58baad6be689b2
rhel-only
Related: #2179309
---
.github/workflows/source-git-automation.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
index 140f21b116..e653e28a7f 100644
--- a/.github/workflows/source-git-automation.yml
+++ b/.github/workflows/source-git-automation.yml
@@ -33,7 +33,7 @@ jobs:
validated-pr-metadata: ${{ steps.commit-linter.outputs.validated-pr-metadata }}
permissions:
- statuses: write
+ checks: write
pull-requests: write
steps:

View File

@ -0,0 +1,130 @@
From 30cbb55a8d9fedf07d5c9d792849b723b856cd62 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
Date: Sun, 12 Feb 2023 12:15:08 +0000
Subject: [PATCH] sulogin: fix control lost of the current terminal when
default.target is rescue.target
When default.target is rescue.target, exiting from the single-user shell
results in lost of the control of the current terminal. This is because the
operation performed to continue to boot is systemctl default but default.target
is now rescue.target and it is already active. Hence, no new process that
controls the current terminal is created. Users need to make hardware reset to
recover the situation.
This sounds like a bit corner case issue and some might feel configuring
default.target as rescue.target is odd because there are several other ways to
transition to rescue.mode without configuring default.target to rescue.target
such as systemctl rescue or systemd.unit=rescue.target something like
that. However, users unfamiliar with systemd operations tend to come up with
systemctl set-default rescue.target.
To fix this issue, let's transition to default.target only when default.target
is inactive. Otherwise, invoke the single-user shell again to keep control of
the current terminal for users.
This new logic depends on whether D-Bus working well. Exiting without any check
of result of systemctl default could lead to again the control lost of the
current terminal. Hence, add checking results of each D-Bus operations
including systemctl default and invoke the single-user shell if they fail.
(cherry picked from commit 937ca8330d11e406b8ef343bead6f4f6244e39c7)
Resolves: #2169932
---
src/sulogin-shell/sulogin-shell.c | 60 +++++++++++++++++++++++++------
1 file changed, 50 insertions(+), 10 deletions(-)
diff --git a/src/sulogin-shell/sulogin-shell.c b/src/sulogin-shell/sulogin-shell.c
index a1ea2333de..8f14ee11bb 100644
--- a/src/sulogin-shell/sulogin-shell.c
+++ b/src/sulogin-shell/sulogin-shell.c
@@ -14,6 +14,8 @@
#include "process-util.h"
#include "sd-bus.h"
#include "signal-util.h"
+#include "special.h"
+#include "unit-def.h"
static int reload_manager(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -43,6 +45,28 @@ static int reload_manager(sd_bus *bus) {
return 0;
}
+static int default_target_is_inactive(sd_bus *bus) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *path = NULL, *state = NULL;
+ int r;
+
+ path = unit_dbus_path_from_name(SPECIAL_DEFAULT_TARGET);
+ if (!path)
+ return log_oom();
+
+ r = sd_bus_get_property_string(bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.systemd1.Unit",
+ "ActiveState",
+ &error,
+ &state);
+ if (r < 0)
+ return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
+
+ return streq_ptr(state, "inactive");
+}
+
static int start_default_target(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -95,7 +119,6 @@ int main(int argc, char *argv[]) {
NULL, /* --force */
NULL
};
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
log_set_target(LOG_TARGET_AUTO);
@@ -108,17 +131,34 @@ int main(int argc, char *argv[]) {
/* allows passwordless logins if root account is locked. */
sulogin_cmdline[1] = "--force";
- (void) fork_wait(sulogin_cmdline);
+ for (;;) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+
+ (void) fork_wait(sulogin_cmdline);
+
+ r = bus_connect_system_systemd(&bus);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to get D-Bus connection: %m");
+ goto fallback;
+ }
- r = bus_connect_system_systemd(&bus);
- if (r < 0) {
- log_warning_errno(r, "Failed to get D-Bus connection: %m");
- r = 0;
- } else {
- (void) reload_manager(bus);
+ if (reload_manager(bus) < 0)
+ goto fallback;
- r = start_default_target(bus);
+ r = default_target_is_inactive(bus);
+ if (r < 0)
+ goto fallback;
+ if (!r) {
+ log_warning(SPECIAL_DEFAULT_TARGET" is not inactive. Please review the "SPECIAL_DEFAULT_TARGET" setting.\n");
+ goto fallback;
+ }
+
+ if (start_default_target(bus) >= 0)
+ break;
+
+ fallback:
+ log_warning("Fallback to the single-user shell.\n");
}
- return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ return 0;
}

View File

@ -0,0 +1,49 @@
From cb99c3e54af1ba7c6cf1cd99d61546f5aa9423cb Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jul 2018 18:50:25 +0200
Subject: [PATCH] parse-util: in parse_permille() check negative earlier
If 'v' is negative, it's wrong to add the decimal to it, as we'd
actually need to subtract it in this case. But given that we don't want
to allow negative vaues anyway, simply check earlier whether what we
have parsed so far was negative, and react to that before adding the
decimal to it.
(cherry picked from commit 8cbc92d5975b603002c3141364a7709a9c66e23a)
Related: #2178179
---
src/basic/parse-util.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 992ea3605b..2ab8e88451 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -728,6 +728,8 @@ int parse_permille_unbounded(const char *p) {
r = safe_atoi(n, &v);
if (r < 0)
return r;
+ if (v < 0)
+ return -ERANGE;
} else {
pc = endswith(p, "%");
if (!pc)
@@ -748,15 +750,14 @@ int parse_permille_unbounded(const char *p) {
r = safe_atoi(n, &v);
if (r < 0)
return r;
+ if (v < 0)
+ return -ERANGE;
if (v > (INT_MAX - q) / 10)
return -ERANGE;
v = v * 10 + q;
}
- if (v < 0)
- return -ERANGE;
-
return v;
}

View File

@ -0,0 +1,165 @@
From 30343fc0ba66dd7a513de736c7708702ec5400be Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jul 2018 18:52:42 +0200
Subject: [PATCH] tree-wide: increase granularity of percent specifications all
over the place to permille
We so far had various placed we'd parse percentages with
parse_percent(). Let's make them use parse_permille() instead, which is
downward compatible (as it also parses percent values), and increases
the granularity a bit. Given that on the wire we usually normalize
relative specifications to something like UINT32_MAX anyway changing
from base-100 to base-1000 calculations can be done easily without
breaking compat.
This commit doesn't document this change in the man pages. While
allowing more precise specifcations permille is not as commonly
understood as perent I guess, hence let's keep this out of the docs for
now.
(cherry picked from commit f806dfd34595dac8632ba777250323a4735568dc)
Resolves: #2178179
---
src/core/load-fragment.c | 12 ++++++------
src/login/logind-user.c | 6 +++---
src/login/pam_systemd.c | 4 ++--
src/shared/bus-unit-util.c | 22 ++++++++++++----------
4 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 53de7ff5e9..f6505cf83c 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2991,13 +2991,13 @@ int config_parse_cpu_quota(
return 0;
}
- r = parse_percent_unbounded(rvalue);
+ r = parse_permille_unbounded(rvalue);
if (r <= 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
return 0;
}
- c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
+ c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U;
return 0;
}
@@ -3057,7 +3057,7 @@ int config_parse_memory_limit(
if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
- r = parse_percent(rvalue);
+ r = parse_permille(rvalue);
if (r < 0) {
r = parse_size(rvalue, 1024, &bytes);
if (r < 0) {
@@ -3065,7 +3065,7 @@ int config_parse_memory_limit(
return 0;
}
} else
- bytes = physical_memory_scale(r, 100U);
+ bytes = physical_memory_scale(r, 1000U);
if (bytes >= UINT64_MAX ||
(bytes <= 0 && !STR_IN_SET(lvalue, "MemorySwapMax", "MemoryLow", "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin"))) {
@@ -3132,7 +3132,7 @@ int config_parse_tasks_max(
return 0;
}
- r = parse_percent(rvalue);
+ r = parse_permille(rvalue);
if (r < 0) {
r = safe_atou64(rvalue, &v);
if (r < 0) {
@@ -3140,7 +3140,7 @@ int config_parse_tasks_max(
return 0;
}
} else
- v = system_tasks_max_scale(r, 100U);
+ v = system_tasks_max_scale(r, 1000U);
if (v <= 0 || v >= UINT64_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range, ignoring.", rvalue);
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index bba3158d1a..00d25d5876 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -794,9 +794,9 @@ int config_parse_tmpfs_size(
assert(data);
/* First, try to parse as percentage */
- r = parse_percent(rvalue);
- if (r > 0 && r < 100)
- *sz = physical_memory_scale(r, 100U);
+ r = parse_permille(rvalue);
+ if (r > 0 && r < 1000)
+ *sz = physical_memory_scale(r, 1000U);
else {
uint64_t k;
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index c87e980b18..7a551a41bb 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -208,9 +208,9 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co
return r;
}
} else {
- r = parse_percent(limit);
+ r = parse_permille(limit);
if (r >= 0) {
- r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
+ r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
return r;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index c475bbafe0..aa4286ab6e 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -440,16 +440,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return 1;
}
- r = parse_percent(eq);
+ r = parse_permille(eq);
if (r >= 0) {
char *n;
- /* When this is a percentage we'll convert this into a relative value in the range
- * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related
- * ones). This way the physical memory size can be determined server-side */
+ /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
+ * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
+ * size can be determined server-side. */
n = strjoina(field, "Scale");
- r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
+ r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
if (r < 0)
return bus_log_create_error(r);
@@ -467,13 +467,15 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
if (isempty(eq))
r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
else {
- r = parse_percent_unbounded(eq);
- if (r <= 0) {
- log_error_errno(r, "CPU quota '%s' invalid.", eq);
- return -EINVAL;
+ r = parse_permille_unbounded(eq);
+ if (r == 0) {
+ log_error("CPU quota too small.");
+ return -ERANGE;
}
+ if (r < 0)
+ return log_error_errno(r, "CPU quota '%s' invalid.", eq);
- r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (usec_t) r * USEC_PER_SEC / 100U);
+ r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U));
}
if (r < 0)

View File

@ -0,0 +1,31 @@
From 5a1d30b9a775a7bbac55752abdc10ed5383d209f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 30 Nov 2021 03:39:35 +0900
Subject: [PATCH] errno-util: introduce ERRNO_IS_TRANSIENT()
(cherry picked from commit 7aad83580fccee926d903bdb1a2a6af2c40ef0fc)
Related: #2172846
---
src/basic/util.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/basic/util.h b/src/basic/util.h
index 195f02cf5f..48beb88bac 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -180,6 +180,14 @@ static inline int negative_errno(void) {
return -errno;
}
+
+/* For send()/recv() or read()/write(). */
+static inline bool ERRNO_IS_TRANSIENT(int r) {
+ return IN_SET(abs(r),
+ EAGAIN,
+ EINTR);
+}
+
/* Two different errors for access problems */
static inline bool ERRNO_IS_PRIVILEGE(int r) {
return IN_SET(abs(r),

View File

@ -0,0 +1,545 @@
From da79f303ec02fdb9a1c07e0fe48e0aaf4bd09e1b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 30 Nov 2021 04:07:24 +0900
Subject: [PATCH] tree-wide: use ERRNO_IS_TRANSIENT()
(cherry picked from commit 8add30a03cb19e4a2722fa5a0fc08c277aaf67fd)
Related: #2172846
---
src/basic/barrier.c | 7 ++++---
src/basic/terminal-util.c | 2 +-
src/core/cgroup.c | 2 +-
src/core/manager.c | 17 ++++++++---------
src/core/path.c | 2 +-
src/import/importd.c | 2 +-
src/journal/journald-kmsg.c | 2 +-
src/journal/journald-server.c | 2 +-
src/journal/journald-stream.c | 2 +-
src/journal/sd-journal.c | 2 +-
src/libsystemd-network/icmp6-util.c | 2 +-
src/libsystemd-network/sd-dhcp-client.c | 4 ++--
src/libsystemd-network/sd-dhcp-server.c | 2 +-
src/libsystemd-network/sd-dhcp6-client.c | 2 +-
src/libsystemd-network/sd-ipv4acd.c | 2 +-
src/libsystemd-network/sd-lldp.c | 2 +-
src/libsystemd/sd-event/sd-event.c | 6 +++---
src/libsystemd/sd-netlink/netlink-socket.c | 4 ++--
src/libsystemd/sd-network/sd-network.c | 2 +-
src/nspawn/nspawn.c | 2 +-
src/resolve/resolved-dns-stream.c | 6 +++---
src/resolve/resolved-dns-stub.c | 2 +-
src/resolve/resolved-manager.c | 2 +-
src/shared/ask-password-api.c | 6 +++---
src/socket-proxy/socket-proxyd.c | 4 ++--
src/time-wait-sync/time-wait-sync.c | 2 +-
.../tty-ask-password-agent.c | 2 +-
src/udev/udevd.c | 2 +-
28 files changed, 47 insertions(+), 47 deletions(-)
diff --git a/src/basic/barrier.c b/src/basic/barrier.c
index 587852aac8..d36c6c6f88 100644
--- a/src/basic/barrier.c
+++ b/src/basic/barrier.c
@@ -13,6 +13,7 @@
#include "barrier.h"
#include "fd-util.h"
#include "macro.h"
+#include "util.h"
/**
* Barriers
@@ -181,7 +182,7 @@ static bool barrier_write(Barrier *b, uint64_t buf) {
assert(b->me >= 0);
do {
len = write(b->me, &buf, sizeof(buf));
- } while (len < 0 && IN_SET(errno, EAGAIN, EINTR));
+ } while (len < 0 && ERRNO_IS_TRANSIENT(errno));
if (len != sizeof(buf))
goto error;
@@ -223,7 +224,7 @@ static bool barrier_read(Barrier *b, int64_t comp) {
int r;
r = poll(pfd, 2, -1);
- if (r < 0 && IN_SET(errno, EAGAIN, EINTR))
+ if (r < 0 && ERRNO_IS_TRANSIENT(errno))
continue;
else if (r < 0)
goto error;
@@ -233,7 +234,7 @@ static bool barrier_read(Barrier *b, int64_t comp) {
/* events on @them signal new data for us */
len = read(b->them, &buf, sizeof(buf));
- if (len < 0 && IN_SET(errno, EAGAIN, EINTR))
+ if (len < 0 && ERRNO_IS_TRANSIENT(errno))
continue;
if (len != sizeof(buf))
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index e2bbe8187d..18176cfe17 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -460,7 +460,7 @@ int acquire_terminal(
l = read(notify, &buffer, sizeof(buffer));
if (l < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (ERRNO_IS_TRANSIENT(errno))
continue;
return -errno;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index f89bce3d61..0c8a66edd1 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -2356,7 +2356,7 @@ static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents,
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return log_error_errno(errno, "Failed to read control group inotify events: %m");
diff --git a/src/core/manager.c b/src/core/manager.c
index 4a9f9bfcf9..e09227d5ac 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2331,7 +2331,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(n))
return 0; /* Spurious wakeup, try again */
/* If this is any other, real error, then let's stop processing this socket. This of course means we
@@ -2573,19 +2573,18 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
}
n = read(m->signal_fd, &sfsi, sizeof(sfsi));
- if (n != sizeof(sfsi)) {
- if (n >= 0) {
- log_warning("Truncated read from signal fd (%zu bytes), ignoring!", n);
- return 0;
- }
-
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (n < 0) {
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
/* We return an error here, which will kill this handler,
* to avoid a busy loop on read error. */
return log_error_errno(errno, "Reading from signal fd failed: %m");
}
+ if (n != sizeof(sfsi)) {
+ log_warning("Truncated read from signal fd (%zu bytes), ignoring!", n);
+ return 0;
+ }
log_received_signal(sfsi.ssi_signo == SIGCHLD ||
(sfsi.ssi_signo == SIGTERM && MANAGER_IS_USER(m))
@@ -4453,7 +4452,7 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re
l = recv(fd, &buffer, sizeof(buffer), MSG_DONTWAIT);
if (l < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return log_error_errno(errno, "Failed to read from user lookup fd: %m");
diff --git a/src/core/path.c b/src/core/path.c
index b899bde0de..dfa63d5102 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -152,7 +152,7 @@ int path_spec_fd_event(PathSpec *s, uint32_t revents) {
l = read(s->inotify_fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return log_error_errno(errno, "Failed to read inotify event: %m");
diff --git a/src/import/importd.c b/src/import/importd.c
index 04563fb098..5463bd7146 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -519,7 +519,7 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(n))
return 0;
return -errno;
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 726c006ce1..a49cc5c4c5 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -321,7 +321,7 @@ static int server_read_dev_kmsg(Server *s) {
return 0;
}
- if (IN_SET(errno, EAGAIN, EINTR, EPIPE))
+ if (ERRNO_IS_TRANSIENT(errno) || errno == EPIPE)
return 0;
return log_error_errno(errno, "Failed to read from kernel: %m");
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 4788ff78bb..1e00e4b4bd 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1131,7 +1131,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (ERRNO_IS_TRANSIENT(n))
return 0;
return log_error_errno(errno, "recvmsg() failed: %m");
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 5be5b0939c..470d2e2661 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -556,7 +556,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (l < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
log_warning_errno(errno, "Failed to read from stream: %m");
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 4c502978de..ca083da161 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -2563,7 +2563,7 @@ _public_ int sd_journal_process(sd_journal *j) {
l = read(j->inotify_fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return got_something ? determine_change(j) : SD_JOURNAL_NOP;
return -errno;
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
index 736df222f0..17d4d1faf2 100644
--- a/src/libsystemd-network/icmp6-util.c
+++ b/src/libsystemd-network/icmp6-util.c
@@ -175,7 +175,7 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst,
len = recvmsg(fd, &msg, MSG_DONTWAIT);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index ff434f8ce7..8a8d806b3f 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1720,7 +1720,7 @@ static int client_receive_message_udp(
len = recv(fd, message, buflen, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return log_dhcp_client_errno(client, errno,
@@ -1814,7 +1814,7 @@ static int client_receive_message_raw(
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return log_dhcp_client_errno(client, errno,
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 5ca46b3502..c964b73da1 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -962,7 +962,7 @@ static int server_receive_message(sd_event_source *s, int fd,
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(len))
return 0;
return -errno;
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index b3bc259280..67257f2e03 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -1055,7 +1055,7 @@ static int client_receive_message(
len = recv(fd, message, buflen, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(len))
return 0;
return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
index a40d40db90..f69810c6f5 100644
--- a/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -336,7 +336,7 @@ static int ipv4acd_on_packet(
n = recv(fd, &packet, sizeof(struct ether_arp), 0);
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index c75d6079e1..bf15029027 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -200,7 +200,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
if (length < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 2c9d331bf2..549103bc6f 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -3007,7 +3007,7 @@ static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) {
ss = read(fd, &x, sizeof(x));
if (ss < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
@@ -3161,7 +3161,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
n = read(d->fd, &si, sizeof(si));
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return read_one;
return -errno;
@@ -3210,7 +3210,7 @@ static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t
n = read(d->fd, &d->buffer, sizeof(d->buffer));
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c
index f103cbedea..5fe91450a7 100644
--- a/src/libsystemd/sd-netlink/netlink-socket.c
+++ b/src/libsystemd/sd-netlink/netlink-socket.c
@@ -265,7 +265,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
else if (errno == EAGAIN)
log_debug("rtnl: no data in socket");
- return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
+ return ERRNO_IS_TRANSIENT(errno) ? 0 : -errno;
}
if (sender.nl.nl_pid != 0) {
@@ -276,7 +276,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
/* drop the message */
n = recvmsg(fd, &msg, 0);
if (n < 0)
- return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
+ return ERRNO_IS_TRANSIENT(errno) ? 0 : -errno;
}
return 0;
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index 3b8ce935b0..09d3b86e14 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -338,7 +338,7 @@ _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 8cb7591f0e..025a513def 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -3252,7 +3252,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(n))
return 0;
return log_warning_errno(errno, "Couldn't read notification socket: %m");
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index ca0313d1d7..cebaba4207 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -380,7 +380,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ss = dns_stream_writev(s, iov, 2, 0);
if (ss < 0) {
- if (!IN_SET(-ss, EINTR, EAGAIN))
+ if (!ERRNO_IS_TRANSIENT(ss))
return dns_stream_complete(s, -ss);
} else
s->n_written += ss;
@@ -402,7 +402,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ss = dns_stream_read(s, (uint8_t*) &s->read_size + s->n_read, sizeof(s->read_size) - s->n_read);
if (ss < 0) {
- if (!IN_SET(-ss, EINTR, EAGAIN))
+ if (!ERRNO_IS_TRANSIENT(ss))
return dns_stream_complete(s, -ss);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
@@ -452,7 +452,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
(uint8_t*) DNS_PACKET_DATA(s->read_packet) + s->n_read - sizeof(s->read_size),
sizeof(s->read_size) + be16toh(s->read_size) - s->n_read);
if (ss < 0) {
- if (!IN_SET(errno, EINTR, EAGAIN))
+ if (!ERRNO_IS_TRANSIENT(errno))
return dns_stream_complete(s, errno);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 5ddf13081e..1b80c42174 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -458,7 +458,7 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 01372fc66b..2a23c387a6 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -755,7 +755,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
if (l == 0)
return 0;
if (l < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 764ebd08e1..062db31bbd 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -332,7 +332,7 @@ int ask_password_tty(
n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
if (n < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (ERRNO_IS_TRANSIENT(errno))
continue;
r = -errno;
@@ -652,7 +652,7 @@ int ask_password_agent(
n = recvmsg(socket_fd, &msghdr, 0);
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
continue;
r = -errno;
@@ -661,7 +661,7 @@ int ask_password_agent(
cmsg_close_all(&msghdr);
- if (n <= 0) {
+ if (n == 0) {
log_debug("Message too short");
continue;
}
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 3d07483eb4..155631f1e7 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -144,7 +144,7 @@ static int connection_shovel(
} else if (z == 0 || IN_SET(errno, EPIPE, ECONNRESET)) {
*from_source = sd_event_source_unref(*from_source);
*from = safe_close(*from);
- } else if (!IN_SET(errno, EAGAIN, EINTR))
+ } else if (!ERRNO_IS_TRANSIENT(errno))
return log_error_errno(errno, "Failed to splice: %m");
}
@@ -156,7 +156,7 @@ static int connection_shovel(
} else if (z == 0 || IN_SET(errno, EPIPE, ECONNRESET)) {
*to_source = sd_event_source_unref(*to_source);
*to = safe_close(*to);
- } else if (!IN_SET(errno, EAGAIN, EINTR))
+ } else if (!ERRNO_IS_TRANSIENT(errno))
return log_error_errno(errno, "Failed to splice: %m");
}
} while (shoveled);
diff --git a/src/time-wait-sync/time-wait-sync.c b/src/time-wait-sync/time-wait-sync.c
index d268fb0c5a..2071cb2759 100644
--- a/src/time-wait-sync/time-wait-sync.c
+++ b/src/time-wait-sync/time-wait-sync.c
@@ -94,7 +94,7 @@ static int inotify_handler(sd_event_source *s,
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return log_warning_errno(errno, "Lost access to inotify: %m");
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 40d594896b..3a20a381c9 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -150,7 +150,7 @@ static int ask_password_plymouth(
k = read(fd, buffer + p, sizeof(buffer) - p);
if (k < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
+ if (ERRNO_IS_TRANSIENT(errno))
continue;
r = -errno;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 34f6a95503..172d21018e 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1119,7 +1119,7 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 1;
return log_error_errno(errno, "Failed to read inotify fd: %m");

View File

@ -0,0 +1,75 @@
From 4cbf11180cc6c6792f541a861f3309c34c156f4b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 30 Nov 2021 03:33:55 +0900
Subject: [PATCH] libsystemd: ignore both EINTR and EAGAIN
(cherry picked from commit b3d06b9226db96fddb6bb45a4708e2e8d413d91d)
Related: #2172846
---
src/libsystemd/sd-bus/bus-socket.c | 8 ++++----
src/libsystemd/sd-resolve/sd-resolve.c | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 8813dd5efd..c6e1a1624f 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -155,7 +155,7 @@ static int bus_socket_write_auth(sd_bus *b) {
}
if (k < 0)
- return errno == EAGAIN ? 0 : -errno;
+ return ERRNO_IS_TRANSIENT(errno) ? 0 : -errno;
iovec_advance(b->auth_iovec, &b->auth_index, (size_t) k);
return 1;
@@ -573,7 +573,7 @@ static int bus_socket_read_auth(sd_bus *b) {
handle_cmsg = true;
}
if (k < 0)
- return errno == EAGAIN ? 0 : -errno;
+ return ERRNO_IS_TRANSIENT(errno) ? 0 : -errno;
if (k == 0)
return -ECONNRESET;
@@ -1051,7 +1051,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
}
if (k < 0)
- return errno == EAGAIN ? 0 : -errno;
+ return ERRNO_IS_TRANSIENT(errno) ? 0 : -errno;
*idx += (size_t) k;
return 1;
@@ -1205,7 +1205,7 @@ int bus_socket_read_message(sd_bus *bus) {
handle_cmsg = true;
}
if (k < 0)
- return errno == EAGAIN ? 0 : -errno;
+ return ERRNO_IS_TRANSIENT(errno) ? 0 : -errno;
if (k == 0)
return -ECONNRESET;
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index a189f140f8..99ecb6a467 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -402,7 +402,7 @@ static void* thread_worker(void *p) {
length = recv(resolve->fds[REQUEST_RECV_FD], &buf, sizeof buf, 0);
if (length < 0) {
- if (errno == EINTR)
+ if (ERRNO_IS_TRANSIENT(errno))
continue;
break;
@@ -850,7 +850,7 @@ _public_ int sd_resolve_process(sd_resolve *resolve) {
l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof buf, 0);
if (l < 0) {
- if (errno == EAGAIN)
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;

View File

@ -0,0 +1,90 @@
From b1075e8b3ecb9e0770dd46331ce8517ea152e1ca Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 21 Nov 2022 17:42:04 +0100
Subject: [PATCH] sd-bus: handle -EINTR return from bus_poll()
In sd_bus_wait(), let's convert EINTR to a return code of 0, thus asking
the caller do loop again and enter sd_bus_process() again (which will
not find any queued events). This way we'll not return an error on
something that isn't really an error. This should typically make sure
things are properly handled by the caller, magically, without eating up
the event entirely, and still giving the caller time to run some code if
they want.
(cherry picked from commit 3022916b4d2483452c3ddbbac9ee7c4372b1cb46)
Resolves: #2172846
---
src/libsystemd/sd-bus/bus-socket.c | 5 ++++-
src/libsystemd/sd-bus/sd-bus.c | 18 +++++++++++++++---
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index c6e1a1624f..a5c750fc69 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -1266,8 +1266,11 @@ int bus_socket_process_opening(sd_bus *b) {
assert(b->state == BUS_OPENING);
r = poll(&p, 1, 0);
- if (r < 0)
+ if (r < 0) {
+ if (ERRNO_IS_TRANSIENT(errno))
+ return 0;
return -errno;
+ }
if (!(p.revents & (POLLOUT|POLLERR|POLLHUP)))
return 0;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 21e54591f7..5d934cbf73 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -2209,8 +2209,11 @@ _public_ int sd_bus_call(
left = (uint64_t) -1;
r = bus_poll(bus, true, left);
- if (r < 0)
+ if (r < 0) {
+ if (ERRNO_IS_TRANSIENT(r))
+ continue;
goto fail;
+ }
if (r == 0) {
r = -ETIMEDOUT;
goto fail;
@@ -3069,6 +3072,7 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
}
_public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
+ int r;
assert_return(bus, -EINVAL);
assert_return(bus = bus_resolve(bus), -ENOPKG);
@@ -3083,7 +3087,11 @@ _public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
if (bus->rqueue_size > 0)
return 0;
- return bus_poll(bus, false, timeout_usec);
+ r = bus_poll(bus, false, timeout_usec);
+ if (r < 0 && ERRNO_IS_TRANSIENT(r))
+ return 1; /* treat EINTR as success, but let's exit, so that the caller will call back into us soon. */
+
+ return r;
}
_public_ int sd_bus_flush(sd_bus *bus) {
@@ -3125,8 +3133,12 @@ _public_ int sd_bus_flush(sd_bus *bus) {
return 0;
r = bus_poll(bus, false, (uint64_t) -1);
- if (r < 0)
+ if (r < 0) {
+ if (ERRNO_IS_TRANSIENT(r))
+ continue;
+
return r;
+ }
}
}

View File

@ -0,0 +1,28 @@
From 9ddb41dd9dc3bac57d6c3e05700485ee98df3e17 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 22 Nov 2022 12:18:07 +0100
Subject: [PATCH] stdio-bridge: don't be bothered with EINTR
We handle signals via signal handlers, hence no need to be concerned
about EINTR.
(cherry picked from commit 7c75f34131772781f690860de797d3e35fd0bed9)
Related: #2172846
---
src/stdio-bridge/stdio-bridge.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c
index 519a92a094..493117ef95 100644
--- a/src/stdio-bridge/stdio-bridge.c
+++ b/src/stdio-bridge/stdio-bridge.c
@@ -276,6 +276,8 @@ int main(int argc, char *argv[]) {
r = ppoll(p, ELEMENTSOF(p), ts, NULL);
}
if (r < 0) {
+ if (ERRNO_IS_TRANSIENT(r)) /* don't be bothered by signals, i.e. EINTR */
+ continue;
log_error_errno(errno, "ppoll() failed: %m");
goto finish;
}

View File

@ -0,0 +1,36 @@
From da367d5c87c039f4d1250c12097a5fb16f179a70 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 22 Nov 2022 13:00:48 +0100
Subject: [PATCH] sd-netlink: handle EINTR from poll() gracefully, as success
(cherry picked from commit 69858785335afffc51bc03127beb53332c0fb983)
Related: #2172846
---
src/libsystemd/sd-netlink/sd-netlink.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index a177f220ab..09900d577b 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -488,13 +488,18 @@ static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
}
int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
+ int r;
+
assert_return(nl, -EINVAL);
assert_return(!rtnl_pid_changed(nl), -ECHILD);
if (nl->rqueue_size > 0)
return 0;
- return rtnl_poll(nl, false, timeout_usec);
+ r = rtnl_poll(nl, false, timeout_usec);
+ if (r < 0 && ERRNO_IS_TRANSIENT(r)) /* Convert EINTR to "something happened" and give user a chance to run some code before calling back into us */
+ return 1;
+ return r;
}
static int timeout_compare(const void *a, const void *b) {

View File

@ -0,0 +1,79 @@
From 1316ec49f209e31799d42d114bd7f35d5acbe097 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 22 Nov 2022 12:28:19 +0100
Subject: [PATCH] resolved: handle -EINTR returned from fd_wait_for_event()
better
We might get signals for various reasons (for example, somebody asking
us to reload caches via a signal), hence let's handle this gracefully.
(cherry picked from commit 6d66a221685c15798e796d9738f73fdb1fdccdb2)
Related: #2172846
---
src/resolve/resolved-manager.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 2a23c387a6..5583d63527 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -842,11 +842,14 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
}
static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
+ usec_t end;
int r;
assert(fd >= 0);
assert(mh);
+ end = usec_add(now(CLOCK_MONOTONIC), SEND_TIMEOUT_USEC);
+
for (;;) {
if (sendmsg(fd, mh, flags) >= 0)
return 0;
@@ -857,20 +860,26 @@ static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
if (errno != EAGAIN)
return -errno;
- r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
- if (r < 0)
+ r = fd_wait_for_event(fd, POLLOUT, LESS_BY(end, now(CLOCK_MONOTONIC)));
+ if (r < 0) {
+ if (ERRNO_IS_TRANSIENT(r))
+ continue;
return r;
+ }
if (r == 0)
return -ETIMEDOUT;
}
}
static int write_loop(int fd, void *message, size_t length) {
+ usec_t end;
int r;
assert(fd >= 0);
assert(message);
+ end = usec_add(now(CLOCK_MONOTONIC), SEND_TIMEOUT_USEC);
+
for (;;) {
if (write(fd, message, length) >= 0)
return 0;
@@ -881,9 +890,12 @@ static int write_loop(int fd, void *message, size_t length) {
if (errno != EAGAIN)
return -errno;
- r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
- if (r < 0)
+ r = fd_wait_for_event(fd, POLLOUT, LESS_BY(end, now(CLOCK_MONOTONIC)));
+ if (r < 0) {
+ if (ERRNO_IS_TRANSIENT(r))
+ continue;
return r;
+ }
if (r == 0)
return -ETIMEDOUT;
}

View File

@ -0,0 +1,28 @@
From c57daab191c6551ac757576fcf7df45fd9790b6b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 22 Nov 2022 12:56:38 +0100
Subject: [PATCH] utmp-wtmp: fix error in case isatty() fails
(cherry picked from commit 80b780ba178a84b248ecee47eef82358480c9492)
Related: #2172846
---
src/shared/utmp-wtmp.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index ef9427fa7b..743b784489 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -312,8 +312,10 @@ static int write_to_terminal(const char *tty, const char *message) {
assert(message);
fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
- if (fd < 0 || !isatty(fd))
+ if (fd < 0)
return -errno;
+ if (!isatty(fd))
+ return -ENOTTY;
p = message;
left = strlen(message);

View File

@ -0,0 +1,52 @@
From 3590a9c5ce038bc56cdded426156cbd278903c86 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 22 Nov 2022 12:56:55 +0100
Subject: [PATCH] utmp-wtmp: handle EINTR gracefully when waiting to write to
tty
(cherry picked from commit 22ecfa83123dbfa2322346ac4e25ad2193a3b10c)
Related: #2172846
---
src/shared/utmp-wtmp.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index 743b784489..7358ece75d 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -320,7 +320,7 @@ static int write_to_terminal(const char *tty, const char *message) {
p = message;
left = strlen(message);
- end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC;
+ end = usec_add(now(CLOCK_MONOTONIC), TIMEOUT_MSEC*USEC_PER_MSEC);
while (left > 0) {
ssize_t n;
@@ -332,20 +332,22 @@ static int write_to_terminal(const char *tty, const char *message) {
int k;
t = now(CLOCK_MONOTONIC);
-
if (t >= end)
return -ETIME;
k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC);
- if (k < 0)
+ if (k < 0) {
+ if (ERRNO_IS_TRANSIENT(k))
+ continue;
return -errno;
+ }
if (k == 0)
return -ETIME;
n = write(fd, p, left);
if (n < 0) {
- if (errno == EAGAIN)
+ if (ERRNO_IS_TRANSIENT(errno))
continue;
return -errno;

View File

@ -0,0 +1,90 @@
From 947296a00d17ef115f4097aa86a8c6f1bfc8bf58 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Wed, 22 Mar 2023 12:36:54 +0100
Subject: [PATCH] journal-vacuum: count size of all journal files
Currently, active journal files are excluded, which means that vacuuming
may not remove anything even if *MaxUse= has been exceeded.
(cherry picked from commit 9ea46af4f2368b41d57705bac09774778126507f)
Resolves: #2180380
---
src/journal/journal-vacuum.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 8d3ae71440..dd21f40966 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -179,6 +179,8 @@ int journal_directory_vacuum(
if (!S_ISREG(st.st_mode))
continue;
+ size = 512UL * (uint64_t) st.st_blocks;
+
q = strlen(de->d_name);
if (endswith(de->d_name, ".journal")) {
@@ -188,6 +190,7 @@ int journal_directory_vacuum(
if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) {
n_active_files++;
+ sum += size;
continue;
}
@@ -195,6 +198,7 @@ int journal_directory_vacuum(
de->d_name[q-8-16-1-16-1] != '-' ||
de->d_name[q-8-16-1-16-1-32-1] != '@') {
n_active_files++;
+ sum += size;
continue;
}
@@ -207,11 +211,13 @@ int journal_directory_vacuum(
de->d_name[q-8-16-1-16-1] = 0;
if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
n_active_files++;
+ sum += size;
continue;
}
if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
n_active_files++;
+ sum += size;
continue;
}
@@ -224,12 +230,14 @@ int journal_directory_vacuum(
if (q < 1 + 16 + 1 + 16 + 8 + 1) {
n_active_files++;
+ sum += size;
continue;
}
if (de->d_name[q-1-8-16-1] != '-' ||
de->d_name[q-1-8-16-1-16-1] != '@') {
n_active_files++;
+ sum += size;
continue;
}
@@ -241,6 +249,7 @@ int journal_directory_vacuum(
if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
n_active_files++;
+ sum += size;
continue;
}
@@ -251,8 +260,6 @@ int journal_directory_vacuum(
continue;
}
- size = 512UL * (uint64_t) st.st_blocks;
-
r = journal_file_empty(dirfd(d), p);
if (r < 0) {
log_debug_errno(r, "Failed check if %s is empty, ignoring: %m", p);

View File

@ -0,0 +1,365 @@
From fc8959efebc662f4050700cc1ed2798750b15b73 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 6 Nov 2020 13:32:53 +0100
Subject: [PATCH] resolved: instead of closing DNS UDP transaction fds
right-away, add them to a socket "graveyard"
The "socket graveyard" shall contain sockets we have sent a question out
of, but not received a reply. If we'd close thus sockets immediately
when we are not interested anymore, we'd trigger ICMP port unreachable
messages once we after all *do* get a reply. Let's avoid that, by
leaving the fds open for a bit longer, until a timeout is reached or a
reply datagram received.
Fixes: #17421
(cherry picked from commit 80710ade03d971a8877fde8ce9d42eb2b07f4c47)
Resolves: #2156751
---
src/resolve/meson.build | 2 +
src/resolve/resolved-dns-transaction.c | 44 ++++++--
src/resolve/resolved-manager.c | 2 +
src/resolve/resolved-manager.h | 5 +
src/resolve/resolved-socket-graveyard.c | 133 ++++++++++++++++++++++++
src/resolve/resolved-socket-graveyard.h | 18 ++++
6 files changed, 194 insertions(+), 10 deletions(-)
create mode 100644 src/resolve/resolved-socket-graveyard.c
create mode 100644 src/resolve/resolved-socket-graveyard.h
diff --git a/src/resolve/meson.build b/src/resolve/meson.build
index 15f3835d55..a975e58242 100644
--- a/src/resolve/meson.build
+++ b/src/resolve/meson.build
@@ -63,6 +63,8 @@ systemd_resolved_sources = files('''
resolved-dns-stub.c
resolved-etc-hosts.h
resolved-etc-hosts.c
+ resolved-socket-graveyard.c
+ resolved-socket-graveyard.h
'''.split())
resolvectl_sources = files('''
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index c60b8215a6..95aea21134 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -48,7 +48,14 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) {
}
}
-static void dns_transaction_close_connection(DnsTransaction *t) {
+static void dns_transaction_close_connection(
+ DnsTransaction *t,
+ bool use_graveyard) { /* Set use_graveyard = false when you know the connection is already
+ * dead, for example because you got a connection error back from the
+ * kernel. In that case there's no point in keeping the fd around,
+ * hence don't. */
+ int r;
+
assert(t);
if (t->stream) {
@@ -62,6 +69,20 @@ static void dns_transaction_close_connection(DnsTransaction *t) {
}
t->dns_udp_event_source = sd_event_source_unref(t->dns_udp_event_source);
+
+ /* If we have an UDP socket where we sent a packet, but never received one, then add it to the socket
+ * graveyard, instead of closing it right away. That way it will stick around for a moment longer,
+ * and the reply we might still get from the server will be eaten up instead of resulting in an ICMP
+ * port unreachable error message. */
+
+ if (use_graveyard && t->dns_udp_fd >= 0 && t->sent && !t->received) {
+ r = manager_add_socket_to_graveyard(t->scope->manager, t->dns_udp_fd);
+ if (r < 0)
+ log_debug_errno(r, "Failed to add UDP socket to graveyard, closing immediately: %m");
+ else
+ TAKE_FD(t->dns_udp_fd);
+ }
+
t->dns_udp_fd = safe_close(t->dns_udp_fd);
}
@@ -81,7 +102,7 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
log_debug("Freeing transaction %" PRIu16 ".", t->id);
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
dns_transaction_stop_timeout(t);
dns_packet_unref(t->sent);
@@ -341,7 +362,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
t->state = state;
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
dns_transaction_stop_timeout(t);
/* Notify all queries that are interested, but make sure the
@@ -455,7 +476,7 @@ static int dns_transaction_maybe_restart(DnsTransaction *t) {
static void on_transaction_stream_error(DnsTransaction *t, int error) {
assert(t);
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
if (ERRNO_IS_DISCONNECT(error)) {
if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
@@ -478,7 +499,7 @@ static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) {
assert(t);
assert(p);
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
if (dns_packet_validate_reply(p) <= 0) {
log_debug("Invalid TCP reply packet.");
@@ -583,7 +604,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
assert(t);
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
switch (t->scope->protocol) {
@@ -692,7 +713,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
r = dns_stream_write_packet(t->stream, t->sent);
if (r < 0) {
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, /* use_graveyard= */ false);
return r;
}
@@ -1196,7 +1217,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
if (r > 0) {
/* There are DNSSEC transactions pending now. Update the state accordingly. */
t->state = DNS_TRANSACTION_VALIDATING;
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
dns_transaction_stop_timeout(t);
return;
}
@@ -1277,7 +1298,10 @@ static int dns_transaction_emit_udp(DnsTransaction *t) {
if (r > 0 || t->dns_udp_fd < 0) { /* Server changed, or no connection yet. */
int fd;
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
+
+ /* Before we allocate a new UDP socket, let's process the graveyard a bit to free some fds */
+ manager_socket_graveyard_process(t->scope->manager);
fd = dns_scope_socket_udp(t->scope, t->server, 53);
if (fd < 0)
@@ -1297,7 +1321,7 @@ static int dns_transaction_emit_udp(DnsTransaction *t) {
if (r < 0)
return r;
} else
- dns_transaction_close_connection(t);
+ dns_transaction_close_connection(t, true);
r = dns_scope_emit_udp(t->scope, t->dns_udp_fd, t->sent);
if (r < 0)
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 5583d63527..5feb92a676 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -683,6 +683,8 @@ Manager *manager_free(Manager *m) {
manager_mdns_stop(m);
manager_dns_stub_stop(m);
+ manager_socket_graveyard_clear(m);
+
sd_bus_slot_unref(m->prepare_for_sleep_slot);
sd_bus_unref(m->bus);
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index d94b2888ab..80119bfcb3 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -20,6 +20,7 @@ typedef struct Manager Manager;
#include "resolved-dns-stream.h"
#include "resolved-dns-trust-anchor.h"
#include "resolved-link.h"
+#include "resolved-socket-graveyard.h"
#define MANAGER_SEARCH_DOMAINS_MAX 32
#define MANAGER_DNS_SERVERS_MAX 32
@@ -130,6 +131,10 @@ struct Manager {
sd_event_source *dns_stub_tcp_event_source;
Hashmap *polkit_registry;
+
+ LIST_HEAD(SocketGraveyard, socket_graveyard);
+ SocketGraveyard *socket_graveyard_oldest;
+ size_t n_socket_graveyard;
};
/* Manager */
diff --git a/src/resolve/resolved-socket-graveyard.c b/src/resolve/resolved-socket-graveyard.c
new file mode 100644
index 0000000000..067cb666d4
--- /dev/null
+++ b/src/resolve/resolved-socket-graveyard.c
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "resolved-socket-graveyard.h"
+
+#define SOCKET_GRAVEYARD_USEC (5 * USEC_PER_SEC)
+#define SOCKET_GRAVEYARD_MAX 100
+
+/* This implements a socket "graveyard" for UDP sockets. If a socket fd is added to the graveyard it is kept
+ * open for a couple of more seconds, expecting one reply. Once the reply is received the fd is closed
+ * immediately, or if none is received it is closed after the timeout. Why all this? So that if we contact a
+ * DNS server, and it doesn't reply instantly, and we lose interest in the response and thus close the fd, we
+ * don't end up sending back an ICMP error once the server responds but we aren't listening anymore. (See
+ * https://github.com/systemd/systemd/issues/17421 for further information.)
+ *
+ * Note that we don't allocate any timer event source to clear up the graveyard once the socket's timeout is
+ * reached. Instead we operate lazily: we close old entries when adding a new fd to the graveyard, or
+ * whenever any code runs manager_socket_graveyard_process() — which the DNS transaction code does right
+ * before allocating a new UDP socket. */
+
+static SocketGraveyard* socket_graveyard_free(SocketGraveyard *g) {
+ if (!g)
+ return NULL;
+
+ if (g->manager) {
+ assert(g->manager->n_socket_graveyard > 0);
+ g->manager->n_socket_graveyard--;
+
+ if (g->manager->socket_graveyard_oldest == g)
+ g->manager->socket_graveyard_oldest = g->graveyard_prev;
+
+ LIST_REMOVE(graveyard, g->manager->socket_graveyard, g);
+
+ assert((g->manager->n_socket_graveyard > 0) == !!g->manager->socket_graveyard);
+ assert((g->manager->n_socket_graveyard > 0) == !!g->manager->socket_graveyard_oldest);
+ }
+
+ if (g->io_event_source) {
+ log_debug("Closing graveyard socket fd %i", sd_event_source_get_io_fd(g->io_event_source));
+ sd_event_source_unref(g->io_event_source);
+ }
+
+ return mfree(g);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(SocketGraveyard*, socket_graveyard_free);
+
+void manager_socket_graveyard_process(Manager *m) {
+ usec_t n = USEC_INFINITY;
+
+ assert(m);
+
+ while (m->socket_graveyard_oldest) {
+ SocketGraveyard *g = m->socket_graveyard_oldest;
+
+ if (n == USEC_INFINITY)
+ assert_se(sd_event_now(m->event, clock_boottime_or_monotonic(), &n) >= 0);
+
+ if (g->deadline > n)
+ break;
+
+ socket_graveyard_free(g);
+ }
+}
+
+void manager_socket_graveyard_clear(Manager *m) {
+ assert(m);
+
+ while (m->socket_graveyard)
+ socket_graveyard_free(m->socket_graveyard);
+}
+
+static int on_io_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ SocketGraveyard *g = userdata;
+
+ assert(g);
+
+ /* An IO event happened on the graveyard fd. We don't actually care which event that is, and we don't
+ * read any incoming packet off the socket. We just close the fd, that's enough to not trigger the
+ * ICMP unreachable port event */
+
+ socket_graveyard_free(g);
+ return 0;
+}
+
+static void manager_socket_graveyard_make_room(Manager *m) {
+ assert(m);
+
+ while (m->n_socket_graveyard >= SOCKET_GRAVEYARD_MAX)
+ socket_graveyard_free(m->socket_graveyard_oldest);
+}
+
+int manager_add_socket_to_graveyard(Manager *m, int fd) {
+ _cleanup_(socket_graveyard_freep) SocketGraveyard *g = NULL;
+ int r;
+
+ assert(m);
+ assert(fd >= 0);
+
+ manager_socket_graveyard_process(m);
+ manager_socket_graveyard_make_room(m);
+
+ g = new(SocketGraveyard, 1);
+ if (!g)
+ return log_oom();
+
+ *g = (SocketGraveyard) {
+ .manager = m,
+ };
+
+ LIST_PREPEND(graveyard, m->socket_graveyard, g);
+ if (!m->socket_graveyard_oldest)
+ m->socket_graveyard_oldest = g;
+
+ m->n_socket_graveyard++;
+
+ assert_se(sd_event_now(m->event, clock_boottime_or_monotonic(), &g->deadline) >= 0);
+ g->deadline += SOCKET_GRAVEYARD_USEC;
+
+ r = sd_event_add_io(m->event, &g->io_event_source, fd, EPOLLIN, on_io_event, g);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create graveyard IO source: %m");
+
+ r = sd_event_source_set_io_fd_own(g->io_event_source, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable graveyard IO source fd ownership: %m");
+
+ (void) sd_event_source_set_description(g->io_event_source, "graveyard");
+
+ log_debug("Added socket %i to graveyard", fd);
+
+ TAKE_PTR(g);
+ return 0;
+}
diff --git a/src/resolve/resolved-socket-graveyard.h b/src/resolve/resolved-socket-graveyard.h
new file mode 100644
index 0000000000..9b13bb0482
--- /dev/null
+++ b/src/resolve/resolved-socket-graveyard.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+typedef struct SocketGraveyard SocketGraveyard;
+
+#include "resolved-manager.h"
+
+struct SocketGraveyard {
+ Manager *manager;
+ usec_t deadline;
+ sd_event_source *io_event_source;
+ LIST_FIELDS(SocketGraveyard, graveyard);
+};
+
+void manager_socket_graveyard_process(Manager *m);
+void manager_socket_graveyard_clear(Manager *m);
+
+int manager_add_socket_to_graveyard(Manager *m, int fd);

View File

@ -0,0 +1,26 @@
From 648fe0097229c7ae46a6b5911521cef27a726cbe Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 6 Nov 2020 14:31:56 +0100
Subject: [PATCH] resolved: close UDP socket when we received a network error
on it
(cherry picked from commit d68dbb37d7408c025e736181f294152e2a515bf1)
Related: #2156751
---
src/resolve/resolved-dns-transaction.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 95aea21134..c975215468 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -1250,6 +1250,8 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use
assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
dns_server_packet_lost(t->server, IPPROTO_UDP, t->current_feature_level);
+ dns_transaction_close_connection(t, /* use_graveyard = */ false);
+
dns_transaction_retry(t, true);
return 0;
}

View File

@ -0,0 +1,24 @@
From 950cc2c5109f269561d3c0fdd020c6bf7cb561e1 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Mon, 10 Jul 2023 12:38:05 +0200
Subject: [PATCH] ci: allow RHEL-only labels to mark downstream-only commits
RHEL-only
Related: #2179309
---
.github/advanced-commit-linter.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/advanced-commit-linter.yml b/.github/advanced-commit-linter.yml
index 491836abbb..327af0467a 100644
--- a/.github/advanced-commit-linter.yml
+++ b/.github/advanced-commit-linter.yml
@@ -6,6 +6,7 @@ policy:
exception:
note:
- rhel-only
+ - RHEL-only
tracker:
- keyword:
- 'Resolves: #?'

View File

@ -0,0 +1,39 @@
From e3d4d6b36c111c5273ce5da124116f1c98b10d9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sat, 29 Feb 2020 09:48:44 +0100
Subject: [PATCH] man: tweak markup in systemd-pstore.service(8)
(cherry picked from commit e3b192626e24cbd3a4dc2c7d5fb9a3b3fd136e24)
Related: #2217786
---
man/systemd-pstore.xml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/man/systemd-pstore.xml b/man/systemd-pstore.xml
index dd1aa5e83b..8726071cf0 100644
--- a/man/systemd-pstore.xml
+++ b/man/systemd-pstore.xml
@@ -49,8 +49,8 @@
<para>The pstore service is independent of the kdump service. In cloud environments
specifically, host and guest filesystems are on remote filesystems (eg. iSCSI
- or NFS), thus kdump relies [implicitly and/or explicitly] upon proper operation
- of networking software *and* hardware *and* infrastructure. Thus it may not be
+ or NFS), thus kdump relies (implicitly and/or explicitly) upon proper operation
+ of networking software *and* hardware *and* infrastructure. Thus it may not be
possible to capture a kernel coredump to a file since writes over the network
may not be possible.</para>
@@ -59,9 +59,9 @@
debugging.</para>
<para>The <command>systemd-pstore</command> executable does the actual work. Upon starting,
- the <filename>pstore.conf</filename> is read to obtain options, then the /sys/fs/pstore
+ the <filename>pstore.conf</filename> file is read and the <filename>/sys/fs/pstore</filename>
directory contents are processed according to the options. Pstore files are written to the
- journal, and optionally saved into /var/lib/systemd/pstore.</para>
+ journal, and optionally saved into <filename>/var/lib/systemd/pstore</filename>.</para>
</refsect1>
<refsect1>

View File

@ -0,0 +1,61 @@
From ff17baae0631f42f59be6e425943c7181c6c5c18 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sat, 29 Feb 2020 09:57:06 +0100
Subject: [PATCH] man: add .service suffix to systemd-pstore(8)
That is the pattern that we always use with executables not in
$PATH.
(cherry picked from commit aa07dc70932837bfeda982affe53f01d36ec6efe)
Related: #2217786
---
man/rules/meson.build | 2 +-
man/{systemd-pstore.xml => systemd-pstore.service.xml} | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
rename man/{systemd-pstore.xml => systemd-pstore.service.xml} (95%)
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 6295330c5e..05eb0a1604 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -634,7 +634,7 @@ manpages = [
['systemd-nspawn', '1', [], ''],
['systemd-path', '1', [], ''],
['systemd-portabled.service', '8', ['systemd-portabled'], 'ENABLE_PORTABLED'],
- ['systemd-pstore', '8', ['systemd-pstore.service'], 'ENABLE_PSTORE'],
+ ['systemd-pstore.service', '8', ['systemd-pstore'], 'ENABLE_PSTORE'],
['systemd-quotacheck.service',
'8',
['systemd-quotacheck'],
diff --git a/man/systemd-pstore.xml b/man/systemd-pstore.service.xml
similarity index 95%
rename from man/systemd-pstore.xml
rename to man/systemd-pstore.service.xml
index 8726071cf0..47916da521 100644
--- a/man/systemd-pstore.xml
+++ b/man/systemd-pstore.service.xml
@@ -7,19 +7,19 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
- <title>systemd-pstore</title>
+ <title>systemd-pstore.service</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
- <refentrytitle>systemd-pstore</refentrytitle>
+ <refentrytitle>systemd-pstore.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
- <refname>systemd-pstore</refname>
<refname>systemd-pstore.service</refname>
- <refpurpose>Tool to archive contents of the persistent storage filesytem</refpurpose>
+ <refname>systemd-pstore</refname>
+ <refpurpose>A service to archive contents of pstore</refpurpose>
</refnamediv>
<refsynopsisdiv>

View File

@ -0,0 +1,26 @@
From 36d9a1a50f80322b24ff5756b8fb89a07363dfd7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sat, 29 Feb 2020 10:01:39 +0100
Subject: [PATCH] presets: enable systemd-pstore.service by default
It has no effect is the pstore is not used, and prevents the non-volatile
storage from filling up if is used by the kernel.
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=952767
(cherry picked from commit 5926ea0a6860095eaa83403417cbbf345db864f6)
Resolves: #2217786
---
presets/90-systemd.preset | 2 ++
1 file changed, 2 insertions(+)
diff --git a/presets/90-systemd.preset b/presets/90-systemd.preset
index 11960e5423..b8edc23d48 100644
--- a/presets/90-systemd.preset
+++ b/presets/90-systemd.preset
@@ -34,3 +34,5 @@ disable syslog.socket
disable systemd-journal-gatewayd.*
disable systemd-journal-remote.*
disable systemd-journal-upload.*
+
+enable systemd-pstore.service

View File

@ -0,0 +1,54 @@
From bf5b87db9785b86fadbd2b5e97e4883cbe51797d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 23 Jun 2022 09:56:33 +0200
Subject: [PATCH] logind: simplify code
Follow-up for 4885d7490b23e08d8444e5a68927ce9ce8727e5a.
(cherry picked from commit e5c09aad375551b9db499703ab7eb123d408ba16)
Resolves: #2209328
---
src/login/logind-session.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 916202a65a..fabf680b61 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -349,12 +349,11 @@ fail:
}
static int session_load_devices(Session *s, const char *devices) {
- const char *p;
int r = 0;
assert(s);
- for (p = devices;;) {
+ for (const char *p = devices;;) {
_cleanup_free_ char *word = NULL;
SessionDevice *sd;
dev_t dev;
@@ -531,7 +530,7 @@ int session_load(Session *s) {
s->class = c;
}
- if (state && streq(state, "closing"))
+ if (streq_ptr(state, "closing"))
s->stopping = true;
if (s->fifo_path) {
@@ -1073,11 +1072,8 @@ int session_set_display(Session *s, const char *display) {
assert(s);
assert(display);
- if (streq(s->display, display))
- return 0;
-
r = free_and_strdup(&s->display, display);
- if (r < 0)
+ if (r <= 0) /* 0 means the strings were equal */
return r;
session_save(s);

View File

@ -0,0 +1,89 @@
From 2fb7d36caf560e4ce57265673da7a518d7a5348f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 Jul 2019 00:44:14 +0900
Subject: [PATCH] format-table: add TABLE_TIMESTAMP_UTC and _RELATIVE
(cherry picked from commit c5bbb2b5be079852d92d16ebc0d0840929ed82e1)
Related: #2156786
---
src/basic/format-table.c | 25 ++++++++++++++++++-------
src/basic/format-table.h | 2 ++
2 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/src/basic/format-table.c b/src/basic/format-table.c
index c541e92b3c..5f2e5e3d73 100644
--- a/src/basic/format-table.c
+++ b/src/basic/format-table.c
@@ -236,6 +236,8 @@ static size_t table_data_size(TableDataType type, const void *data) {
return sizeof(bool);
case TABLE_TIMESTAMP:
+ case TABLE_TIMESTAMP_UTC:
+ case TABLE_TIMESTAMP_RELATIVE:
case TABLE_TIMESPAN:
return sizeof(usec_t);
@@ -700,6 +702,8 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
break;
case TABLE_TIMESTAMP:
+ case TABLE_TIMESTAMP_UTC:
+ case TABLE_TIMESTAMP_RELATIVE:
case TABLE_TIMESPAN:
buffer.usec = va_arg(ap, usec_t);
data = &buffer.usec;
@@ -837,11 +841,9 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
return 0;
case TABLE_TIMESTAMP:
- if (a->timestamp < b->timestamp)
- return -1;
- if (a->timestamp > b->timestamp)
- return 1;
- return 0;
+ case TABLE_TIMESTAMP_UTC:
+ case TABLE_TIMESTAMP_RELATIVE:
+ return CMP(a->timestamp, b->timestamp);
case TABLE_TIMESPAN:
if (a->timespan < b->timespan)
@@ -952,14 +954,23 @@ static const char *table_data_format(TableData *d) {
case TABLE_BOOLEAN:
return yes_no(d->boolean);
- case TABLE_TIMESTAMP: {
+ case TABLE_TIMESTAMP:
+ case TABLE_TIMESTAMP_UTC:
+ case TABLE_TIMESTAMP_RELATIVE: {
_cleanup_free_ char *p;
+ char *ret;
p = new(char, FORMAT_TIMESTAMP_MAX);
if (!p)
return NULL;
- if (!format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp))
+ if (d->type == TABLE_TIMESTAMP)
+ ret = format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
+ else if (d->type == TABLE_TIMESTAMP_UTC)
+ ret = format_timestamp_utc(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
+ else
+ ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
+ if (!ret)
return "n/a";
d->formatted = TAKE_PTR(p);
diff --git a/src/basic/format-table.h b/src/basic/format-table.h
index 5a076b5383..1c8ab5436d 100644
--- a/src/basic/format-table.h
+++ b/src/basic/format-table.h
@@ -12,6 +12,8 @@ typedef enum TableDataType {
TABLE_STRING,
TABLE_BOOLEAN,
TABLE_TIMESTAMP,
+ TABLE_TIMESTAMP_UTC,
+ TABLE_TIMESTAMP_RELATIVE,
TABLE_TIMESPAN,
TABLE_SIZE,
TABLE_UINT32,

View File

@ -0,0 +1,39 @@
From c88514d4de20ceeeea2028917087e2710ea419b2 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Tue, 23 May 2023 10:48:15 +0200
Subject: [PATCH] loginctl: shorten variable name
(cherry picked from commit 86f128558d57586bd28c55eb63968eab3dc4b36e)
Related: #2156786
---
src/login/loginctl.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 9b3fed928b..079c0e2b17 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -147,7 +147,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
(void) table_set_align_percent(table, TABLE_HEADER_CELL(1), 100);
for (;;) {
- _cleanup_(sd_bus_error_free) sd_bus_error error_tty = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_tty = NULL;
const char *id, *user, *seat, *object, *tty = NULL;
uint32_t uid;
@@ -164,11 +164,11 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
object,
"org.freedesktop.login1.Session",
"TTY",
- &error_tty,
+ &e,
&reply_tty,
"s");
if (r < 0)
- log_warning_errno(r, "Failed to get TTY for session %s: %s", id, bus_error_message(&error_tty, r));
+ log_warning_errno(r, "Failed to get TTY for session %s: %s", id, bus_error_message(&e, r));
else {
r = sd_bus_message_read(reply_tty, "s", &tty);
if (r < 0)

View File

@ -0,0 +1,137 @@
From 5d2f49451c5e697d6e3548cfc9087ef3c16aa969 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 19 May 2023 13:33:58 +0200
Subject: [PATCH] loginctl: use bus_map_all_properties
(cherry picked from commit 5b7d1536d0c2ccf0b7688490f31c92c1e766ea44)
Related: #2156786
---
src/login/loginctl.c | 78 ++++++++++++++++++++++----------------------
1 file changed, 39 insertions(+), 39 deletions(-)
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 079c0e2b17..9e4c710062 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -47,6 +47,27 @@ static bool arg_ask_password = true;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
+typedef struct SessionStatusInfo {
+ const char *id;
+ uid_t uid;
+ const char *name;
+ struct dual_timestamp timestamp;
+ unsigned int vtnr;
+ const char *seat;
+ const char *tty;
+ const char *display;
+ bool remote;
+ const char *remote_host;
+ const char *remote_user;
+ const char *service;
+ pid_t leader;
+ const char *type;
+ const char *class;
+ const char *state;
+ const char *scope;
+ const char *desktop;
+} SessionStatusInfo;
+
static OutputFlags get_output_flags(void) {
return
@@ -112,6 +133,12 @@ static int show_table(Table *table, const char *word) {
}
static int list_sessions(int argc, char *argv[], void *userdata) {
+
+ static const struct bus_properties_map map[] = {
+ { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
+ {},
+ };
+
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
@@ -148,9 +175,10 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
for (;;) {
_cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_tty = NULL;
- const char *id, *user, *seat, *object, *tty = NULL;
+ const char *id, *user, *seat, *object;
uint32_t uid;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ SessionStatusInfo i = {};
r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object);
if (r < 0)
@@ -158,21 +186,14 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
if (r == 0)
break;
- r = sd_bus_get_property(
- bus,
- "org.freedesktop.login1",
- object,
- "org.freedesktop.login1.Session",
- "TTY",
- &e,
- &reply_tty,
- "s");
- if (r < 0)
- log_warning_errno(r, "Failed to get TTY for session %s: %s", id, bus_error_message(&e, r));
- else {
- r = sd_bus_message_read(reply_tty, "s", &tty);
- if (r < 0)
- return bus_log_parse_error(r);
+ r = bus_map_all_properties(bus, "org.freedesktop.login1", object, map, BUS_MAP_BOOLEAN_AS_BOOL, &e, &m, &i);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT))
+ /* The session is already closed when we're querying the property */
+ continue;
+
+ log_warning_errno(r, "Failed to get properties of session %s, ignoring: %s",
+ id, bus_error_message(&e, r));
}
r = table_add_many(table,
@@ -180,7 +201,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
TABLE_UINT32, uid,
TABLE_STRING, user,
TABLE_STRING, seat,
- TABLE_STRING, strna(tty));
+ TABLE_STRING, strna(i.tty));
if (r < 0)
return log_error_errno(r, "Failed to add row to table: %m");
}
@@ -341,27 +362,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
return 0;
}
-typedef struct SessionStatusInfo {
- const char *id;
- uid_t uid;
- const char *name;
- struct dual_timestamp timestamp;
- unsigned int vtnr;
- const char *seat;
- const char *tty;
- const char *display;
- bool remote;
- const char *remote_host;
- const char *remote_user;
- const char *service;
- pid_t leader;
- const char *type;
- const char *class;
- const char *state;
- const char *scope;
- const char *desktop;
-} SessionStatusInfo;
-
typedef struct UserStatusInfo {
uid_t uid;
bool linger;

View File

@ -0,0 +1,80 @@
From 0d1082f3cf9d4028ac69c22e9dad2adb51ee910d Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 19 May 2023 14:03:09 +0200
Subject: [PATCH] loginctl: show session idle status in list-sessions
(cherry picked from commit 556723e738b96a5c2b2d45a96b87b7b80e0c5664)
Resolves: #2156786
---
src/login/loginctl.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 9e4c710062..65fe182195 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -66,6 +66,8 @@ typedef struct SessionStatusInfo {
const char *state;
const char *scope;
const char *desktop;
+ bool idle_hint;
+ dual_timestamp idle_hint_timestamp;
} SessionStatusInfo;
static OutputFlags get_output_flags(void) {
@@ -135,7 +137,9 @@ static int show_table(Table *table, const char *word) {
static int list_sessions(int argc, char *argv[], void *userdata) {
static const struct bus_properties_map map[] = {
- { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
+ { "IdleHint", "b", NULL, offsetof(SessionStatusInfo, idle_hint) },
+ { "IdleSinceHintMonotonic", "t", NULL, offsetof(SessionStatusInfo, idle_hint_timestamp.monotonic) },
+ { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
{},
};
@@ -165,7 +169,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- table = table_new("SESSION", "UID", "USER", "SEAT", "TTY");
+ table = table_new("SESSION", "UID", "USER", "SEAT", "TTY", "IDLE", "SINCE");
if (!table)
return log_oom();
@@ -188,12 +192,11 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
r = bus_map_all_properties(bus, "org.freedesktop.login1", object, map, BUS_MAP_BOOLEAN_AS_BOOL, &e, &m, &i);
if (r < 0) {
- if (sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT))
- /* The session is already closed when we're querying the property */
- continue;
-
- log_warning_errno(r, "Failed to get properties of session %s, ignoring: %s",
- id, bus_error_message(&e, r));
+ log_full_errno(sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT) ? LOG_DEBUG : LOG_WARNING,
+ r,
+ "Failed to get properties of session %s, ignoring: %s",
+ id, bus_error_message(&e, r));
+ continue;
}
r = table_add_many(table,
@@ -201,7 +204,15 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
TABLE_UINT32, uid,
TABLE_STRING, user,
TABLE_STRING, seat,
- TABLE_STRING, strna(i.tty));
+ TABLE_STRING, strna(i.tty),
+ TABLE_BOOLEAN, i.idle_hint);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add row to table: %m");
+
+ if (i.idle_hint)
+ r = table_add_cell(table, NULL, TABLE_TIMESTAMP_RELATIVE, &i.idle_hint_timestamp.monotonic);
+ else
+ r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
if (r < 0)
return log_error_errno(r, "Failed to add row to table: %m");
}

View File

@ -0,0 +1,53 @@
From ea3d85221a7ba83ff1d9612d29cc8ca3e054f2fa Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Thu, 25 May 2023 01:20:45 +0800
Subject: [PATCH] loginctl: list-sessions: fix timestamp for idle hint
Follow-up for 556723e738b96a5c2b2d45a96b87b7b80e0c5664
TABLE_TIMESTAMP_RELATIVE takes a realtime timestamp.
(cherry picked from commit be88af3d9646c8bd1aaea3d4a00520e97ee8674d)
Related: #2156786
---
src/login/loginctl.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 65fe182195..1131267015 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -67,7 +67,7 @@ typedef struct SessionStatusInfo {
const char *scope;
const char *desktop;
bool idle_hint;
- dual_timestamp idle_hint_timestamp;
+ usec_t idle_hint_timestamp;
} SessionStatusInfo;
static OutputFlags get_output_flags(void) {
@@ -136,10 +136,10 @@ static int show_table(Table *table, const char *word) {
static int list_sessions(int argc, char *argv[], void *userdata) {
- static const struct bus_properties_map map[] = {
- { "IdleHint", "b", NULL, offsetof(SessionStatusInfo, idle_hint) },
- { "IdleSinceHintMonotonic", "t", NULL, offsetof(SessionStatusInfo, idle_hint_timestamp.monotonic) },
- { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
+ static const struct bus_properties_map map[] = {
+ { "IdleHint", "b", NULL, offsetof(SessionStatusInfo, idle_hint) },
+ { "IdleSinceHint", "t", NULL, offsetof(SessionStatusInfo, idle_hint_timestamp) },
+ { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
{},
};
@@ -210,7 +210,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to add row to table: %m");
if (i.idle_hint)
- r = table_add_cell(table, NULL, TABLE_TIMESTAMP_RELATIVE, &i.idle_hint_timestamp.monotonic);
+ r = table_add_cell(table, NULL, TABLE_TIMESTAMP_RELATIVE, &i.idle_hint_timestamp);
else
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
if (r < 0)

View File

@ -0,0 +1,40 @@
From 0d3f481f791d918380a1b5587529cb8642d3e407 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Tue, 23 May 2023 18:54:30 +0800
Subject: [PATCH] loginctl: also show idle hint in session-status
(cherry picked from commit 82449055af97cf92466dbe132a89c9d889440c3d)
Related: #2156786
---
src/login/loginctl.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 1131267015..80d0a302d3 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -473,6 +473,8 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
{ "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
{ "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
{ "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
+ { "IdleHint", "b", NULL, offsetof(SessionStatusInfo, idle_hint) },
+ { "IdleSinceHint", "t", NULL, offsetof(SessionStatusInfo, idle_hint_timestamp) },
{ "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
{ "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
{}
@@ -571,6 +573,14 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
if (i.state)
printf("\t State: %s\n", i.state);
+ if (i.idle_hint && i.idle_hint_timestamp > 0) {
+ s1 = format_timestamp_relative(since1, sizeof(since1), i.idle_hint_timestamp);
+ s2 = format_timestamp(since2, sizeof(since2), i.idle_hint_timestamp);
+
+ printf("\t Idle: %s since %s (%s)\n", yes_no(i.idle_hint), s2, s1);
+ } else
+ printf("\t Idle: %s\n", yes_no(i.idle_hint));
+
if (i.scope) {
printf("\t Unit: %s\n", i.scope);
show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);

View File

@ -0,0 +1,46 @@
From a741d3b8bc23b4be1b83e393ca864983558a730c Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 23 May 2023 16:24:47 +0200
Subject: [PATCH] core/timer: Always use inactive_exit_timestamp if it is set
If we're doing a daemon-reload, we'll be going from TIMER_DEAD => TIMER_WAITING,
so we won't use inactive_exit_timestamp because TIMER_DEAD != UNIT_ACTIVE, even
though inactive_exit_timestamp is serialized/deserialized and will be valid after
the daemon-reload.
This issue can lead to timers never firing as we'll always calculate the next
elapse based on the current realtime on daemon-reload, so if daemon-reload happens
often enough, the elapse interval will be moved into the future every time, which
means the timer will never trigger.
To fix the issue, let's always use inactive_exit_timestamp if it is set, and only
fall back to the current realtime if it is not set.
(cherry picked from commit 6546045fa0bf84737bd8b2e1e8bf7dd3941d8352)
Resolves: #1719364
---
src/core/timer.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/core/timer.c b/src/core/timer.c
index 990f05fee4..b80f6d714c 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -368,12 +368,10 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
if (t->last_trigger.realtime > 0)
b = t->last_trigger.realtime;
- else {
- if (state_translation_table[t->state] == UNIT_ACTIVE)
- b = UNIT(t)->inactive_exit_timestamp.realtime;
- else
- b = ts.realtime;
- }
+ else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
+ b = UNIT(t)->inactive_exit_timestamp.realtime;
+ else
+ b = ts.realtime;
r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
if (r < 0)

View File

@ -0,0 +1,25 @@
From e7c06a10a106068e5bd9f092edbfcc937954a959 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Wed, 24 May 2023 11:41:37 +0200
Subject: [PATCH] timer: Use dual_timestamp_is_set() in one more place
(cherry picked from commit e21f75afcd95a46261a36a2614712eff6bc119f4)
Related: #1719364
---
src/core/timer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/timer.c b/src/core/timer.c
index b80f6d714c..81468d4ca6 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -366,7 +366,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
* to that. If we don't, just start from
* the activation time. */
- if (t->last_trigger.realtime > 0)
+ if (dual_timestamp_is_set(&t->last_trigger))
b = t->last_trigger.realtime;
else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
b = UNIT(t)->inactive_exit_timestamp.realtime;

View File

@ -0,0 +1,28 @@
From d55687b7489127b4b6be953c54719f3219e852f6 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 13 Jul 2023 14:23:51 +0200
Subject: [PATCH] ci: drop systemd-stable from advanced-commit-linter config
It's sufficient enough to check only the `systemd/systemd` repo.
Related to https://github.com/redhat-plumbers-in-action/advanced-commit-linter/issues/62
rhel-only
Related: #2179309
---
.github/advanced-commit-linter.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/advanced-commit-linter.yml b/.github/advanced-commit-linter.yml
index 327af0467a..0fb74a9dc8 100644
--- a/.github/advanced-commit-linter.yml
+++ b/.github/advanced-commit-linter.yml
@@ -2,7 +2,6 @@ policy:
cherry-pick:
upstream:
- github: systemd/systemd
- - github: systemd/systemd-stable
exception:
note:
- rhel-only

View File

@ -0,0 +1,108 @@
From 048c335acdaaba173574305c9b03677b3fde999f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 11 May 2023 19:21:57 +0900
Subject: [PATCH] core/mount: escape invalid UTF8 char in dbus reply
When What= or Options= may contain invalid UTF8 chars.
Replaces aaf7b0e41105d7b7cf30912cdac32820f011a219 (#27541).
(cherry picked from commit 4804da58536ab7ad46178a03f4d2da49fd8e4ba2)
Resolves: #2158724
---
src/core/dbus-mount.c | 69 +++++++++++++++++++++++++++++++++++--------
1 file changed, 57 insertions(+), 12 deletions(-)
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 3f98d3ecf0..a089b37e04 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -9,21 +9,68 @@
#include "mount.h"
#include "string-util.h"
#include "unit.h"
+#include "utf8.h"
+
+static int property_get_what(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ _cleanup_free_ char *escaped = NULL;
+ Mount *m = userdata;
+ const char *s = NULL;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
-static const char *mount_get_what(const Mount *m) {
if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what)
- return m->parameters_proc_self_mountinfo.what;
- if (m->from_fragment && m->parameters_fragment.what)
- return m->parameters_fragment.what;
- return NULL;
+ s = m->parameters_proc_self_mountinfo.what;
+ else if (m->from_fragment && m->parameters_fragment.what)
+ s = m->parameters_fragment.what;
+
+ if (s) {
+ escaped = utf8_escape_invalid(s);
+ if (!escaped)
+ return -ENOMEM;
+ }
+
+ return sd_bus_message_append_basic(reply, 's', escaped);
}
-static const char *mount_get_options(const Mount *m) {
+static int property_get_options(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ _cleanup_free_ char *escaped = NULL;
+ Mount *m = userdata;
+ const char *s = NULL;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options)
- return m->parameters_proc_self_mountinfo.options;
- if (m->from_fragment && m->parameters_fragment.options)
- return m->parameters_fragment.options;
- return NULL;
+ s = m->parameters_proc_self_mountinfo.options;
+ else if (m->from_fragment && m->parameters_fragment.options)
+ s = m->parameters_fragment.options;
+
+ if (s) {
+ escaped = utf8_escape_invalid(s);
+ if (!escaped)
+ return -ENOMEM;
+ }
+
+ return sd_bus_message_append_basic(reply, 's', escaped);
}
static const char *mount_get_fstype(const Mount *m) {
@@ -34,8 +81,6 @@ static const char *mount_get_fstype(const Mount *m) {
return NULL;
}
-static BUS_DEFINE_PROPERTY_GET(property_get_what, "s", Mount, mount_get_what);
-static BUS_DEFINE_PROPERTY_GET(property_get_options, "s", Mount, mount_get_options);
static BUS_DEFINE_PROPERTY_GET(property_get_type, "s", Mount, mount_get_fstype);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult);

View File

@ -0,0 +1,32 @@
From fd6e63d9c24845c0e9f97d0929d89dbe0c4a4434 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 14 Feb 2019 10:59:13 +0900
Subject: [PATCH] login: add a missing error check for session_set_leader()
session_set_leader() may fail. If it fails, then manager_start_scope()
will trigger assertion.
This may be related to RHBZ#1663704.
(cherry picked from commit fe3ab8458b9c0ead4b3e14ac25b342d8c34376fe)
Related: #2158167
---
src/login/logind-dbus.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 81aacb4eed..5edcf4e43f 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -784,7 +784,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
goto fail;
session_set_user(session, user);
- session_set_leader(session, leader);
+ r = session_set_leader(session, leader);
+ if (r < 0)
+ goto fail;
session->type = t;
session->class = c;

View File

@ -0,0 +1,77 @@
From ab53c4f5c39ab8d34a3cca652de67fe31dbb776d Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 5 Jul 2023 15:27:38 +0200
Subject: [PATCH] logind: reset session leader if we know for a fact that it is
gone
rhel-only
Related: #2158167
---
src/login/logind-dbus.c | 3 +++
src/login/logind-session.c | 18 ++++++++++++++++++
src/login/logind-session.h | 1 +
3 files changed, 22 insertions(+)
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 5edcf4e43f..dbac406035 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -3169,6 +3169,9 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
session->scope_job = mfree(session->scope_job);
(void) session_jobs_reply(session, unit, result);
+ /* Scope job is done so leader should be gone as well. */
+ session_invalidate_leader(session);
+
session_save(session);
user_save(session->user);
}
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index fabf680b61..4edc4b9b88 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -179,6 +179,23 @@ int session_set_leader(Session *s, pid_t pid) {
return 1;
}
+int session_invalidate_leader(Session *s) {
+ assert(s);
+
+ if (s->leader <= 0)
+ return 0;
+
+ if (pid_is_alive(s->leader))
+ return 0;
+
+ (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
+ s->leader = 0;
+
+ (void) session_save(s);
+
+ return 1;
+}
+
static void session_save_devices(Session *s, FILE *f) {
SessionDevice *sd;
Iterator i;
@@ -1092,6 +1109,7 @@ static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents,
/* EOF on the FIFO means the session died abnormally. */
session_remove_fifo(s);
+ session_invalidate_leader(s);
session_stop(s, false);
return 1;
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 6678441bb9..0557696761 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -127,6 +127,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Session *, session_free);
void session_set_user(Session *s, User *u);
int session_set_leader(Session *s, pid_t pid);
+int session_invalidate_leader(Session *s);
bool session_may_gc(Session *s, bool drop_not_started);
void session_add_to_gc_queue(Session *s);
int session_activate(Session *s);

View File

@ -0,0 +1,170 @@
From f80320d15ba6815f0b385e4b8f86f3293fed66ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 16 Dec 2020 15:56:44 +0100
Subject: [PATCH] test-login: skip consistency checks when logind is not active
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There are two ways in swich sd_login_* functions acquire data:
some are derived from the cgroup path, but others use the data serialized
by logind.
When the tests are executed under Fedora's mock, without systemd-spawn
but instead in a traditional chroot, test-login gets confused:
the "outside" cgroup path is visible, so sd_pid_get_unit() and
sd_pid_get_session() work, but sd_session_is_active() and other functions
that need logind data fail.
Such a buildroot setup is fairly bad, but it can be encountered in the wild, so
let's just skip the tests in that case.
/* Information printed is from the live system */
sd_pid_get_unit(0, …) → "session-237.scope"
sd_pid_get_user_unit(0, …) → "n/a"
sd_pid_get_slice(0, …) → "user-1000.slice"
sd_pid_get_session(0, …) → "237"
sd_pid_get_owner_uid(0, …) → 1000
sd_pid_get_cgroup(0, …) → "/user.slice/user-1000.slice/session-237.scope"
sd_uid_get_display(1000, …) → "(null)"
sd_uid_get_sessions(1000, …) → [0] ""
sd_uid_get_seats(1000, …) → [0] ""
Assertion 'r >= 0' failed at src/libsystemd/sd-login/test-login.c:104, function test_login(). Aborting.
(cherry picked from commit ac5644635dba54ce5eb0ff394fc0bc772a984849)
Resolves: #2223582
---
src/libsystemd/sd-login/test-login.c | 98 +++++++++++++++-------------
1 file changed, 52 insertions(+), 46 deletions(-)
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index d24a04ccc8..5a64aef868 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -115,65 +115,71 @@ static void test_login(void) {
if (session) {
r = sd_session_is_active(session);
- assert_se(r >= 0);
- log_info("sd_session_is_active(\"%s\") → %s", session, yes_no(r));
+ if (r == -ENXIO)
+ log_notice("sd_session_is_active() failed with ENXIO, it seems logind is not running.");
+ else {
+ /* All those tests will fail with ENXIO, so let's skip them. */
- r = sd_session_is_remote(session);
- assert_se(r >= 0);
- log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r));
+ assert_se(r >= 0);
+ log_info("sd_session_is_active(\"%s\") → %s", session, yes_no(r));
- r = sd_session_get_state(session, &state);
- assert_se(r == 0);
- log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state);
+ r = sd_session_is_remote(session);
+ assert_se(r >= 0);
+ log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r));
- assert_se(sd_session_get_uid(session, &u) >= 0);
- log_info("sd_session_get_uid(\"%s\") → "UID_FMT, session, u);
- assert_se(u == u2);
+ r = sd_session_get_state(session, &state);
+ assert_se(r == 0);
+ log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state);
- assert_se(sd_session_get_type(session, &type) >= 0);
- log_info("sd_session_get_type(\"%s\") → \"%s\"", session, type);
+ assert_se(sd_session_get_uid(session, &u) >= 0);
+ log_info("sd_session_get_uid(\"%s\") → "UID_FMT, session, u);
+ assert_se(u == u2);
- assert_se(sd_session_get_class(session, &class) >= 0);
- log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class);
+ assert_se(sd_session_get_type(session, &type) >= 0);
+ log_info("sd_session_get_type(\"%s\") → \"%s\"", session, type);
- r = sd_session_get_display(session, &display);
- assert_se(IN_SET(r, 0, -ENODATA));
- log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display));
+ assert_se(sd_session_get_class(session, &class) >= 0);
+ log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class);
- r = sd_session_get_remote_user(session, &remote_user);
- assert_se(IN_SET(r, 0, -ENODATA));
- log_info("sd_session_get_remote_user(\"%s\") → \"%s\"",
- session, strna(remote_user));
+ r = sd_session_get_display(session, &display);
+ assert_se(IN_SET(r, 0, -ENODATA));
+ log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display));
- r = sd_session_get_remote_host(session, &remote_host);
- assert_se(IN_SET(r, 0, -ENODATA));
- log_info("sd_session_get_remote_host(\"%s\") → \"%s\"",
- session, strna(remote_host));
+ r = sd_session_get_remote_user(session, &remote_user);
+ assert_se(IN_SET(r, 0, -ENODATA));
+ log_info("sd_session_get_remote_user(\"%s\") → \"%s\"",
+ session, strna(remote_user));
- r = sd_session_get_seat(session, &seat);
- if (r >= 0) {
- assert_se(seat);
+ r = sd_session_get_remote_host(session, &remote_host);
+ assert_se(IN_SET(r, 0, -ENODATA));
+ log_info("sd_session_get_remote_host(\"%s\") → \"%s\"",
+ session, strna(remote_host));
- log_info("sd_session_get_seat(\"%s\") → \"%s\"", session, seat);
+ r = sd_session_get_seat(session, &seat);
+ if (r >= 0) {
+ assert_se(seat);
- r = sd_seat_can_multi_session(seat);
- assert_se(r >= 0);
- log_info("sd_session_can_multi_seat(\"%s\") → %s", seat, yes_no(r));
+ log_info("sd_session_get_seat(\"%s\") → \"%s\"", session, seat);
- r = sd_seat_can_tty(seat);
- assert_se(r >= 0);
- log_info("sd_session_can_tty(\"%s\") → %s", seat, yes_no(r));
+ r = sd_seat_can_multi_session(seat);
+ assert_se(r >= 0);
+ log_info("sd_session_can_multi_seat(\"%s\") → %s", seat, yes_no(r));
- r = sd_seat_can_graphical(seat);
- assert_se(r >= 0);
- log_info("sd_session_can_graphical(\"%s\") → %s", seat, yes_no(r));
- } else {
- log_info_errno(r, "sd_session_get_seat(\"%s\"): %m", session);
- assert_se(r == -ENODATA);
- }
+ r = sd_seat_can_tty(seat);
+ assert_se(r >= 0);
+ log_info("sd_session_can_tty(\"%s\") → %s", seat, yes_no(r));
- assert_se(sd_uid_get_state(u, &state2) == 0);
- log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
+ r = sd_seat_can_graphical(seat);
+ assert_se(r >= 0);
+ log_info("sd_session_can_graphical(\"%s\") → %s", seat, yes_no(r));
+ } else {
+ log_info_errno(r, "sd_session_get_seat(\"%s\"): %m", session);
+ assert_se(r == -ENODATA);
+ }
+
+ assert_se(sd_uid_get_state(u, &state2) == 0);
+ log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
+ }
}
if (seat) {
@@ -214,7 +220,7 @@ static void test_login(void) {
assert_se(sd_get_seats(NULL) == r);
r = sd_seat_get_active(NULL, &t, NULL);
- assert_se(IN_SET(r, 0, -ENODATA));
+ assert_se(IN_SET(r, 0, -ENODATA, -ENXIO));
log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s / \"%s\"", e(r), strnull(t));
free(t);

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