import systemd-239-73.el8

This commit is contained in:
CentOS Sources 2023-03-01 06:10:27 +00:00 committed by Stepan Oksanichenko
parent 48b003cd3a
commit 18d12a5bb4
30 changed files with 3128 additions and 2 deletions

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

@ -13,7 +13,7 @@
Name: systemd
Url: http://www.freedesktop.org/wiki/Software/systemd
Version: 239
Release: 72%{?dist}
Release: 73%{?dist}
# For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager
@ -922,6 +922,35 @@ Patch0869: 0869-systemctl-reintroduce-the-original-halt_main.patch
Patch0870: 0870-systemctl-preserve-old-behavior-unless-requested.patch
Patch0871: 0871-pam_systemd-suppress-LOG_DEBUG-log-messages-if-debug.patch
Patch0872: 0872-udev-net_id-introduce-naming-scheme-for-RHEL-8.8.patch
Patch0873: 0873-journald-add-API-to-move-logging-from-var-to-run-aga.patch
Patch0874: 0874-journalctl-add-new-relinquish-and-smart-relinquish-o.patch
Patch0875: 0875-units-automatically-revert-to-run-logging-on-shutdow.patch
Patch0876: 0876-pstore-Tool-to-archive-contents-of-pstore.patch
Patch0877: 0877-meson-drop-redundant-line.patch
Patch0878: 0878-pstore-drop-unnecessary-initializations.patch
Patch0879: 0879-pstopre-fix-return-value-of-list_files.patch
Patch0880: 0880-pstore-remove-temporary-file-on-failure.patch
Patch0881: 0881-pstore-do-not-add-FILE-journal-entry-if-content_size.patch
Patch0882: 0882-pstore-run-only-when-sys-fs-pstore-is-not-empty.patch
Patch0883: 0883-pstore-fix-use-after-free.patch
Patch0884: 0884-pstore-refuse-to-run-if-arguments-are-specified.patch
Patch0885: 0885-pstore-allow-specifying-src-and-dst-dirs-are-argumen.patch
Patch0886: 0886-pstore-rework-memory-handling-for-dmesg.patch
Patch0887: 0887-pstore-fixes-for-dmesg.txt-reconstruction.patch
Patch0888: 0888-pstore-Don-t-start-systemd-pstore.service-in-contain.patch
Patch0889: 0889-units-pull-in-systemd-pstore.service-from-sysinit.ta.patch
Patch0890: 0890-units-drop-dependency-on-systemd-remount-fs.service-.patch
Patch0891: 0891-units-make-sure-systemd-pstore-stops-at-shutdown.patch
Patch0892: 0892-pstore-Run-after-modules-are-loaded.patch
Patch0893: 0893-pstore-do-not-try-to-load-all-known-pstore-modules.patch
Patch0894: 0894-logind-session-make-stopping-of-idle-session-visible.patch
Patch0895: 0895-journald-Increase-stdout-buffer-size-sooner-when-alm.patch
Patch0896: 0896-journald-rework-end-of-line-marker-handling-to-use-a.patch
Patch0897: 0897-journald-use-the-fact-that-client_context_release-re.patch
Patch0898: 0898-journald-rework-pid-change-handling.patch
Patch0899: 0899-test-Add-a-test-case-for-15654.patch
Patch0900: 0900-test-Stricter-test-case-for-15654-Add-more-checks.patch
Patch0901: 0901-man-document-the-new-_LINE_BREAK-type.patch
%ifarch %{ix86} x86_64 aarch64
%global have_gnu_efi 1
@ -1339,7 +1368,8 @@ python3 %{SOURCE2} %buildroot <<EOF
EOF
%check
%meson_test
# Add --num-processes 1 as workaround for issues on ppc64le - AttributeError: 'NoneType' object has no attribute '_add_reader' - https://github.com/python/cpython/issues/82200
%meson_test --num-processes 1
#############################################################################################
@ -1551,6 +1581,37 @@ fi
%files tests -f .file-list-tests
%changelog
* Mon Feb 27 2023 systemd maintenance team <systemd-maint@redhat.com> - 239-73
- journald: add API to move logging from /var to /run again (#1873540)
- journalctl: add new --relinquish and --smart-relinquish options (#1873540)
- units: automatically revert to /run logging on shutdown if necessary (#1873540)
- pstore: Tool to archive contents of pstore (#2158832)
- meson: drop redundant line (#2158832)
- pstore: drop unnecessary initializations (#2158832)
- pstopre: fix return value of list_files() (#2158832)
- pstore: remove temporary file on failure (#2158832)
- pstore: do not add FILE= journal entry if content_size == 0 (#2158832)
- pstore: run only when /sys/fs/pstore is not empty (#2158832)
- pstore: fix use after free (#2158832)
- pstore: refuse to run if arguments are specified (#2158832)
- pstore: allow specifying src and dst dirs are arguments (#2158832)
- pstore: rework memory handling for dmesg (#2158832)
- pstore: fixes for dmesg.txt reconstruction (#2158832)
- pstore: Don't start systemd-pstore.service in containers (#2158832)
- units: pull in systemd-pstore.service from sysinit.target (#2158832)
- units: drop dependency on systemd-remount-fs.service from systemd-pstore.service (#2158832)
- units: make sure systemd-pstore stops at shutdown (#2158832)
- pstore: Run after modules are loaded (#2158832)
- pstore: do not try to load all known pstore modules (#2158832)
- logind-session: make stopping of idle session visible to admins (#2156780)
- journald: Increase stdout buffer size sooner, when almost full (#2029426)
- journald: rework end of line marker handling to use a field table (#2029426)
- journald: use the fact that client_context_release() returns NULL (#2029426)
- journald: rework pid change handling (#2029426)
- test: Add a test case for #15654 (#2029426)
- test: Stricter test case for #15654 (Add more checks) (#2029426)
- man: document the new _LINE_BREAK= type (#2029426)
* Fri Feb 17 2023 systemd maintenance team <systemd-maint@redhat.com> - 239-72
- test: import logind test from debian/ubuntu test suite (#1866955)
- test: introduce inst_recursive() helper function (#1866955)