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