journal: Introduce journald-file.c for journal file write related logic
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 30 Nov 2021 15:18:56 +0000 (16:18 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 6 Dec 2021 21:17:38 +0000 (22:17 +0100)
Currently, all the logic related to writing journal files lives in
journal-file.c which is part of libsystemd (sd-journal). Because it's
part of libsystemd, we can't depend on any code from src/shared.

To allow using code from src/shared when writing journal files, let's
gradually move the write related logic from journal-file.c to
journald-file.c in src/journal. This directory is not part of libsystemd
and as such can use code from src/shared.

We can safely remove any journal write related logic from libsystemd as
it's not used by any public APIs in libsystemd.

This commit introduces the new file along with the JournaldFile struct
which wraps an instance of JournalFile. The goal is to gradually move
more functions from journal-file.c and fields from JournalFile to
journald-file.c and JournaldFile respectively.

This commit also modifies all call sites that write journal files to
use JournaldFile instead of JournalFile. All sd-journal tests that
write journal files are moved to src/journal so they can make use of
journald-file.c.

Because the deferred closes logic is only used by journald, we move it
out of journal-file.c as well. In journal_file_open(), we would wait for
any remaining deferred closes for the file we're about to open to complete
before continuing if the file was not newly created. In journald_file_open(),
we call this logic unconditionally since it stands that if a file is newly
created, it can't have any outstanding deferred closes.

No changes in behavior are introduced aside from the earlier execution
of waiting for any deferred closes to complete when opening a new journal
file.

25 files changed:
meson.build
src/journal-remote/journal-remote-write.c
src/journal-remote/journal-remote-write.h
src/journal-remote/journal-remote.c
src/journal-remote/meson.build
src/journal/journald-file.c [new file with mode: 0644]
src/journal/journald-file.h [new file with mode: 0644]
src/journal/journald-server.c
src/journal/journald-server.h
src/journal/journald.c
src/journal/meson.build
src/journal/test-journal-flush.c [new file with mode: 0644]
src/journal/test-journal-interleaving.c [new file with mode: 0644]
src/journal/test-journal-stream.c [new file with mode: 0644]
src/journal/test-journal-verify.c [new file with mode: 0644]
src/journal/test-journal.c [new file with mode: 0644]
src/libsystemd/meson.build
src/libsystemd/sd-journal/journal-file.c
src/libsystemd/sd-journal/journal-file.h
src/libsystemd/sd-journal/sd-journal.c
src/libsystemd/sd-journal/test-journal-flush.c [deleted file]
src/libsystemd/sd-journal/test-journal-interleaving.c [deleted file]
src/libsystemd/sd-journal/test-journal-stream.c [deleted file]
src/libsystemd/sd-journal/test-journal-verify.c [deleted file]
src/libsystemd/sd-journal/test-journal.c [deleted file]

index 43f5bf2c5ab080ddfaa9c5421ea5b59c59ca4e0b..519de53345976f83d7ab58057727dcf60147db9d 100644 (file)
@@ -2814,7 +2814,7 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
         public_programs += executable(
                 'systemd-journal-remote',
                 systemd_journal_remote_sources,
-                include_directories : includes,
+                include_directories : journal_includes,
                 link_with : [libshared,
                              libsystemd_journal_remote],
                 dependencies : [threads,
@@ -2830,7 +2830,7 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
         public_programs += executable(
                 'systemd-journal-gatewayd',
                 systemd_journal_gatewayd_sources,
-                include_directories : includes,
+                include_directories : journal_includes,
                 link_with : [libshared],
                 dependencies : [threads,
                                 libmicrohttpd,
index c953a5e93e0891c4dc0a6108ed6004e6ee7880e8..fd7cb91f2c017b0ca1d8d68ee3fdad60ff900f23 100644 (file)
@@ -3,11 +3,11 @@
 #include "alloc-util.h"
 #include "journal-remote.h"
 
-static int do_rotate(JournalFile **f, bool compress, bool seal) {
-        int r = journal_file_rotate(f, compress, UINT64_MAX, seal, NULL);
+static int do_rotate(JournaldFile **f, bool compress, bool seal) {
+        int r = journald_file_rotate(f, compress, UINT64_MAX, seal, NULL);
         if (r < 0) {
                 if (*f)
-                        log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
+                        log_error_errno(r, "Failed to rotate %s: %m", (*f)->file->path);
                 else
                         log_error_errno(r, "Failed to create rotated journal: %m");
         }
@@ -39,8 +39,8 @@ static Writer* writer_free(Writer *w) {
                 return NULL;
 
         if (w->journal) {
-                log_debug("Closing journal file %s.", w->journal->path);
-                journal_file_close(w->journal);
+                log_debug("Closing journal file %s.", w->journal->file->path);
+                journald_file_close(w->journal);
         }
 
         if (w->server && w->hashmap_key)
@@ -68,15 +68,15 @@ int writer_write(Writer *w,
         assert(iovw);
         assert(iovw->count > 0);
 
-        if (journal_file_rotate_suggested(w->journal, 0, LOG_DEBUG)) {
+        if (journal_file_rotate_suggested(w->journal->file, 0, LOG_DEBUG)) {
                 log_info("%s: Journal header limits reached or header out-of-date, rotating",
-                         w->journal->path);
+                         w->journal->file->path);
                 r = do_rotate(&w->journal, compress, seal);
                 if (r < 0)
                         return r;
         }
 
-        r = journal_file_append_entry(w->journal, ts, boot_id,
+        r = journal_file_append_entry(w->journal->file, ts, boot_id,
                                       iovw->iovec, iovw->count,
                                       &w->seqnum, NULL, NULL);
         if (r >= 0) {
@@ -86,15 +86,15 @@ int writer_write(Writer *w,
         } else if (r == -EBADMSG)
                 return r;
 
-        log_debug_errno(r, "%s: Write failed, rotating: %m", w->journal->path);
+        log_debug_errno(r, "%s: Write failed, rotating: %m", w->journal->file->path);
         r = do_rotate(&w->journal, compress, seal);
         if (r < 0)
                 return r;
         else
-                log_debug("%s: Successfully rotated journal", w->journal->path);
+                log_debug("%s: Successfully rotated journal", w->journal->file->path);
 
         log_debug("Retrying write.");
-        r = journal_file_append_entry(w->journal, ts, boot_id,
+        r = journal_file_append_entry(w->journal->file, ts, boot_id,
                                       iovw->iovec, iovw->count,
                                       &w->seqnum, NULL, NULL);
         if (r < 0)
index 123015b8440cb23f3eebac46fa8175478ed08720..d97f6c674ba79f13019389981dfea9a05acdf879 100644 (file)
@@ -1,13 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-#include "journal-file.h"
+#include "journald-file.h"
 #include "journal-importer.h"
 
 typedef struct RemoteServer RemoteServer;
 
 typedef struct Writer {
-        JournalFile *journal;
+        JournaldFile *journal;
         JournalMetrics metrics;
 
         MMapCache *mmap;
index 9fd6a23076c2a3bfb20023c3151ee3a780cb6ee7..e91b46473be0e58077107da781d1ca190f888d26 100644 (file)
@@ -14,7 +14,7 @@
 #include "errno-util.h"
 #include "escape.h"
 #include "fd-util.h"
-#include "journal-file.h"
+#include "journald-file.h"
 #include "journal-remote-write.h"
 #include "journal-remote.h"
 #include "journald-native.h"
@@ -61,16 +61,16 @@ static int open_output(RemoteServer *s, Writer *w, const char* host) {
                 assert_not_reached();
         }
 
-        r = journal_file_open_reliably(filename,
-                                       O_RDWR|O_CREAT, 0640,
-                                       s->compress, UINT64_MAX, s->seal,
-                                       &w->metrics,
-                                       w->mmap, NULL,
-                                       NULL, &w->journal);
+        r = journald_file_open_reliably(filename,
+                                        O_RDWR|O_CREAT, 0640,
+                                        s->compress, UINT64_MAX, s->seal,
+                                        &w->metrics,
+                                        w->mmap, NULL,
+                                        NULL, &w->journal);
         if (r < 0)
                 return log_error_errno(r, "Failed to open output journal %s: %m", filename);
 
-        log_debug("Opened output file %s", w->journal->path);
+        log_debug("Opened output file %s", w->journal->file->path);
         return 0;
 }
 
index 54b314552b4d666f36ede7a1e3d134f465153369..b9f8b472cb149f4d2d88bf70e475fa1bc179cfec 100644 (file)
@@ -25,6 +25,7 @@ libsystemd_journal_remote = static_library(
         'systemd-journal-remote',
         libsystemd_journal_remote_sources,
         include_directories : journal_includes,
+        link_with : libjournal_core,
         dependencies : [threads,
                         libmicrohttpd,
                         libgnutls,
@@ -77,5 +78,7 @@ endif
 fuzzers += [
         [['src/journal-remote/fuzz-journal-remote.c'],
          [libsystemd_journal_remote,
-          libshared]],
+          libshared],
+         [],
+         [journal_includes]],
 ]
diff --git a/src/journal/journald-file.c b/src/journal/journald-file.c
new file mode 100644 (file)
index 0000000..b12f405
--- /dev/null
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "chattr-util.h"
+#include "fd-util.h"
+#include "format-util.h"
+#include "journal-authenticate.h"
+#include "journald-file.h"
+#include "path-util.h"
+#include "random-util.h"
+#include "set.h"
+#include "sync-util.h"
+
+JournaldFile* journald_file_close(JournaldFile *f) {
+        if (!f)
+                return NULL;
+
+        journal_file_close(f->file);
+
+        return mfree(f);
+}
+
+int journald_file_open(
+                int fd,
+                const char *fname,
+                int flags,
+                mode_t mode,
+                bool compress,
+                uint64_t compress_threshold_bytes,
+                bool seal,
+                JournalMetrics *metrics,
+                MMapCache *mmap_cache,
+                Set *deferred_closes,
+                JournaldFile *template,
+                JournaldFile **ret) {
+        _cleanup_free_ JournaldFile *f = NULL;
+        int r;
+
+        set_clear_with_destructor(deferred_closes, journald_file_close);
+
+        f = new0(JournaldFile, 1);
+        if (!f)
+                return -ENOMEM;
+
+        r = journal_file_open(fd, fname, flags, mode, compress, compress_threshold_bytes, seal, metrics,
+                              mmap_cache, template ? template->file : NULL, &f->file);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(f);
+
+        return 0;
+}
+
+
+JournaldFile* journald_file_initiate_close(JournaldFile *f, Set *deferred_closes) {
+        int r;
+
+        assert(f);
+
+        if (deferred_closes) {
+                r = set_put(deferred_closes, f);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to add file to deferred close set, closing immediately.");
+                else {
+                        (void) journal_file_set_offline(f->file, false);
+                        return NULL;
+                }
+        }
+
+        return journald_file_close(f);
+}
+
+int journald_file_rotate(
+                JournaldFile **f,
+                bool compress,
+                uint64_t compress_threshold_bytes,
+                bool seal,
+                Set *deferred_closes) {
+
+        JournaldFile *new_file = NULL;
+        int r;
+
+        assert(f);
+        assert(*f);
+
+        r = journal_file_archive((*f)->file);
+        if (r < 0)
+                return r;
+
+        r = journald_file_open(
+                        -1,
+                        (*f)->file->path,
+                        (*f)->file->flags,
+                        (*f)->file->mode,
+                        compress,
+                        compress_threshold_bytes,
+                        seal,
+                        NULL,            /* metrics */
+                        (*f)->file->mmap,
+                        deferred_closes,
+                        *f,              /* template */
+                        &new_file);
+
+        journald_file_initiate_close(*f, deferred_closes);
+        *f = new_file;
+
+        return r;
+}
+
+int journald_file_open_reliably(
+                const char *fname,
+                int flags,
+                mode_t mode,
+                bool compress,
+                uint64_t compress_threshold_bytes,
+                bool seal,
+                JournalMetrics *metrics,
+                MMapCache *mmap_cache,
+                Set *deferred_closes,
+                JournaldFile *template,
+                JournaldFile **ret) {
+
+        int r;
+
+        r = journald_file_open(-1, fname, flags, mode, compress, compress_threshold_bytes, seal, metrics,
+                               mmap_cache, deferred_closes, template, ret);
+        if (!IN_SET(r,
+                    -EBADMSG,           /* Corrupted */
+                    -ENODATA,           /* Truncated */
+                    -EHOSTDOWN,         /* Other machine */
+                    -EPROTONOSUPPORT,   /* Incompatible feature */
+                    -EBUSY,             /* Unclean shutdown */
+                    -ESHUTDOWN,         /* Already archived */
+                    -EIO,               /* IO error, including SIGBUS on mmap */
+                    -EIDRM,             /* File has been deleted */
+                    -ETXTBSY))          /* File is from the future */
+                return r;
+
+        if ((flags & O_ACCMODE) == O_RDONLY)
+                return r;
+
+        if (!(flags & O_CREAT))
+                return r;
+
+        if (!endswith(fname, ".journal"))
+                return r;
+
+        /* The file is corrupted. Rotate it away and try it again (but only once) */
+        log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
+
+        r = journal_file_dispose(AT_FDCWD, fname);
+        if (r < 0)
+                return r;
+
+        return journald_file_open(-1, fname, flags, mode, compress, compress_threshold_bytes, seal, metrics,
+                                  mmap_cache, deferred_closes, template, ret);
+}
diff --git a/src/journal/journald-file.h b/src/journal/journald-file.h
new file mode 100644 (file)
index 0000000..7a299bd
--- /dev/null
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "journal-file.h"
+
+typedef struct {
+        JournalFile *file;
+} JournaldFile;
+
+int journald_file_open(
+                int fd,
+                const char *fname,
+                int flags,
+                mode_t mode,
+                bool compress,
+                uint64_t compress_threshold_bytes,
+                bool seal,
+                JournalMetrics *metrics,
+                MMapCache *mmap_cache,
+                Set *deferred_closes,
+                JournaldFile *template,
+                JournaldFile **ret);
+
+JournaldFile* journald_file_close(JournaldFile *f);
+DEFINE_TRIVIAL_CLEANUP_FUNC(JournaldFile*, journald_file_close);
+
+int journald_file_open_reliably(
+                const char *fname,
+                int flags,
+                mode_t mode,
+                bool compress,
+                uint64_t compress_threshold_bytes,
+                bool seal,
+                JournalMetrics *metrics,
+                MMapCache *mmap_cache,
+                Set *deferred_closes,
+                JournaldFile *template,
+                JournaldFile **ret);
+
+JournaldFile* journald_file_initiate_close(JournaldFile *f, Set *deferred_closes);
+int journald_file_rotate(JournaldFile **f, bool compress, uint64_t compress_threshold_bytes, bool seal, Set *deferred_closes);
index 5ba9b3765b9fd41a1a609d46105660ca09ce6f71..3d40c3822e02cebd6679d9df7b9a1cf428c945be 100644 (file)
@@ -29,7 +29,7 @@
 #include "id128-util.h"
 #include "io-util.h"
 #include "journal-authenticate.h"
-#include "journal-file.h"
+#include "journald-file.h"
 #include "journal-internal.h"
 #include "journal-vacuum.h"
 #include "journald-audit.h"
@@ -243,7 +243,7 @@ static bool uid_for_system_journal(uid_t uid) {
         return uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY;
 }
 
-static void server_add_acls(JournalFile *f, uid_t uid) {
+static void server_add_acls(JournaldFile *f, uid_t uid) {
         assert(f);
 
 #if HAVE_ACL
@@ -252,9 +252,9 @@ static void server_add_acls(JournalFile *f, uid_t uid) {
         if (uid_for_system_journal(uid))
                 return;
 
-        r = fd_add_uid_acl_permission(f->fd, uid, ACL_READ);
+        r = fd_add_uid_acl_permission(f->file->fd, uid, ACL_READ);
         if (r < 0)
-                log_warning_errno(r, "Failed to set ACL on %s, ignoring: %m", f->path);
+                log_warning_errno(r, "Failed to set ACL on %s, ignoring: %m", f->file->path);
 #endif
 }
 
@@ -265,9 +265,9 @@ static int open_journal(
                 int flags,
                 bool seal,
                 JournalMetrics *metrics,
-                JournalFile **ret) {
+                JournaldFile **ret) {
 
-        _cleanup_(journal_file_closep) JournalFile *f = NULL;
+        _cleanup_(journald_file_closep) JournaldFile *f = NULL;
         int r;
 
         assert(s);
@@ -275,16 +275,18 @@ static int open_journal(
         assert(ret);
 
         if (reliably)
-                r = journal_file_open_reliably(fname, flags, 0640, s->compress.enabled, s->compress.threshold_bytes,
-                                               seal, metrics, s->mmap, s->deferred_closes, NULL, &f);
+                r = journald_file_open_reliably(fname, flags, 0640, s->compress.enabled,
+                                                s->compress.threshold_bytes, seal, metrics, s->mmap,
+                                                s->deferred_closes, NULL, &f);
         else
-                r = journal_file_open(-1, fname, flags, 0640, s->compress.enabled, s->compress.threshold_bytes, seal,
-                                      metrics, s->mmap, s->deferred_closes, NULL, &f);
+                r = journald_file_open(-1, fname, flags, 0640, s->compress.enabled,
+                                       s->compress.threshold_bytes, seal, metrics, s->mmap,
+                                       s->deferred_closes, NULL, &f);
 
         if (r < 0)
                 return r;
 
-        r = journal_file_enable_post_change_timer(f, s->event, POST_CHANGE_TIMER_INTERVAL_USEC);
+        r = journal_file_enable_post_change_timer(f->file, s->event, POST_CHANGE_TIMER_INTERVAL_USEC);
         if (r < 0)
                 return r;
 
@@ -388,9 +390,9 @@ static int system_journal_open(Server *s, bool flush_requested, bool relinquish_
         return r;
 }
 
-static JournalFile* find_journal(Server *s, uid_t uid) {
+static JournaldFile* find_journal(Server *s, uid_t uid) {
         _cleanup_free_ char *p = NULL;
-        JournalFile *f;
+        JournaldFile *f;
         int r;
 
         assert(s);
@@ -433,7 +435,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
         /* Too many open? Then let's close one (or more) */
         while (ordered_hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
                 assert_se(f = ordered_hashmap_steal_first(s->user_journals));
-                (void) journal_file_close(f);
+                (void) journald_file_close(f);
         }
 
         r = open_journal(s, true, p, O_RDWR|O_CREAT, s->seal, &s->system_storage.metrics, &f);
@@ -442,7 +444,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
 
         r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f);
         if (r < 0) {
-                (void) journal_file_close(f);
+                (void) journald_file_close(f);
                 return s->system_journal;
         }
 
@@ -452,7 +454,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
 
 static int do_rotate(
                 Server *s,
-                JournalFile **f,
+                JournaldFile **f,
                 const char* name,
                 bool seal,
                 uint32_t uid) {
@@ -463,10 +465,10 @@ static int do_rotate(
         if (!*f)
                 return -EINVAL;
 
-        r = journal_file_rotate(f, s->compress.enabled, s->compress.threshold_bytes, seal, s->deferred_closes);
+        r = journald_file_rotate(f, s->compress.enabled, s->compress.threshold_bytes, seal, s->deferred_closes);
         if (r < 0) {
                 if (*f)
-                        return log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
+                        return log_error_errno(r, "Failed to rotate %s: %m", (*f)->file->path);
                 else
                         return log_error_errno(r, "Failed to create new %s journal: %m", name);
         }
@@ -476,15 +478,15 @@ static int do_rotate(
 }
 
 static void server_process_deferred_closes(Server *s) {
-        JournalFile *f;
+        JournaldFile *f;
 
         /* Perform any deferred closes which aren't still offlining. */
         SET_FOREACH(f, s->deferred_closes) {
-                if (journal_file_is_offlining(f))
+                if (journal_file_is_offlining(f->file))
                         continue;
 
                 (void) set_remove(s->deferred_closes, f);
-                (void) journal_file_close(f);
+                (void) journald_file_close(f);
         }
 }
 
@@ -500,10 +502,10 @@ static void server_vacuum_deferred_closes(Server *s) {
 
         /* And now, let's close some more until we reach the limit again. */
         while (set_size(s->deferred_closes) >= DEFERRED_CLOSES_MAX) {
-                JournalFile *f;
+                JournaldFile *f;
 
                 assert_se(f = set_steal_first(s->deferred_closes));
-                journal_file_close(f);
+                journald_file_close(f);
         }
 }
 
@@ -526,7 +528,7 @@ static int vacuum_offline_user_journals(Server *s) {
                 _cleanup_close_ int fd = -1;
                 const char *a, *b;
                 struct dirent *de;
-                JournalFile *f;
+                JournaldFile *f;
                 uid_t uid;
 
                 errno = 0;
@@ -574,18 +576,18 @@ static int vacuum_offline_user_journals(Server *s) {
                 server_vacuum_deferred_closes(s);
 
                 /* Open the file briefly, so that we can archive it */
-                r = journal_file_open(fd,
-                                      full,
-                                      O_RDWR,
-                                      0640,
-                                      s->compress.enabled,
-                                      s->compress.threshold_bytes,
-                                      s->seal,
-                                      &s->system_storage.metrics,
-                                      s->mmap,
-                                      s->deferred_closes,
-                                      NULL,
-                                      &f);
+                r = journald_file_open(fd,
+                                       full,
+                                       O_RDWR,
+                                       0640,
+                                       s->compress.enabled,
+                                       s->compress.threshold_bytes,
+                                       s->seal,
+                                       &s->system_storage.metrics,
+                                       s->mmap,
+                                       s->deferred_closes,
+                                       NULL,
+                                       &f);
                 if (r < 0) {
                         log_warning_errno(r, "Failed to read journal file %s for rotation, trying to move it out of the way: %m", full);
 
@@ -598,20 +600,21 @@ static int vacuum_offline_user_journals(Server *s) {
                         continue;
                 }
 
-                TAKE_FD(fd); /* Donated to journal_file_open() */
+                TAKE_FD(fd); /* Donated to journald_file_open() */
 
-                r = journal_file_archive(f);
+                r = journal_file_archive(f->file);
                 if (r < 0)
                         log_debug_errno(r, "Failed to archive journal file '%s', ignoring: %m", full);
 
-                f = journal_initiate_close(f, s->deferred_closes);
+                journald_file_initiate_close(f, s->deferred_closes);
+                f = NULL;
         }
 
         return 0;
 }
 
 void server_rotate(Server *s) {
-        JournalFile *f;
+        JournaldFile *f;
         void *k;
         int r;
 
@@ -640,17 +643,17 @@ void server_rotate(Server *s) {
 }
 
 void server_sync(Server *s) {
-        JournalFile *f;
+        JournaldFile *f;
         int r;
 
         if (s->system_journal) {
-                r = journal_file_set_offline(s->system_journal, false);
+                r = journal_file_set_offline(s->system_journal->file, false);
                 if (r < 0)
                         log_warning_errno(r, "Failed to sync system journal, ignoring: %m");
         }
 
         ORDERED_HASHMAP_FOREACH(f, s->user_journals) {
-                r = journal_file_set_offline(f, false);
+                r = journal_file_set_offline(f->file, false);
                 if (r < 0)
                         log_warning_errno(r, "Failed to sync user journal, ignoring: %m");
         }
@@ -795,7 +798,7 @@ static bool shall_try_append_again(JournalFile *f, int r) {
 static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n, int priority) {
         bool vacuumed = false, rotate = false;
         struct dual_timestamp ts;
-        JournalFile *f;
+        JournaldFile *f;
         int r;
 
         assert(s);
@@ -822,8 +825,8 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
                 if (!f)
                         return;
 
-                if (journal_file_rotate_suggested(f, s->max_file_usec, LOG_INFO)) {
-                        log_info("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
+                if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_INFO)) {
+                        log_info("%s: Journal header limits reached or header out-of-date, rotating.", f->file->path);
                         rotate = true;
                 }
         }
@@ -840,13 +843,13 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
 
         s->last_realtime_clock = ts.realtime;
 
-        r = journal_file_append_entry(f, &ts, NULL, iovec, n, &s->seqnum, NULL, NULL);
+        r = journal_file_append_entry(f->file, &ts, NULL, iovec, n, &s->seqnum, NULL, NULL);
         if (r >= 0) {
                 server_schedule_sync(s, priority);
                 return;
         }
 
-        if (vacuumed || !shall_try_append_again(f, r)) {
+        if (vacuumed || !shall_try_append_again(f->file, r)) {
                 log_error_errno(r, "Failed to write entry (%zu items, %zu bytes), ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
                 return;
         }
@@ -861,7 +864,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
                 return;
 
         log_debug("Retrying write.");
-        r = journal_file_append_entry(f, &ts, NULL, iovec, n, &s->seqnum, NULL, NULL);
+        r = journal_file_append_entry(f->file, &ts, NULL, iovec, n, &s->seqnum, NULL, NULL);
         if (r < 0)
                 log_error_errno(r, "Failed to write entry (%zu items, %zu bytes) despite vacuuming, ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
         else
@@ -1168,11 +1171,11 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
                         goto finish;
                 }
 
-                r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset);
+                r = journal_file_copy_entry(f, s->system_journal->file, o, f->current_offset);
                 if (r >= 0)
                         continue;
 
-                if (!shall_try_append_again(s->system_journal, r)) {
+                if (!shall_try_append_again(s->system_journal->file, r)) {
                         log_error_errno(r, "Can't write entry: %m");
                         goto finish;
                 }
@@ -1189,7 +1192,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
                 }
 
                 log_debug("Retrying write.");
-                r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset);
+                r = journal_file_copy_entry(f, s->system_journal->file, o, f->current_offset);
                 if (r < 0) {
                         log_error_errno(r, "Can't write entry: %m");
                         goto finish;
@@ -1200,9 +1203,9 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
 
 finish:
         if (s->system_journal)
-                journal_file_post_change(s->system_journal);
+                journal_file_post_change(s->system_journal->file);
 
-        s->runtime_journal = journal_file_close(s->runtime_journal);
+        s->runtime_journal = journald_file_close(s->runtime_journal);
 
         if (r >= 0)
                 (void) rm_rf(s->runtime_storage.path, REMOVE_ROOT);
@@ -1242,9 +1245,9 @@ static int server_relinquish_var(Server *s) {
 
         (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);
+        s->system_journal = journald_file_close(s->system_journal);
+        ordered_hashmap_clear_with_destructor(s->user_journals, journald_file_close);
+        set_clear_with_destructor(s->deferred_closes, journald_file_close);
 
         fn = strjoina(s->runtime_directory, "/flushed");
         if (unlink(fn) < 0 && errno != ENOENT)
@@ -2439,16 +2442,16 @@ int server_init(Server *s, const char *namespace) {
 
 void server_maybe_append_tags(Server *s) {
 #if HAVE_GCRYPT
-        JournalFile *f;
+        JournaldFile *f;
         usec_t n;
 
         n = now(CLOCK_REALTIME);
 
         if (s->system_journal)
-                journal_file_maybe_append_tag(s->system_journal, n);
+                journal_file_maybe_append_tag(s->system_journal->file, n);
 
         ORDERED_HASHMAP_FOREACH(f, s->user_journals)
-                journal_file_maybe_append_tag(f, n);
+                journal_file_maybe_append_tag(f->file, n);
 #endif
 }
 
@@ -2458,17 +2461,17 @@ void server_done(Server *s) {
         free(s->namespace);
         free(s->namespace_field);
 
-        set_free_with_destructor(s->deferred_closes, journal_file_close);
+        set_free_with_destructor(s->deferred_closes, journald_file_close);
 
         while (s->stdout_streams)
                 stdout_stream_free(s->stdout_streams);
 
         client_context_flush_all(s);
 
-        (void) journal_file_close(s->system_journal);
-        (void) journal_file_close(s->runtime_journal);
+        (void) journald_file_close(s->system_journal);
+        (void) journald_file_close(s->runtime_journal);
 
-        ordered_hashmap_free_with_destructor(s->user_journals, journal_file_close);
+        ordered_hashmap_free_with_destructor(s->user_journals, journald_file_close);
 
         varlink_server_unref(s->varlink_server);
 
index 5b7e59cada663057922f31d50a1ad26799dadcc0..92c78a0d741ad8092b33124f84e3450dff156496 100644 (file)
@@ -10,7 +10,7 @@ typedef struct Server Server;
 
 #include "conf-parser.h"
 #include "hashmap.h"
-#include "journal-file.h"
+#include "journald-file.h"
 #include "journald-context.h"
 #include "journald-rate-limit.h"
 #include "journald-stream.h"
@@ -89,8 +89,8 @@ struct Server {
         sd_event_source *watchdog_event_source;
         sd_event_source *idle_event_source;
 
-        JournalFile *runtime_journal;
-        JournalFile *system_journal;
+        JournaldFile *runtime_journal;
+        JournaldFile *system_journal;
         OrderedHashmap *user_journals;
 
         uint64_t seqnum;
index 94aad05de9158604dacdd80d0aee67aaba6ca9b0..3d4044295e310e4392b788ae4645c6c024733441 100644 (file)
@@ -102,7 +102,7 @@ int main(int argc, char *argv[]) {
                 if (server.system_journal) {
                         usec_t u;
 
-                        if (journal_file_next_evolve_usec(server.system_journal, &u)) {
+                        if (journal_file_next_evolve_usec(server.system_journal->file, &u)) {
                                 if (n >= u)
                                         t = 0;
                                 else
index 171e2767368375a29199c98686ec1b634ee9671a..3eeed772cffb94da1baf160478df38e1c3650350 100644 (file)
@@ -7,6 +7,8 @@ sources = files('''
         journald-console.h
         journald-context.c
         journald-context.h
+        journald-file.c
+        journald-file.h
         journald-kmsg.c
         journald-kmsg.h
         journald-native.c
@@ -92,6 +94,26 @@ tests += [
          [libxz,
           liblz4,
           libselinux]],
+
+        [['src/journal/test-journal.c'],
+         [libjournal_core,
+          libshared]],
+
+        [['src/journal/test-journal-stream.c'],
+         [libjournal_core,
+          libshared]],
+
+         [['src/journal/test-journal-flush.c'],
+          [libjournal_core,
+           libshared]],
+
+        [['src/journal/test-journal-verify.c'],
+         [libjournal_core,
+          libshared]],
+
+        [['src/journal/test-journal-interleaving.c'],
+         [libjournal_core,
+          libshared]],
 ]
 
 fuzzers += [
diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c
new file mode 100644 (file)
index 0000000..f0a7024
--- /dev/null
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "sd-journal.h"
+
+#include "alloc-util.h"
+#include "chattr-util.h"
+#include "journald-file.h"
+#include "journal-internal.h"
+#include "macro.h"
+#include "path-util.h"
+#include "string-util.h"
+
+int main(int argc, char *argv[]) {
+        _cleanup_free_ char *fn = NULL;
+        char dn[] = "/var/tmp/test-journal-flush.XXXXXX";
+        JournaldFile *new_journal = NULL;
+        sd_journal *j = NULL;
+        unsigned n = 0;
+        int r;
+
+        assert_se(mkdtemp(dn));
+        (void) chattr_path(dn, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+
+        fn = path_join(dn, "test.journal");
+
+        r = journald_file_open(-1, fn, O_CREAT|O_RDWR, 0644, false, 0, false, NULL, NULL, NULL, NULL, &new_journal);
+        assert_se(r >= 0);
+
+        if (argc > 1)
+                r = sd_journal_open_files(&j, (const char **) strv_skip(argv, 1), 0);
+        else
+                r = sd_journal_open(&j, 0);
+        assert_se(r == 0);
+
+        sd_journal_set_data_threshold(j, 0);
+
+        SD_JOURNAL_FOREACH(j) {
+                Object *o;
+                JournalFile *f;
+
+                f = j->current_file;
+                assert_se(f && f->current_offset > 0);
+
+                r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
+                if (r < 0)
+                        log_error_errno(r, "journal_file_move_to_object failed: %m");
+                assert_se(r >= 0);
+
+                r = journal_file_copy_entry(f, new_journal->file, o, f->current_offset);
+                if (r < 0)
+                        log_warning_errno(r, "journal_file_copy_entry failed: %m");
+                assert_se(r >= 0 ||
+                          IN_SET(r, -EBADMSG,         /* corrupted file */
+                                    -EPROTONOSUPPORT, /* unsupported compression */
+                                    -EIO));           /* file rotated */
+
+                if (++n >= 10000)
+                        break;
+        }
+
+        sd_journal_close(j);
+
+        (void) journald_file_close(new_journal);
+
+        unlink(fn);
+        assert_se(rmdir(dn) == 0);
+
+        return 0;
+}
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
new file mode 100644 (file)
index 0000000..48be6a1
--- /dev/null
@@ -0,0 +1,296 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "sd-journal.h"
+
+#include "alloc-util.h"
+#include "chattr-util.h"
+#include "io-util.h"
+#include "journald-file.h"
+#include "journal-vacuum.h"
+#include "log.h"
+#include "parse-util.h"
+#include "rm-rf.h"
+#include "tests.h"
+#include "util.h"
+
+/* This program tests skipping around in a multi-file journal. */
+
+static bool arg_keep = false;
+
+_noreturn_ static void log_assert_errno(const char *text, int error, const char *file, int line, const char *func) {
+        log_internal(LOG_CRIT, error, file, line, func,
+                     "'%s' failed at %s:%u (%s): %m", text, file, line, func);
+        abort();
+}
+
+#define assert_ret(expr)                                                \
+        do {                                                            \
+                int _r_ = (expr);                                       \
+                if (_unlikely_(_r_ < 0))                                \
+                        log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
+        } while (false)
+
+static JournaldFile *test_open(const char *name) {
+        JournaldFile *f;
+        assert_ret(journald_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f));
+        return f;
+}
+
+static void test_close(JournaldFile *f) {
+        (void) journald_file_close(f);
+}
+
+static void append_number(JournaldFile *f, int n, uint64_t *seqnum) {
+        char *p;
+        dual_timestamp ts;
+        static dual_timestamp previous_ts = {};
+        struct iovec iovec[1];
+
+        dual_timestamp_get(&ts);
+
+        if (ts.monotonic <= previous_ts.monotonic)
+                ts.monotonic = previous_ts.monotonic + 1;
+
+        if (ts.realtime <= previous_ts.realtime)
+                ts.realtime = previous_ts.realtime + 1;
+
+        previous_ts = ts;
+
+        assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
+        iovec[0] = IOVEC_MAKE_STRING(p);
+        assert_ret(journal_file_append_entry(f->file, &ts, NULL, iovec, 1, seqnum, NULL, NULL));
+        free(p);
+}
+
+static void test_check_number (sd_journal *j, int n) {
+        const void *d;
+        _cleanup_free_ char *k;
+        size_t l;
+        int x;
+
+        assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
+        assert_se(k = strndup(d, l));
+        printf("%s\n", k);
+
+        assert_se(safe_atoi(k + 7, &x) >= 0);
+        assert_se(n == x);
+}
+
+static void test_check_numbers_down (sd_journal *j, int count) {
+        int i;
+
+        for (i = 1; i <= count; i++) {
+                int r;
+                test_check_number(j, i);
+                assert_ret(r = sd_journal_next(j));
+                if (i == count)
+                        assert_se(r == 0);
+                else
+                        assert_se(r == 1);
+        }
+
+}
+
+static void test_check_numbers_up (sd_journal *j, int count) {
+        for (int i = count; i >= 1; i--) {
+                int r;
+                test_check_number(j, i);
+                assert_ret(r = sd_journal_previous(j));
+                if (i == 1)
+                        assert_se(r == 0);
+                else
+                        assert_se(r == 1);
+        }
+
+}
+
+static void setup_sequential(void) {
+        JournaldFile *one, *two;
+        one = test_open("one.journal");
+        two = test_open("two.journal");
+        append_number(one, 1, NULL);
+        append_number(one, 2, NULL);
+        append_number(two, 3, NULL);
+        append_number(two, 4, NULL);
+        test_close(one);
+        test_close(two);
+}
+
+static void setup_interleaved(void) {
+        JournaldFile *one, *two;
+        one = test_open("one.journal");
+        two = test_open("two.journal");
+        append_number(one, 1, NULL);
+        append_number(two, 2, NULL);
+        append_number(one, 3, NULL);
+        append_number(two, 4, NULL);
+        test_close(one);
+        test_close(two);
+}
+
+static void mkdtemp_chdir_chattr(char *path) {
+        assert_se(mkdtemp(path));
+        assert_se(chdir(path) >= 0);
+
+        /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
+         * directory during the test run */
+        (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+}
+
+static void test_skip(void (*setup)(void)) {
+        char t[] = "/var/tmp/journal-skip-XXXXXX";
+        sd_journal *j;
+        int r;
+
+        mkdtemp_chdir_chattr(t);
+
+        setup();
+
+        /* Seek to head, iterate down.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_head(j));
+        assert_ret(sd_journal_next(j));
+        test_check_numbers_down(j, 4);
+        sd_journal_close(j);
+
+        /* Seek to tail, iterate up.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_tail(j));
+        assert_ret(sd_journal_previous(j));
+        test_check_numbers_up(j, 4);
+        sd_journal_close(j);
+
+        /* Seek to tail, skip to head, iterate down.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_tail(j));
+        assert_ret(r = sd_journal_previous_skip(j, 4));
+        assert_se(r == 4);
+        test_check_numbers_down(j, 4);
+        sd_journal_close(j);
+
+        /* Seek to head, skip to tail, iterate up.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_head(j));
+        assert_ret(r = sd_journal_next_skip(j, 4));
+        assert_se(r == 4);
+        test_check_numbers_up(j, 4);
+        sd_journal_close(j);
+
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
+
+                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+        }
+
+        puts("------------------------------------------------------------");
+}
+
+static void test_sequence_numbers(void) {
+
+        char t[] = "/var/tmp/journal-seq-XXXXXX";
+        JournaldFile *one, *two;
+        uint64_t seqnum = 0;
+        sd_id128_t seqnum_id;
+
+        mkdtemp_chdir_chattr(t);
+
+        assert_se(journald_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644,
+                                     true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &one) == 0);
+
+        append_number(one, 1, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert_se(seqnum == 1);
+        append_number(one, 2, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert_se(seqnum == 2);
+
+        assert_se(one->file->header->state == STATE_ONLINE);
+        assert_se(!sd_id128_equal(one->file->header->file_id, one->file->header->machine_id));
+        assert_se(!sd_id128_equal(one->file->header->file_id, one->file->header->boot_id));
+        assert_se(sd_id128_equal(one->file->header->file_id, one->file->header->seqnum_id));
+
+        memcpy(&seqnum_id, &one->file->header->seqnum_id, sizeof(sd_id128_t));
+
+        assert_se(journald_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644,
+                                     true, UINT64_MAX, false, NULL, NULL, NULL, one, &two) == 0);
+
+        assert_se(two->file->header->state == STATE_ONLINE);
+        assert_se(!sd_id128_equal(two->file->header->file_id, one->file->header->file_id));
+        assert_se(sd_id128_equal(one->file->header->machine_id, one->file->header->machine_id));
+        assert_se(sd_id128_equal(one->file->header->boot_id, one->file->header->boot_id));
+        assert_se(sd_id128_equal(one->file->header->seqnum_id, one->file->header->seqnum_id));
+
+        append_number(two, 3, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert_se(seqnum == 3);
+        append_number(two, 4, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert_se(seqnum == 4);
+
+        test_close(two);
+
+        append_number(one, 5, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert_se(seqnum == 5);
+
+        append_number(one, 6, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert_se(seqnum == 6);
+
+        test_close(one);
+
+        /* restart server */
+        seqnum = 0;
+
+        assert_se(journald_file_open(-1, "two.journal", O_RDWR, 0,
+                                     true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &two) == 0);
+
+        assert_se(sd_id128_equal(two->file->header->seqnum_id, seqnum_id));
+
+        append_number(two, 7, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert_se(seqnum == 5);
+
+        /* So..., here we have the same seqnum in two files with the
+         * same seqnum_id. */
+
+        test_close(two);
+
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
+
+                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+        }
+}
+
+int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_DEBUG);
+
+        /* journald_file_open requires a valid machine id */
+        if (access("/etc/machine-id", F_OK) != 0)
+                return log_tests_skipped("/etc/machine-id not found");
+
+        arg_keep = argc > 1;
+
+        test_skip(setup_sequential);
+        test_skip(setup_interleaved);
+
+        test_sequence_numbers();
+
+        return 0;
+}
diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c
new file mode 100644 (file)
index 0000000..f7fc433
--- /dev/null
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "sd-journal.h"
+
+#include "alloc-util.h"
+#include "chattr-util.h"
+#include "io-util.h"
+#include "journald-file.h"
+#include "journal-internal.h"
+#include "log.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "rm-rf.h"
+#include "tests.h"
+#include "util.h"
+
+#define N_ENTRIES 200
+
+static void verify_contents(sd_journal *j, unsigned skip) {
+        unsigned i;
+
+        assert_se(j);
+
+        i = 0;
+        SD_JOURNAL_FOREACH(j) {
+                const void *d;
+                char *k, *c;
+                size_t l;
+                unsigned u = 0;
+
+                assert_se(sd_journal_get_cursor(j, &k) >= 0);
+                printf("cursor: %s\n", k);
+                free(k);
+
+                assert_se(sd_journal_get_data(j, "MAGIC", &d, &l) >= 0);
+                printf("\t%.*s\n", (int) l, (const char*) d);
+
+                assert_se(sd_journal_get_data(j, "NUMBER", &d, &l) >= 0);
+                assert_se(k = strndup(d, l));
+                printf("\t%s\n", k);
+
+                if (skip > 0) {
+                        assert_se(safe_atou(k + 7, &u) >= 0);
+                        assert_se(i == u);
+                        i += skip;
+                }
+
+                free(k);
+
+                assert_se(sd_journal_get_cursor(j, &c) >= 0);
+                assert_se(sd_journal_test_cursor(j, c) > 0);
+                free(c);
+        }
+
+        if (skip > 0)
+                assert_se(i == N_ENTRIES);
+}
+
+static void run_test(void) {
+        JournaldFile *one, *two, *three;
+        char t[] = "/var/tmp/journal-stream-XXXXXX";
+        unsigned i;
+        _cleanup_(sd_journal_closep) sd_journal *j = NULL;
+        char *z;
+        const void *data;
+        size_t l;
+        dual_timestamp previous_ts = DUAL_TIMESTAMP_NULL;
+
+        assert_se(mkdtemp(t));
+        assert_se(chdir(t) >= 0);
+        (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+
+        assert_se(journald_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &one) == 0);
+        assert_se(journald_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &two) == 0);
+        assert_se(journald_file_open(-1, "three.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &three) == 0);
+
+        for (i = 0; i < N_ENTRIES; i++) {
+                char *p, *q;
+                dual_timestamp ts;
+                struct iovec iovec[2];
+
+                dual_timestamp_get(&ts);
+
+                if (ts.monotonic <= previous_ts.monotonic)
+                        ts.monotonic = previous_ts.monotonic + 1;
+
+                if (ts.realtime <= previous_ts.realtime)
+                        ts.realtime = previous_ts.realtime + 1;
+
+                previous_ts = ts;
+
+                assert_se(asprintf(&p, "NUMBER=%u", i) >= 0);
+                iovec[0] = IOVEC_MAKE(p, strlen(p));
+
+                assert_se(asprintf(&q, "MAGIC=%s", i % 5 == 0 ? "quux" : "waldo") >= 0);
+
+                iovec[1] = IOVEC_MAKE(q, strlen(q));
+
+                if (i % 10 == 0)
+                        assert_se(journal_file_append_entry(three->file, &ts, NULL, iovec, 2, NULL, NULL, NULL) == 0);
+                else {
+                        if (i % 3 == 0)
+                                assert_se(journal_file_append_entry(two->file, &ts, NULL, iovec, 2, NULL, NULL, NULL) == 0);
+
+                        assert_se(journal_file_append_entry(one->file, &ts, NULL, iovec, 2, NULL, NULL, NULL) == 0);
+                }
+
+                free(p);
+                free(q);
+        }
+
+        (void) journald_file_close(one);
+        (void) journald_file_close(two);
+        (void) journald_file_close(three);
+
+        assert_se(sd_journal_open_directory(&j, t, 0) >= 0);
+
+        assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0);
+        SD_JOURNAL_FOREACH_BACKWARDS(j) {
+                _cleanup_free_ char *c;
+
+                assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0);
+                printf("\t%.*s\n", (int) l, (const char*) data);
+
+                assert_se(sd_journal_get_cursor(j, &c) >= 0);
+                assert_se(sd_journal_test_cursor(j, c) > 0);
+        }
+
+        SD_JOURNAL_FOREACH(j) {
+                _cleanup_free_ char *c;
+
+                assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0);
+                printf("\t%.*s\n", (int) l, (const char*) data);
+
+                assert_se(sd_journal_get_cursor(j, &c) >= 0);
+                assert_se(sd_journal_test_cursor(j, c) > 0);
+        }
+
+        sd_journal_flush_matches(j);
+
+        verify_contents(j, 1);
+
+        printf("NEXT TEST\n");
+        assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0);
+
+        assert_se(z = journal_make_match_string(j));
+        printf("resulting match expression is: %s\n", z);
+        free(z);
+
+        verify_contents(j, 5);
+
+        printf("NEXT TEST\n");
+        sd_journal_flush_matches(j);
+        assert_se(sd_journal_add_match(j, "MAGIC=waldo", 0) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=10", 0) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=11", 0) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=12", 0) >= 0);
+
+        assert_se(z = journal_make_match_string(j));
+        printf("resulting match expression is: %s\n", z);
+        free(z);
+
+        verify_contents(j, 0);
+
+        assert_se(sd_journal_query_unique(j, "NUMBER") >= 0);
+        SD_JOURNAL_FOREACH_UNIQUE(j, data, l)
+                printf("%.*s\n", (int) l, (const char*) data);
+
+        assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+}
+
+int main(int argc, char *argv[]) {
+
+        /* journald_file_open requires a valid machine id */
+        if (access("/etc/machine-id", F_OK) != 0)
+                return log_tests_skipped("/etc/machine-id not found");
+
+        test_setup_logging(LOG_DEBUG);
+
+        /* Run this test twice. Once with old hashing and once with new hashing */
+        assert_se(setenv("SYSTEMD_JOURNAL_KEYED_HASH", "1", 1) >= 0);
+        run_test();
+
+        assert_se(setenv("SYSTEMD_JOURNAL_KEYED_HASH", "0", 1) >= 0);
+        run_test();
+
+        return 0;
+}
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
new file mode 100644 (file)
index 0000000..cf9692b
--- /dev/null
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "chattr-util.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "journald-file.h"
+#include "journal-verify.h"
+#include "log.h"
+#include "rm-rf.h"
+#include "terminal-util.h"
+#include "tests.h"
+#include "util.h"
+
+#define N_ENTRIES 6000
+#define RANDOM_RANGE 77
+
+static void bit_toggle(const char *fn, uint64_t p) {
+        uint8_t b;
+        ssize_t r;
+        int fd;
+
+        fd = open(fn, O_RDWR|O_CLOEXEC);
+        assert_se(fd >= 0);
+
+        r = pread(fd, &b, 1, p/8);
+        assert_se(r == 1);
+
+        b ^= 1 << (p % 8);
+
+        r = pwrite(fd, &b, 1, p/8);
+        assert_se(r == 1);
+
+        safe_close(fd);
+}
+
+static int raw_verify(const char *fn, const char *verification_key) {
+        JournalFile *f;
+        int r;
+
+        r = journal_file_open(-1, fn, O_RDONLY, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, &f);
+        if (r < 0)
+                return r;
+
+        r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false);
+        (void) journal_file_close(f);
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        char t[] = "/var/tmp/journal-XXXXXX";
+        unsigned n;
+        JournalFile *f;
+        JournaldFile *df;
+        const char *verification_key = argv[1];
+        usec_t from = 0, to = 0, total = 0;
+        struct stat st;
+        uint64_t p;
+
+        /* journald_file_open requires a valid machine id */
+        if (access("/etc/machine-id", F_OK) != 0)
+                return log_tests_skipped("/etc/machine-id not found");
+
+        test_setup_logging(LOG_DEBUG);
+
+        assert_se(mkdtemp(t));
+        assert_se(chdir(t) >= 0);
+        (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+
+        log_info("Generating...");
+
+        assert_se(journald_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, NULL, &df) == 0);
+
+        for (n = 0; n < N_ENTRIES; n++) {
+                struct iovec iovec;
+                struct dual_timestamp ts;
+                char *test;
+
+                dual_timestamp_get(&ts);
+
+                assert_se(asprintf(&test, "RANDOM=%lu", random() % RANDOM_RANGE));
+
+                iovec = IOVEC_MAKE_STRING(test);
+
+                assert_se(journal_file_append_entry(df->file, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
+
+                free(test);
+        }
+
+        (void) journald_file_close(df);
+
+        log_info("Verifying...");
+
+        assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, &f) == 0);
+        /* journal_file_print_header(f); */
+        journal_file_dump(f);
+
+        assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0);
+
+        if (verification_key && JOURNAL_HEADER_SEALED(f->header))
+                log_info("=> Validated from %s to %s, %s missing",
+                         FORMAT_TIMESTAMP(from),
+                         FORMAT_TIMESTAMP(to),
+                         FORMAT_TIMESPAN(total > to ? total - to : 0, 0));
+
+        (void) journal_file_close(f);
+
+        if (verification_key) {
+                log_info("Toggling bits...");
+
+                assert_se(stat("test.journal", &st) >= 0);
+
+                for (p = 38448*8+0; p < ((uint64_t) st.st_size * 8); p ++) {
+                        bit_toggle("test.journal", p);
+
+                        log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8);
+
+                        if (raw_verify("test.journal", verification_key) >= 0)
+                                log_notice(ANSI_HIGHLIGHT_RED ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_NORMAL, p / 8, p % 8);
+
+                        bit_toggle("test.journal", p);
+                }
+        }
+
+        log_info("Exiting...");
+
+        assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+
+        return 0;
+}
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
new file mode 100644 (file)
index 0000000..c2c4a75
--- /dev/null
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "chattr-util.h"
+#include "io-util.h"
+#include "journal-authenticate.h"
+#include "journald-file.h"
+#include "journal-vacuum.h"
+#include "log.h"
+#include "rm-rf.h"
+#include "tests.h"
+
+static bool arg_keep = false;
+
+static void mkdtemp_chdir_chattr(char *path) {
+        assert_se(mkdtemp(path));
+        assert_se(chdir(path) >= 0);
+
+        /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
+         * directory during the test run */
+        (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+}
+
+static void test_non_empty(void) {
+        dual_timestamp ts;
+        JournaldFile *f;
+        struct iovec iovec;
+        static const char test[] = "TEST1=1", test2[] = "TEST2=2";
+        Object *o;
+        uint64_t p;
+        sd_id128_t fake_boot_id;
+        char t[] = "/var/tmp/journal-XXXXXX";
+
+        test_setup_logging(LOG_DEBUG);
+
+        mkdtemp_chdir_chattr(t);
+
+        assert_se(journald_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f) == 0);
+
+        assert_se(dual_timestamp_get(&ts));
+        assert_se(sd_id128_randomize(&fake_boot_id) == 0);
+
+        iovec = IOVEC_MAKE_STRING(test);
+        assert_se(journal_file_append_entry(f->file, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
+
+        iovec = IOVEC_MAKE_STRING(test2);
+        assert_se(journal_file_append_entry(f->file, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
+
+        iovec = IOVEC_MAKE_STRING(test);
+        assert_se(journal_file_append_entry(f->file, &ts, &fake_boot_id, &iovec, 1, NULL, NULL, NULL) == 0);
+
+#if HAVE_GCRYPT
+        journal_file_append_tag(f->file);
+#endif
+        journal_file_dump(f->file);
+
+        assert_se(journal_file_next_entry(f->file, 0, DIRECTION_DOWN, &o, &p) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 1);
+
+        assert_se(journal_file_next_entry(f->file, p, DIRECTION_DOWN, &o, &p) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 2);
+
+        assert_se(journal_file_next_entry(f->file, p, DIRECTION_DOWN, &o, &p) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 3);
+        assert_se(sd_id128_equal(o->entry.boot_id, fake_boot_id));
+
+        assert_se(journal_file_next_entry(f->file, p, DIRECTION_DOWN, &o, &p) == 0);
+
+        assert_se(journal_file_next_entry(f->file, 0, DIRECTION_DOWN, &o, &p) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 1);
+
+        assert_se(journal_file_find_data_object(f->file, test, strlen(test), NULL, &p) == 1);
+        assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 1);
+
+        assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 3);
+
+        assert_se(journal_file_find_data_object(f->file, test2, strlen(test2), NULL, &p) == 1);
+        assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 2);
+
+        assert_se(journal_file_next_entry_for_data(f->file, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 2);
+
+        assert_se(journal_file_find_data_object(f->file, "quux", 4, NULL, &p) == 0);
+
+        assert_se(journal_file_move_to_entry_by_seqnum(f->file, 1, DIRECTION_DOWN, &o, NULL) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 1);
+
+        assert_se(journal_file_move_to_entry_by_seqnum(f->file, 3, DIRECTION_DOWN, &o, NULL) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 3);
+
+        assert_se(journal_file_move_to_entry_by_seqnum(f->file, 2, DIRECTION_DOWN, &o, NULL) == 1);
+        assert_se(le64toh(o->entry.seqnum) == 2);
+
+        assert_se(journal_file_move_to_entry_by_seqnum(f->file, 10, DIRECTION_DOWN, &o, NULL) == 0);
+
+        journald_file_rotate(&f, true, UINT64_MAX, true, NULL);
+        journald_file_rotate(&f, true, UINT64_MAX, true, NULL);
+
+        (void) journald_file_close(f);
+
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
+
+                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+        }
+
+        puts("------------------------------------------------------------");
+}
+
+static void test_empty(void) {
+        JournaldFile *f1, *f2, *f3, *f4;
+        char t[] = "/var/tmp/journal-XXXXXX";
+
+        test_setup_logging(LOG_DEBUG);
+
+        mkdtemp_chdir_chattr(t);
+
+        assert_se(journald_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f1) == 0);
+        assert_se(journald_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f2) == 0);
+        assert_se(journald_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f3) == 0);
+        assert_se(journald_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f4) == 0);
+
+        journal_file_print_header(f1->file);
+        puts("");
+        journal_file_print_header(f2->file);
+        puts("");
+        journal_file_print_header(f3->file);
+        puts("");
+        journal_file_print_header(f4->file);
+        puts("");
+
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
+
+                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+        }
+
+        (void) journald_file_close(f1);
+        (void) journald_file_close(f2);
+        (void) journald_file_close(f3);
+        (void) journald_file_close(f4);
+}
+
+#if HAVE_COMPRESSION
+static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
+        dual_timestamp ts;
+        JournaldFile *f;
+        struct iovec iovec;
+        Object *o;
+        uint64_t p;
+        char t[] = "/var/tmp/journal-XXXXXX";
+        char data[2048] = "FIELD=";
+        bool is_compressed;
+        int r;
+
+        assert_se(data_size <= sizeof(data));
+
+        test_setup_logging(LOG_DEBUG);
+
+        mkdtemp_chdir_chattr(t);
+
+        assert_se(journald_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, compress_threshold, true, NULL, NULL, NULL, NULL, &f) == 0);
+
+        dual_timestamp_get(&ts);
+
+        iovec = IOVEC_MAKE(data, data_size);
+        assert_se(journal_file_append_entry(f->file, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
+
+#if HAVE_GCRYPT
+        journal_file_append_tag(f->file);
+#endif
+        journal_file_dump(f->file);
+
+        /* We have to partially reimplement some of the dump logic, because the normal next_entry does the
+         * decompression for us. */
+        p = le64toh(f->file->header->header_size);
+        for (;;) {
+                r = journal_file_move_to_object(f->file, OBJECT_UNUSED, p, &o);
+                assert_se(r == 0);
+                if (o->object.type == OBJECT_DATA)
+                        break;
+
+                assert_se(p < le64toh(f->file->header->tail_object_offset));
+                p = p + ALIGN64(le64toh(o->object.size));
+        }
+
+        is_compressed = (o->object.flags & OBJECT_COMPRESSION_MASK) != 0;
+
+        (void) journald_file_close(f);
+
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
+
+                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+        }
+
+        puts("------------------------------------------------------------");
+
+        return is_compressed;
+}
+
+static void test_min_compress_size(void) {
+        /* Note that XZ will actually fail to compress anything under 80 bytes, so you have to choose the limits
+         * carefully */
+
+        /* DEFAULT_MIN_COMPRESS_SIZE is 512 */
+        assert_se(!check_compressed(UINT64_MAX, 255));
+        assert_se(check_compressed(UINT64_MAX, 513));
+
+        /* compress everything */
+        assert_se(check_compressed(0, 96));
+        assert_se(check_compressed(8, 96));
+
+        /* Ensure we don't try to compress less than 8 bytes */
+        assert_se(!check_compressed(0, 7));
+
+        /* check boundary conditions */
+        assert_se(check_compressed(256, 256));
+        assert_se(!check_compressed(256, 255));
+}
+#endif
+
+int main(int argc, char *argv[]) {
+        arg_keep = argc > 1;
+
+        test_setup_logging(LOG_INFO);
+
+        /* journald_file_open requires a valid machine id */
+        if (access("/etc/machine-id", F_OK) != 0)
+                return log_tests_skipped("/etc/machine-id not found");
+
+        test_non_empty();
+        test_empty();
+#if HAVE_COMPRESSION
+        test_min_compress_size();
+#endif
+
+        return 0;
+}
index 6ee78fd195521fd7b6b4b47ed095902c0b6f5f4a..73c0228248d332b3fe2ee1fac75e771e735c2314 100644 (file)
@@ -190,8 +190,6 @@ custom_target(
 ############################################################
 
 tests += [
-        [['src/libsystemd/sd-journal/test-journal.c']],
-
         [['src/libsystemd/sd-journal/test-journal-send.c']],
 
         [['src/libsystemd/sd-journal/test-journal-match.c']],
@@ -199,16 +197,8 @@ tests += [
         [['src/libsystemd/sd-journal/test-journal-enum.c'],
          [], [], [], '', 'timeout=360'],
 
-        [['src/libsystemd/sd-journal/test-journal-stream.c']],
-
-        [['src/libsystemd/sd-journal/test-journal-flush.c']],
-
         [['src/libsystemd/sd-journal/test-journal-init.c']],
 
-        [['src/libsystemd/sd-journal/test-journal-verify.c']],
-
-        [['src/libsystemd/sd-journal/test-journal-interleaving.c']],
-
         [['src/libsystemd/sd-journal/test-mmap-cache.c']],
 
         [['src/libsystemd/sd-journal/test-catalog.c']],
index 611c8c0d28a2c1bc52461f9a4987d6ef6d8038cf..b2ec6cde542c54a9f748f14c8a9b73e57958c900 100644 (file)
@@ -3562,7 +3562,6 @@ int journal_file_open(
                 bool seal,
                 JournalMetrics *metrics,
                 MMapCache *mmap_cache,
-                Set *deferred_closes,
                 JournalFile *template,
                 JournalFile **ret) {
 
@@ -3747,8 +3746,6 @@ int journal_file_open(
         f->header = h;
 
         if (!newly_created) {
-                set_clear_with_destructor(deferred_closes, journal_file_close);
-
                 r = journal_file_verify_header(f);
                 if (r < 0)
                         goto fail;
@@ -3871,65 +3868,6 @@ int journal_file_archive(JournalFile *f) {
         return 0;
 }
 
-JournalFile* journal_initiate_close(
-                JournalFile *f,
-                Set *deferred_closes) {
-
-        int r;
-
-        assert(f);
-
-        if (deferred_closes) {
-
-                r = set_put(deferred_closes, f);
-                if (r < 0)
-                        log_debug_errno(r, "Failed to add file to deferred close set, closing immediately.");
-                else {
-                        (void) journal_file_set_offline(f, false);
-                        return NULL;
-                }
-        }
-
-        return journal_file_close(f);
-}
-
-int journal_file_rotate(
-                JournalFile **f,
-                bool compress,
-                uint64_t compress_threshold_bytes,
-                bool seal,
-                Set *deferred_closes) {
-
-        JournalFile *new_file = NULL;
-        int r;
-
-        assert(f);
-        assert(*f);
-
-        r = journal_file_archive(*f);
-        if (r < 0)
-                return r;
-
-        r = journal_file_open(
-                        -1,
-                        (*f)->path,
-                        (*f)->flags,
-                        (*f)->mode,
-                        compress,
-                        compress_threshold_bytes,
-                        seal,
-                        NULL,            /* metrics */
-                        (*f)->mmap,
-                        deferred_closes,
-                        *f,              /* template */
-                        &new_file);
-
-        journal_initiate_close(*f, deferred_closes);
-        *f = new_file;
-
-        return r;
-}
-
 int journal_file_dispose(int dir_fd, const char *fname) {
         _cleanup_free_ char *p = NULL;
         _cleanup_close_ int fd = -1;
@@ -3965,55 +3903,6 @@ int journal_file_dispose(int dir_fd, const char *fname) {
         return 0;
 }
 
-int journal_file_open_reliably(
-                const char *fname,
-                int flags,
-                mode_t mode,
-                bool compress,
-                uint64_t compress_threshold_bytes,
-                bool seal,
-                JournalMetrics *metrics,
-                MMapCache *mmap_cache,
-                Set *deferred_closes,
-                JournalFile *template,
-                JournalFile **ret) {
-
-        int r;
-
-        r = journal_file_open(-1, fname, flags, mode, compress, compress_threshold_bytes, seal, metrics, mmap_cache,
-                              deferred_closes, template, ret);
-        if (!IN_SET(r,
-                    -EBADMSG,           /* Corrupted */
-                    -ENODATA,           /* Truncated */
-                    -EHOSTDOWN,         /* Other machine */
-                    -EPROTONOSUPPORT,   /* Incompatible feature */
-                    -EBUSY,             /* Unclean shutdown */
-                    -ESHUTDOWN,         /* Already archived */
-                    -EIO,               /* IO error, including SIGBUS on mmap */
-                    -EIDRM,             /* File has been deleted */
-                    -ETXTBSY))          /* File is from the future */
-                return r;
-
-        if ((flags & O_ACCMODE) == O_RDONLY)
-                return r;
-
-        if (!(flags & O_CREAT))
-                return r;
-
-        if (!endswith(fname, ".journal"))
-                return r;
-
-        /* The file is corrupted. Rotate it away and try it again (but only once) */
-        log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
-
-        r = journal_file_dispose(AT_FDCWD, fname);
-        if (r < 0)
-                return r;
-
-        return journal_file_open(-1, fname, flags, mode, compress, compress_threshold_bytes, seal, metrics, mmap_cache,
-                                 deferred_closes, template, ret);
-}
-
 int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p) {
         uint64_t q, n, xor_hash = 0;
         const sd_id128_t *boot_id;
index 81b2ff23e1d08e64ae242cf7045010aaec625379..0fbd84e31cb83925c6a682bf9837c40ddcad0440 100644 (file)
@@ -138,7 +138,6 @@ int journal_file_open(
                 bool seal,
                 JournalMetrics *metrics,
                 MMapCache *mmap_cache,
-                Set *deferred_closes,
                 JournalFile *template,
                 JournalFile **ret);
 
@@ -148,19 +147,6 @@ JournalFile* journal_file_close(JournalFile *j);
 int journal_file_fstat(JournalFile *f);
 DEFINE_TRIVIAL_CLEANUP_FUNC(JournalFile*, journal_file_close);
 
-int journal_file_open_reliably(
-                const char *fname,
-                int flags,
-                mode_t mode,
-                bool compress,
-                uint64_t compress_threshold_bytes,
-                bool seal,
-                JournalMetrics *metrics,
-                MMapCache *mmap_cache,
-                Set *deferred_closes,
-                JournalFile *template,
-                JournalFile **ret);
-
 #define ALIGN64(x) (((x) + 7ULL) & ~7ULL)
 #define VALID64(x) (((x) & 7ULL) == 0ULL)
 
@@ -246,8 +232,6 @@ void journal_file_dump(JournalFile *f);
 void journal_file_print_header(JournalFile *f);
 
 int journal_file_archive(JournalFile *f);
-JournalFile* journal_initiate_close(JournalFile *f, Set *deferred_closes);
-int journal_file_rotate(JournalFile **f, bool compress, uint64_t compress_threshold_bytes, bool seal, Set *deferred_closes);
 
 int journal_file_dispose(int dir_fd, const char *fname);
 
index 4861726673c2ea223a853d042c5c62708f551611..b3f14cc5483e35377b37f45183687b720848239f 100644 (file)
@@ -1334,7 +1334,7 @@ static int add_any_file(
                 goto finish;
         }
 
-        r = journal_file_open(fd, path, O_RDONLY, 0, false, 0, false, NULL, j->mmap, NULL, NULL, &f);
+        r = journal_file_open(fd, path, O_RDONLY, 0, false, 0, false, NULL, j->mmap, NULL, &f);
         if (r < 0) {
                 log_debug_errno(r, "Failed to open journal file %s: %m", path);
                 goto finish;
diff --git a/src/libsystemd/sd-journal/test-journal-flush.c b/src/libsystemd/sd-journal/test-journal-flush.c
deleted file mode 100644 (file)
index c6fb657..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "sd-journal.h"
-
-#include "alloc-util.h"
-#include "chattr-util.h"
-#include "journal-file.h"
-#include "journal-internal.h"
-#include "macro.h"
-#include "path-util.h"
-#include "string-util.h"
-
-int main(int argc, char *argv[]) {
-        _cleanup_free_ char *fn = NULL;
-        char dn[] = "/var/tmp/test-journal-flush.XXXXXX";
-        JournalFile *new_journal = NULL;
-        sd_journal *j = NULL;
-        unsigned n = 0;
-        int r;
-
-        assert_se(mkdtemp(dn));
-        (void) chattr_path(dn, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
-
-        fn = path_join(dn, "test.journal");
-
-        r = journal_file_open(-1, fn, O_CREAT|O_RDWR, 0644, false, 0, false, NULL, NULL, NULL, NULL, &new_journal);
-        assert_se(r >= 0);
-
-        if (argc > 1)
-                r = sd_journal_open_files(&j, (const char **) strv_skip(argv, 1), 0);
-        else
-                r = sd_journal_open(&j, 0);
-        assert_se(r == 0);
-
-        sd_journal_set_data_threshold(j, 0);
-
-        SD_JOURNAL_FOREACH(j) {
-                Object *o;
-                JournalFile *f;
-
-                f = j->current_file;
-                assert_se(f && f->current_offset > 0);
-
-                r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
-                if (r < 0)
-                        log_error_errno(r, "journal_file_move_to_object failed: %m");
-                assert_se(r >= 0);
-
-                r = journal_file_copy_entry(f, new_journal, o, f->current_offset);
-                if (r < 0)
-                        log_warning_errno(r, "journal_file_copy_entry failed: %m");
-                assert_se(r >= 0 ||
-                          IN_SET(r, -EBADMSG,         /* corrupted file */
-                                    -EPROTONOSUPPORT, /* unsupported compression */
-                                    -EIO));           /* file rotated */
-
-                if (++n >= 10000)
-                        break;
-        }
-
-        sd_journal_close(j);
-
-        (void) journal_file_close(new_journal);
-
-        unlink(fn);
-        assert_se(rmdir(dn) == 0);
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-journal/test-journal-interleaving.c b/src/libsystemd/sd-journal/test-journal-interleaving.c
deleted file mode 100644 (file)
index 62db226..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "sd-journal.h"
-
-#include "alloc-util.h"
-#include "chattr-util.h"
-#include "io-util.h"
-#include "journal-file.h"
-#include "journal-vacuum.h"
-#include "log.h"
-#include "parse-util.h"
-#include "rm-rf.h"
-#include "tests.h"
-#include "util.h"
-
-/* This program tests skipping around in a multi-file journal. */
-
-static bool arg_keep = false;
-
-_noreturn_ static void log_assert_errno(const char *text, int error, const char *file, int line, const char *func) {
-        log_internal(LOG_CRIT, error, file, line, func,
-                     "'%s' failed at %s:%u (%s): %m", text, file, line, func);
-        abort();
-}
-
-#define assert_ret(expr)                                                \
-        do {                                                            \
-                int _r_ = (expr);                                       \
-                if (_unlikely_(_r_ < 0))                                \
-                        log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
-        } while (false)
-
-static JournalFile *test_open(const char *name) {
-        JournalFile *f;
-        assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f));
-        return f;
-}
-
-static void test_close(JournalFile *f) {
-        (void) journal_file_close (f);
-}
-
-static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
-        char *p;
-        dual_timestamp ts;
-        static dual_timestamp previous_ts = {};
-        struct iovec iovec[1];
-
-        dual_timestamp_get(&ts);
-
-        if (ts.monotonic <= previous_ts.monotonic)
-                ts.monotonic = previous_ts.monotonic + 1;
-
-        if (ts.realtime <= previous_ts.realtime)
-                ts.realtime = previous_ts.realtime + 1;
-
-        previous_ts = ts;
-
-        assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
-        iovec[0] = IOVEC_MAKE_STRING(p);
-        assert_ret(journal_file_append_entry(f, &ts, NULL, iovec, 1, seqnum, NULL, NULL));
-        free(p);
-}
-
-static void test_check_number (sd_journal *j, int n) {
-        const void *d;
-        _cleanup_free_ char *k;
-        size_t l;
-        int x;
-
-        assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
-        assert_se(k = strndup(d, l));
-        printf("%s\n", k);
-
-        assert_se(safe_atoi(k + 7, &x) >= 0);
-        assert_se(n == x);
-}
-
-static void test_check_numbers_down (sd_journal *j, int count) {
-        int i;
-
-        for (i = 1; i <= count; i++) {
-                int r;
-                test_check_number(j, i);
-                assert_ret(r = sd_journal_next(j));
-                if (i == count)
-                        assert_se(r == 0);
-                else
-                        assert_se(r == 1);
-        }
-
-}
-
-static void test_check_numbers_up (sd_journal *j, int count) {
-        for (int i = count; i >= 1; i--) {
-                int r;
-                test_check_number(j, i);
-                assert_ret(r = sd_journal_previous(j));
-                if (i == 1)
-                        assert_se(r == 0);
-                else
-                        assert_se(r == 1);
-        }
-
-}
-
-static void setup_sequential(void) {
-        JournalFile *one, *two;
-        one = test_open("one.journal");
-        two = test_open("two.journal");
-        append_number(one, 1, NULL);
-        append_number(one, 2, NULL);
-        append_number(two, 3, NULL);
-        append_number(two, 4, NULL);
-        test_close(one);
-        test_close(two);
-}
-
-static void setup_interleaved(void) {
-        JournalFile *one, *two;
-        one = test_open("one.journal");
-        two = test_open("two.journal");
-        append_number(one, 1, NULL);
-        append_number(two, 2, NULL);
-        append_number(one, 3, NULL);
-        append_number(two, 4, NULL);
-        test_close(one);
-        test_close(two);
-}
-
-static void mkdtemp_chdir_chattr(char *path) {
-        assert_se(mkdtemp(path));
-        assert_se(chdir(path) >= 0);
-
-        /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
-         * directory during the test run */
-        (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
-}
-
-static void test_skip(void (*setup)(void)) {
-        char t[] = "/var/tmp/journal-skip-XXXXXX";
-        sd_journal *j;
-        int r;
-
-        mkdtemp_chdir_chattr(t);
-
-        setup();
-
-        /* Seek to head, iterate down.
-         */
-        assert_ret(sd_journal_open_directory(&j, t, 0));
-        assert_ret(sd_journal_seek_head(j));
-        assert_ret(sd_journal_next(j));
-        test_check_numbers_down(j, 4);
-        sd_journal_close(j);
-
-        /* Seek to tail, iterate up.
-         */
-        assert_ret(sd_journal_open_directory(&j, t, 0));
-        assert_ret(sd_journal_seek_tail(j));
-        assert_ret(sd_journal_previous(j));
-        test_check_numbers_up(j, 4);
-        sd_journal_close(j);
-
-        /* Seek to tail, skip to head, iterate down.
-         */
-        assert_ret(sd_journal_open_directory(&j, t, 0));
-        assert_ret(sd_journal_seek_tail(j));
-        assert_ret(r = sd_journal_previous_skip(j, 4));
-        assert_se(r == 4);
-        test_check_numbers_down(j, 4);
-        sd_journal_close(j);
-
-        /* Seek to head, skip to tail, iterate up.
-         */
-        assert_ret(sd_journal_open_directory(&j, t, 0));
-        assert_ret(sd_journal_seek_head(j));
-        assert_ret(r = sd_journal_next_skip(j, 4));
-        assert_se(r == 4);
-        test_check_numbers_up(j, 4);
-        sd_journal_close(j);
-
-        log_info("Done...");
-
-        if (arg_keep)
-                log_info("Not removing %s", t);
-        else {
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
-
-                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-        }
-
-        puts("------------------------------------------------------------");
-}
-
-static void test_sequence_numbers(void) {
-
-        char t[] = "/var/tmp/journal-seq-XXXXXX";
-        JournalFile *one, *two;
-        uint64_t seqnum = 0;
-        sd_id128_t seqnum_id;
-
-        mkdtemp_chdir_chattr(t);
-
-        assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644,
-                                    true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &one) == 0);
-
-        append_number(one, 1, &seqnum);
-        printf("seqnum=%"PRIu64"\n", seqnum);
-        assert_se(seqnum == 1);
-        append_number(one, 2, &seqnum);
-        printf("seqnum=%"PRIu64"\n", seqnum);
-        assert_se(seqnum == 2);
-
-        assert_se(one->header->state == STATE_ONLINE);
-        assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
-        assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
-        assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
-
-        memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
-
-        assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644,
-                                    true, UINT64_MAX, false, NULL, NULL, NULL, one, &two) == 0);
-
-        assert_se(two->header->state == STATE_ONLINE);
-        assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
-        assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
-        assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
-        assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
-
-        append_number(two, 3, &seqnum);
-        printf("seqnum=%"PRIu64"\n", seqnum);
-        assert_se(seqnum == 3);
-        append_number(two, 4, &seqnum);
-        printf("seqnum=%"PRIu64"\n", seqnum);
-        assert_se(seqnum == 4);
-
-        test_close(two);
-
-        append_number(one, 5, &seqnum);
-        printf("seqnum=%"PRIu64"\n", seqnum);
-        assert_se(seqnum == 5);
-
-        append_number(one, 6, &seqnum);
-        printf("seqnum=%"PRIu64"\n", seqnum);
-        assert_se(seqnum == 6);
-
-        test_close(one);
-
-        /* restart server */
-        seqnum = 0;
-
-        assert_se(journal_file_open(-1, "two.journal", O_RDWR, 0,
-                                    true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &two) == 0);
-
-        assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
-
-        append_number(two, 7, &seqnum);
-        printf("seqnum=%"PRIu64"\n", seqnum);
-        assert_se(seqnum == 5);
-
-        /* So..., here we have the same seqnum in two files with the
-         * same seqnum_id. */
-
-        test_close(two);
-
-        log_info("Done...");
-
-        if (arg_keep)
-                log_info("Not removing %s", t);
-        else {
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
-
-                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-        }
-}
-
-int main(int argc, char *argv[]) {
-        test_setup_logging(LOG_DEBUG);
-
-        /* journal_file_open requires a valid machine id */
-        if (access("/etc/machine-id", F_OK) != 0)
-                return log_tests_skipped("/etc/machine-id not found");
-
-        arg_keep = argc > 1;
-
-        test_skip(setup_sequential);
-        test_skip(setup_interleaved);
-
-        test_sequence_numbers();
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-journal/test-journal-stream.c b/src/libsystemd/sd-journal/test-journal-stream.c
deleted file mode 100644 (file)
index ca1eaae..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "sd-journal.h"
-
-#include "alloc-util.h"
-#include "chattr-util.h"
-#include "io-util.h"
-#include "journal-file.h"
-#include "journal-internal.h"
-#include "log.h"
-#include "macro.h"
-#include "parse-util.h"
-#include "rm-rf.h"
-#include "tests.h"
-#include "util.h"
-
-#define N_ENTRIES 200
-
-static void verify_contents(sd_journal *j, unsigned skip) {
-        unsigned i;
-
-        assert_se(j);
-
-        i = 0;
-        SD_JOURNAL_FOREACH(j) {
-                const void *d;
-                char *k, *c;
-                size_t l;
-                unsigned u = 0;
-
-                assert_se(sd_journal_get_cursor(j, &k) >= 0);
-                printf("cursor: %s\n", k);
-                free(k);
-
-                assert_se(sd_journal_get_data(j, "MAGIC", &d, &l) >= 0);
-                printf("\t%.*s\n", (int) l, (const char*) d);
-
-                assert_se(sd_journal_get_data(j, "NUMBER", &d, &l) >= 0);
-                assert_se(k = strndup(d, l));
-                printf("\t%s\n", k);
-
-                if (skip > 0) {
-                        assert_se(safe_atou(k + 7, &u) >= 0);
-                        assert_se(i == u);
-                        i += skip;
-                }
-
-                free(k);
-
-                assert_se(sd_journal_get_cursor(j, &c) >= 0);
-                assert_se(sd_journal_test_cursor(j, c) > 0);
-                free(c);
-        }
-
-        if (skip > 0)
-                assert_se(i == N_ENTRIES);
-}
-
-static void run_test(void) {
-        JournalFile *one, *two, *three;
-        char t[] = "/var/tmp/journal-stream-XXXXXX";
-        unsigned i;
-        _cleanup_(sd_journal_closep) sd_journal *j = NULL;
-        char *z;
-        const void *data;
-        size_t l;
-        dual_timestamp previous_ts = DUAL_TIMESTAMP_NULL;
-
-        assert_se(mkdtemp(t));
-        assert_se(chdir(t) >= 0);
-        (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
-
-        assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &one) == 0);
-        assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &two) == 0);
-        assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &three) == 0);
-
-        for (i = 0; i < N_ENTRIES; i++) {
-                char *p, *q;
-                dual_timestamp ts;
-                struct iovec iovec[2];
-
-                dual_timestamp_get(&ts);
-
-                if (ts.monotonic <= previous_ts.monotonic)
-                        ts.monotonic = previous_ts.monotonic + 1;
-
-                if (ts.realtime <= previous_ts.realtime)
-                        ts.realtime = previous_ts.realtime + 1;
-
-                previous_ts = ts;
-
-                assert_se(asprintf(&p, "NUMBER=%u", i) >= 0);
-                iovec[0] = IOVEC_MAKE(p, strlen(p));
-
-                assert_se(asprintf(&q, "MAGIC=%s", i % 5 == 0 ? "quux" : "waldo") >= 0);
-
-                iovec[1] = IOVEC_MAKE(q, strlen(q));
-
-                if (i % 10 == 0)
-                        assert_se(journal_file_append_entry(three, &ts, NULL, iovec, 2, NULL, NULL, NULL) == 0);
-                else {
-                        if (i % 3 == 0)
-                                assert_se(journal_file_append_entry(two, &ts, NULL, iovec, 2, NULL, NULL, NULL) == 0);
-
-                        assert_se(journal_file_append_entry(one, &ts, NULL, iovec, 2, NULL, NULL, NULL) == 0);
-                }
-
-                free(p);
-                free(q);
-        }
-
-        (void) journal_file_close(one);
-        (void) journal_file_close(two);
-        (void) journal_file_close(three);
-
-        assert_se(sd_journal_open_directory(&j, t, 0) >= 0);
-
-        assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0);
-        SD_JOURNAL_FOREACH_BACKWARDS(j) {
-                _cleanup_free_ char *c;
-
-                assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0);
-                printf("\t%.*s\n", (int) l, (const char*) data);
-
-                assert_se(sd_journal_get_cursor(j, &c) >= 0);
-                assert_se(sd_journal_test_cursor(j, c) > 0);
-        }
-
-        SD_JOURNAL_FOREACH(j) {
-                _cleanup_free_ char *c;
-
-                assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0);
-                printf("\t%.*s\n", (int) l, (const char*) data);
-
-                assert_se(sd_journal_get_cursor(j, &c) >= 0);
-                assert_se(sd_journal_test_cursor(j, c) > 0);
-        }
-
-        sd_journal_flush_matches(j);
-
-        verify_contents(j, 1);
-
-        printf("NEXT TEST\n");
-        assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0);
-
-        assert_se(z = journal_make_match_string(j));
-        printf("resulting match expression is: %s\n", z);
-        free(z);
-
-        verify_contents(j, 5);
-
-        printf("NEXT TEST\n");
-        sd_journal_flush_matches(j);
-        assert_se(sd_journal_add_match(j, "MAGIC=waldo", 0) >= 0);
-        assert_se(sd_journal_add_match(j, "NUMBER=10", 0) >= 0);
-        assert_se(sd_journal_add_match(j, "NUMBER=11", 0) >= 0);
-        assert_se(sd_journal_add_match(j, "NUMBER=12", 0) >= 0);
-
-        assert_se(z = journal_make_match_string(j));
-        printf("resulting match expression is: %s\n", z);
-        free(z);
-
-        verify_contents(j, 0);
-
-        assert_se(sd_journal_query_unique(j, "NUMBER") >= 0);
-        SD_JOURNAL_FOREACH_UNIQUE(j, data, l)
-                printf("%.*s\n", (int) l, (const char*) data);
-
-        assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-}
-
-int main(int argc, char *argv[]) {
-
-        /* journal_file_open requires a valid machine id */
-        if (access("/etc/machine-id", F_OK) != 0)
-                return log_tests_skipped("/etc/machine-id not found");
-
-        test_setup_logging(LOG_DEBUG);
-
-        /* Run this test twice. Once with old hashing and once with new hashing */
-        assert_se(setenv("SYSTEMD_JOURNAL_KEYED_HASH", "1", 1) >= 0);
-        run_test();
-
-        assert_se(setenv("SYSTEMD_JOURNAL_KEYED_HASH", "0", 1) >= 0);
-        run_test();
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-journal/test-journal-verify.c b/src/libsystemd/sd-journal/test-journal-verify.c
deleted file mode 100644 (file)
index 8eb9ca8..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "chattr-util.h"
-#include "fd-util.h"
-#include "io-util.h"
-#include "journal-file.h"
-#include "journal-verify.h"
-#include "log.h"
-#include "rm-rf.h"
-#include "terminal-util.h"
-#include "tests.h"
-#include "util.h"
-
-#define N_ENTRIES 6000
-#define RANDOM_RANGE 77
-
-static void bit_toggle(const char *fn, uint64_t p) {
-        uint8_t b;
-        ssize_t r;
-        int fd;
-
-        fd = open(fn, O_RDWR|O_CLOEXEC);
-        assert_se(fd >= 0);
-
-        r = pread(fd, &b, 1, p/8);
-        assert_se(r == 1);
-
-        b ^= 1 << (p % 8);
-
-        r = pwrite(fd, &b, 1, p/8);
-        assert_se(r == 1);
-
-        safe_close(fd);
-}
-
-static int raw_verify(const char *fn, const char *verification_key) {
-        JournalFile *f;
-        int r;
-
-        r = journal_file_open(-1, fn, O_RDONLY, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, NULL, &f);
-        if (r < 0)
-                return r;
-
-        r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false);
-        (void) journal_file_close(f);
-
-        return r;
-}
-
-int main(int argc, char *argv[]) {
-        char t[] = "/var/tmp/journal-XXXXXX";
-        unsigned n;
-        JournalFile *f;
-        const char *verification_key = argv[1];
-        usec_t from = 0, to = 0, total = 0;
-        struct stat st;
-        uint64_t p;
-
-        /* journal_file_open requires a valid machine id */
-        if (access("/etc/machine-id", F_OK) != 0)
-                return log_tests_skipped("/etc/machine-id not found");
-
-        test_setup_logging(LOG_DEBUG);
-
-        assert_se(mkdtemp(t));
-        assert_se(chdir(t) >= 0);
-        (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
-
-        log_info("Generating...");
-
-        assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
-
-        for (n = 0; n < N_ENTRIES; n++) {
-                struct iovec iovec;
-                struct dual_timestamp ts;
-                char *test;
-
-                dual_timestamp_get(&ts);
-
-                assert_se(asprintf(&test, "RANDOM=%lu", random() % RANDOM_RANGE));
-
-                iovec = IOVEC_MAKE_STRING(test);
-
-                assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
-
-                free(test);
-        }
-
-        (void) journal_file_close(f);
-
-        log_info("Verifying...");
-
-        assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
-        /* journal_file_print_header(f); */
-        journal_file_dump(f);
-
-        assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0);
-
-        if (verification_key && JOURNAL_HEADER_SEALED(f->header))
-                log_info("=> Validated from %s to %s, %s missing",
-                         FORMAT_TIMESTAMP(from),
-                         FORMAT_TIMESTAMP(to),
-                         FORMAT_TIMESPAN(total > to ? total - to : 0, 0));
-
-        (void) journal_file_close(f);
-
-        if (verification_key) {
-                log_info("Toggling bits...");
-
-                assert_se(stat("test.journal", &st) >= 0);
-
-                for (p = 38448*8+0; p < ((uint64_t) st.st_size * 8); p ++) {
-                        bit_toggle("test.journal", p);
-
-                        log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8);
-
-                        if (raw_verify("test.journal", verification_key) >= 0)
-                                log_notice(ANSI_HIGHLIGHT_RED ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_NORMAL, p / 8, p % 8);
-
-                        bit_toggle("test.journal", p);
-                }
-        }
-
-        log_info("Exiting...");
-
-        assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-
-        return 0;
-}
diff --git a/src/libsystemd/sd-journal/test-journal.c b/src/libsystemd/sd-journal/test-journal.c
deleted file mode 100644 (file)
index bf69111..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "chattr-util.h"
-#include "io-util.h"
-#include "journal-authenticate.h"
-#include "journal-file.h"
-#include "journal-vacuum.h"
-#include "log.h"
-#include "rm-rf.h"
-#include "tests.h"
-
-static bool arg_keep = false;
-
-static void mkdtemp_chdir_chattr(char *path) {
-        assert_se(mkdtemp(path));
-        assert_se(chdir(path) >= 0);
-
-        /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
-         * directory during the test run */
-        (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
-}
-
-static void test_non_empty(void) {
-        dual_timestamp ts;
-        JournalFile *f;
-        struct iovec iovec;
-        static const char test[] = "TEST1=1", test2[] = "TEST2=2";
-        Object *o;
-        uint64_t p;
-        sd_id128_t fake_boot_id;
-        char t[] = "/var/tmp/journal-XXXXXX";
-
-        test_setup_logging(LOG_DEBUG);
-
-        mkdtemp_chdir_chattr(t);
-
-        assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f) == 0);
-
-        assert_se(dual_timestamp_get(&ts));
-        assert_se(sd_id128_randomize(&fake_boot_id) == 0);
-
-        iovec = IOVEC_MAKE_STRING(test);
-        assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
-
-        iovec = IOVEC_MAKE_STRING(test2);
-        assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
-
-        iovec = IOVEC_MAKE_STRING(test);
-        assert_se(journal_file_append_entry(f, &ts, &fake_boot_id, &iovec, 1, NULL, NULL, NULL) == 0);
-
-#if HAVE_GCRYPT
-        journal_file_append_tag(f);
-#endif
-        journal_file_dump(f);
-
-        assert_se(journal_file_next_entry(f, 0, DIRECTION_DOWN, &o, &p) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 1);
-
-        assert_se(journal_file_next_entry(f, p, DIRECTION_DOWN, &o, &p) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 2);
-
-        assert_se(journal_file_next_entry(f, p, DIRECTION_DOWN, &o, &p) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 3);
-        assert_se(sd_id128_equal(o->entry.boot_id, fake_boot_id));
-
-        assert_se(journal_file_next_entry(f, p, DIRECTION_DOWN, &o, &p) == 0);
-
-        assert_se(journal_file_next_entry(f, 0, DIRECTION_DOWN, &o, &p) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 1);
-
-        assert_se(journal_file_find_data_object(f, test, strlen(test), NULL, &p) == 1);
-        assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 1);
-
-        assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 3);
-
-        assert_se(journal_file_find_data_object(f, test2, strlen(test2), NULL, &p) == 1);
-        assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 2);
-
-        assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 2);
-
-        assert_se(journal_file_find_data_object(f, "quux", 4, NULL, &p) == 0);
-
-        assert_se(journal_file_move_to_entry_by_seqnum(f, 1, DIRECTION_DOWN, &o, NULL) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 1);
-
-        assert_se(journal_file_move_to_entry_by_seqnum(f, 3, DIRECTION_DOWN, &o, NULL) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 3);
-
-        assert_se(journal_file_move_to_entry_by_seqnum(f, 2, DIRECTION_DOWN, &o, NULL) == 1);
-        assert_se(le64toh(o->entry.seqnum) == 2);
-
-        assert_se(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0);
-
-        journal_file_rotate(&f, true, UINT64_MAX, true, NULL);
-        journal_file_rotate(&f, true, UINT64_MAX, true, NULL);
-
-        (void) journal_file_close(f);
-
-        log_info("Done...");
-
-        if (arg_keep)
-                log_info("Not removing %s", t);
-        else {
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
-
-                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-        }
-
-        puts("------------------------------------------------------------");
-}
-
-static void test_empty(void) {
-        JournalFile *f1, *f2, *f3, *f4;
-        char t[] = "/var/tmp/journal-XXXXXX";
-
-        test_setup_logging(LOG_DEBUG);
-
-        mkdtemp_chdir_chattr(t);
-
-        assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f1) == 0);
-
-        assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f2) == 0);
-
-        assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f3) == 0);
-
-        assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f4) == 0);
-
-        journal_file_print_header(f1);
-        puts("");
-        journal_file_print_header(f2);
-        puts("");
-        journal_file_print_header(f3);
-        puts("");
-        journal_file_print_header(f4);
-        puts("");
-
-        log_info("Done...");
-
-        if (arg_keep)
-                log_info("Not removing %s", t);
-        else {
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
-
-                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-        }
-
-        (void) journal_file_close(f1);
-        (void) journal_file_close(f2);
-        (void) journal_file_close(f3);
-        (void) journal_file_close(f4);
-}
-
-#if HAVE_COMPRESSION
-static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
-        dual_timestamp ts;
-        JournalFile *f;
-        struct iovec iovec;
-        Object *o;
-        uint64_t p;
-        char t[] = "/var/tmp/journal-XXXXXX";
-        char data[2048] = "FIELD=";
-        bool is_compressed;
-        int r;
-
-        assert_se(data_size <= sizeof(data));
-
-        test_setup_logging(LOG_DEBUG);
-
-        mkdtemp_chdir_chattr(t);
-
-        assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, compress_threshold, true, NULL, NULL, NULL, NULL, &f) == 0);
-
-        dual_timestamp_get(&ts);
-
-        iovec = IOVEC_MAKE(data, data_size);
-        assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
-
-#if HAVE_GCRYPT
-        journal_file_append_tag(f);
-#endif
-        journal_file_dump(f);
-
-        /* We have to partially reimplement some of the dump logic, because the normal next_entry does the
-         * decompression for us. */
-        p = le64toh(f->header->header_size);
-        for (;;) {
-                r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
-                assert_se(r == 0);
-                if (o->object.type == OBJECT_DATA)
-                        break;
-
-                assert_se(p < le64toh(f->header->tail_object_offset));
-                p = p + ALIGN64(le64toh(o->object.size));
-        }
-
-        is_compressed = (o->object.flags & OBJECT_COMPRESSION_MASK) != 0;
-
-        (void) journal_file_close(f);
-
-        log_info("Done...");
-
-        if (arg_keep)
-                log_info("Not removing %s", t);
-        else {
-                journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
-
-                assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-        }
-
-        puts("------------------------------------------------------------");
-
-        return is_compressed;
-}
-
-static void test_min_compress_size(void) {
-        /* Note that XZ will actually fail to compress anything under 80 bytes, so you have to choose the limits
-         * carefully */
-
-        /* DEFAULT_MIN_COMPRESS_SIZE is 512 */
-        assert_se(!check_compressed(UINT64_MAX, 255));
-        assert_se(check_compressed(UINT64_MAX, 513));
-
-        /* compress everything */
-        assert_se(check_compressed(0, 96));
-        assert_se(check_compressed(8, 96));
-
-        /* Ensure we don't try to compress less than 8 bytes */
-        assert_se(!check_compressed(0, 7));
-
-        /* check boundary conditions */
-        assert_se(check_compressed(256, 256));
-        assert_se(!check_compressed(256, 255));
-}
-#endif
-
-int main(int argc, char *argv[]) {
-        arg_keep = argc > 1;
-
-        test_setup_logging(LOG_INFO);
-
-        /* journal_file_open requires a valid machine id */
-        if (access("/etc/machine-id", F_OK) != 0)
-                return log_tests_skipped("/etc/machine-id not found");
-
-        test_non_empty();
-        test_empty();
-#if HAVE_COMPRESSION
-        test_min_compress_size();
-#endif
-
-        return 0;
-}