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