journal: move several tests to libsystemd/sd-journal
This also renames test-journal-xyz for journald (rather than sd-journal) to test-journald-xyz.
This commit is contained in:
+2
-22
@@ -103,11 +103,7 @@ executables += [
|
||||
],
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal-append.c'),
|
||||
'type' : 'manual',
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal-config.c'),
|
||||
'sources' : files('test-journald-config.c'),
|
||||
'dependencies' : [
|
||||
liblz4,
|
||||
libselinux,
|
||||
@@ -115,16 +111,7 @@ executables += [
|
||||
],
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal-flush.c'),
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal-interleaving.c'),
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal-stream.c'),
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal-syslog.c'),
|
||||
'sources' : files('test-journald-syslog.c'),
|
||||
'dependencies' : [
|
||||
liblz4,
|
||||
libselinux,
|
||||
@@ -132,13 +119,6 @@ executables += [
|
||||
threads,
|
||||
],
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal-verify.c'),
|
||||
'timeout' : 90,
|
||||
},
|
||||
journal_test_template + {
|
||||
'sources' : files('test-journal.c'),
|
||||
},
|
||||
journal_fuzz_template + {
|
||||
'sources' : files(
|
||||
'fuzz-journald-audit.c',
|
||||
|
||||
@@ -1,269 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "chattr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "io-util.h"
|
||||
#include "journal-file-util.h"
|
||||
#include "log.h"
|
||||
#include "mmap-cache.h"
|
||||
#include "parse-util.h"
|
||||
#include "random-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
static int journal_append_message(JournalFile *mj, const char *message) {
|
||||
struct iovec iovec;
|
||||
struct dual_timestamp ts;
|
||||
|
||||
assert(mj);
|
||||
assert(message);
|
||||
|
||||
dual_timestamp_get(&ts);
|
||||
iovec = IOVEC_MAKE_STRING(message);
|
||||
return journal_file_append_entry(
|
||||
mj,
|
||||
&ts,
|
||||
/* boot_id= */ NULL,
|
||||
&iovec,
|
||||
/* n_iovec= */ 1,
|
||||
/* seqnum= */ NULL,
|
||||
/* seqnum_id= */ NULL,
|
||||
/* ret_object= */ NULL,
|
||||
/* ret_offset= */ NULL);
|
||||
}
|
||||
|
||||
static int journal_corrupt_and_append(uint64_t start_offset, uint64_t step) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *mmap_cache = NULL;
|
||||
_cleanup_(rm_rf_physical_and_freep) char *tempdir = NULL;
|
||||
_cleanup_(journal_file_offline_closep) JournalFile *mj = NULL;
|
||||
uint64_t start, end;
|
||||
int r;
|
||||
|
||||
mmap_cache = mmap_cache_new();
|
||||
assert_se(mmap_cache);
|
||||
|
||||
/* journal_file_open() requires a valid machine id */
|
||||
if (sd_id128_get_machine(NULL) < 0)
|
||||
return log_tests_skipped("No valid machine ID found");
|
||||
|
||||
assert_se(mkdtemp_malloc("/tmp/journal-append-XXXXXX", &tempdir) >= 0);
|
||||
assert_se(chdir(tempdir) >= 0);
|
||||
(void) chattr_path(tempdir, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
|
||||
|
||||
log_debug("Opening journal %s/system.journal", tempdir);
|
||||
|
||||
r = journal_file_open(
|
||||
/* fd= */ -1,
|
||||
"system.journal",
|
||||
O_RDWR|O_CREAT,
|
||||
JOURNAL_COMPRESS,
|
||||
0644,
|
||||
/* compress_threshold_bytes= */ UINT64_MAX,
|
||||
/* metrics= */ NULL,
|
||||
mmap_cache,
|
||||
/* template= */ NULL,
|
||||
&mj);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open the journal: %m");
|
||||
|
||||
assert_se(mj);
|
||||
|
||||
/* Add a couple of initial messages */
|
||||
for (int i = 0; i < 10; i++) {
|
||||
_cleanup_free_ char *message = NULL;
|
||||
|
||||
assert_se(asprintf(&message, "MESSAGE=Initial message %d", i) >= 0);
|
||||
r = journal_append_message(mj, message);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write to the journal: %m");
|
||||
}
|
||||
|
||||
start = start_offset == UINT64_MAX ? random_u64() % mj->last_stat.st_size : start_offset;
|
||||
end = (uint64_t) mj->last_stat.st_size;
|
||||
|
||||
/* Print the initial offset at which we start flipping bits, which can be
|
||||
* later used to reproduce a potential fail */
|
||||
log_info("Start offset: %" PRIu64 ", corrupt-step: %" PRIu64, start, step);
|
||||
fflush(stdout);
|
||||
|
||||
if (start >= end)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Start offset >= journal size, can't continue");
|
||||
|
||||
for (uint64_t offset = start; offset < end; offset += step) {
|
||||
_cleanup_free_ char *message = NULL;
|
||||
uint8_t b;
|
||||
|
||||
/* Flip a bit in the journal file */
|
||||
r = pread(mj->fd, &b, 1, offset);
|
||||
assert_se(r == 1);
|
||||
b |= 0x1;
|
||||
r = pwrite(mj->fd, &b, 1, offset);
|
||||
assert_se(r == 1);
|
||||
|
||||
/* Close and reopen the journal to flush all caches and remap
|
||||
* the corrupted journal */
|
||||
mj = journal_file_offline_close(mj);
|
||||
r = journal_file_open(
|
||||
/* fd= */ -1,
|
||||
"system.journal",
|
||||
O_RDWR|O_CREAT,
|
||||
JOURNAL_COMPRESS,
|
||||
0644,
|
||||
/* compress_threshold_bytes= */ UINT64_MAX,
|
||||
/* metrics= */ NULL,
|
||||
mmap_cache,
|
||||
/* template= */ NULL,
|
||||
&mj);
|
||||
if (r < 0) {
|
||||
/* The corrupted journal might get rejected during reopening
|
||||
* if it's corrupted enough (especially its header), so
|
||||
* treat this as a success if it doesn't crash */
|
||||
log_info_errno(r, "Failed to reopen the journal: %m");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Try to write something to the (possibly corrupted) journal */
|
||||
assert_se(asprintf(&message, "MESSAGE=Hello world %" PRIu64, offset) >= 0);
|
||||
r = journal_append_message(mj, message);
|
||||
if (r < 0) {
|
||||
/* We care only about crashes or sanitizer errors,
|
||||
* failed write without any crash is a success */
|
||||
log_info_errno(r, "Failed to write to the journal: %m");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
uint64_t start_offset = UINT64_MAX;
|
||||
uint64_t iterations = 100;
|
||||
uint64_t iteration_step = 1;
|
||||
uint64_t corrupt_step = 31;
|
||||
bool sequential = false, run_one = false;
|
||||
int c, r;
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
enum {
|
||||
ARG_START_OFFSET = 0x1000,
|
||||
ARG_ITERATIONS,
|
||||
ARG_ITERATION_STEP,
|
||||
ARG_CORRUPT_STEP,
|
||||
ARG_SEQUENTIAL,
|
||||
ARG_RUN_ONE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "start-offset", required_argument, NULL, ARG_START_OFFSET },
|
||||
{ "iterations", required_argument, NULL, ARG_ITERATIONS },
|
||||
{ "iteration-step", required_argument, NULL, ARG_ITERATION_STEP },
|
||||
{ "corrupt-step", required_argument, NULL, ARG_CORRUPT_STEP },
|
||||
{ "sequential", no_argument, NULL, ARG_SEQUENTIAL },
|
||||
{ "run-one", required_argument, NULL, ARG_RUN_ONE },
|
||||
{}
|
||||
};
|
||||
|
||||
assert_se(argc >= 0);
|
||||
assert_se(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
printf("Syntax:\n"
|
||||
" %s [OPTION...]\n"
|
||||
"Options:\n"
|
||||
" --start-offset=OFFSET Offset at which to start corrupting the journal\n"
|
||||
" (default: random offset is picked, unless\n"
|
||||
" --sequential is used - in that case we use 0 + iteration)\n"
|
||||
" --iterations=ITER Number of iterations to perform before exiting\n"
|
||||
" (default: 100)\n"
|
||||
" --iteration-step=STEP Iteration step (default: 1)\n"
|
||||
" --corrupt-step=STEP Corrupt every n-th byte starting from OFFSET (default: 31)\n"
|
||||
" --sequential Go through offsets sequentially instead of picking\n"
|
||||
" a random one on each iteration. If set, we go through\n"
|
||||
" offsets <0; ITER), or <OFFSET, ITER) if --start-offset=\n"
|
||||
" is set (default: false)\n"
|
||||
" --run-one=OFFSET Single shot mode for reproducing issues. Takes the same\n"
|
||||
" offset as --start-offset= and does only one iteration\n"
|
||||
, program_invocation_short_name);
|
||||
return 0;
|
||||
|
||||
case ARG_START_OFFSET:
|
||||
r = safe_atou64(optarg, &start_offset);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid starting offset: %m");
|
||||
break;
|
||||
|
||||
case ARG_ITERATIONS:
|
||||
r = safe_atou64(optarg, &iterations);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid value for iterations: %m");
|
||||
break;
|
||||
|
||||
case ARG_CORRUPT_STEP:
|
||||
r = safe_atou64(optarg, &corrupt_step);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid value for corrupt-step: %m");
|
||||
break;
|
||||
|
||||
case ARG_ITERATION_STEP:
|
||||
r = safe_atou64(optarg, &iteration_step);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid value for iteration-step: %m");
|
||||
break;
|
||||
|
||||
case ARG_SEQUENTIAL:
|
||||
sequential = true;
|
||||
break;
|
||||
|
||||
case ARG_RUN_ONE:
|
||||
r = safe_atou64(optarg, &start_offset);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid offset: %m");
|
||||
|
||||
run_one = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (run_one)
|
||||
/* Reproducer mode */
|
||||
return journal_corrupt_and_append(start_offset, corrupt_step);
|
||||
|
||||
for (uint64_t i = 0; i < iterations; i++) {
|
||||
uint64_t offset = UINT64_MAX;
|
||||
|
||||
log_info("Iteration #%" PRIu64 ", step: %" PRIu64, i, iteration_step);
|
||||
|
||||
if (sequential)
|
||||
offset = (start_offset == UINT64_MAX ? 0 : start_offset) + i * iteration_step;
|
||||
|
||||
r = journal_corrupt_and_append(offset, corrupt_step);
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
if (r > 0)
|
||||
/* Reached the end of the journal file */
|
||||
break;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,82 +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-util.h"
|
||||
#include "journal-internal.h"
|
||||
#include "macro.h"
|
||||
#include "path-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "string-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
static void test_journal_flush(int argc, char *argv[]) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
_cleanup_(rm_rf_physical_and_freep) char *dn = NULL;
|
||||
JournalFile *new_journal = NULL;
|
||||
sd_journal *j = NULL;
|
||||
unsigned n = 0;
|
||||
int r;
|
||||
|
||||
assert_se(m = mmap_cache_new());
|
||||
assert_se(mkdtemp_malloc("/var/tmp/test-journal-flush.XXXXXX", &dn) >= 0);
|
||||
(void) chattr_path(dn, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
|
||||
|
||||
assert_se(fn = path_join(dn, "test.journal"));
|
||||
|
||||
r = journal_file_open(-1, fn, O_CREAT|O_RDWR, 0, 0644, 0, NULL, m, 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, NULL, NULL);
|
||||
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 */
|
||||
-EREMCHG)); /* clock rollback */
|
||||
|
||||
if (++n >= 10000)
|
||||
break;
|
||||
}
|
||||
|
||||
sd_journal_close(j);
|
||||
|
||||
(void) journal_file_offline_close(new_journal);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
test_journal_flush(argc, argv);
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
test_journal_flush(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,559 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
#include "sd-journal.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "chattr-util.h"
|
||||
#include "io-util.h"
|
||||
#include "journal-file-util.h"
|
||||
#include "journal-vacuum.h"
|
||||
#include "log.h"
|
||||
#include "logs-show.h"
|
||||
#include "parse-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "tests.h"
|
||||
|
||||
/* This program tests skipping around in a multi-file journal. */
|
||||
|
||||
static bool arg_keep = false;
|
||||
static dual_timestamp previous_ts = {};
|
||||
|
||||
_noreturn_ static void log_assert_errno(const char *text, int error, const char *file, unsigned 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__, __func__); \
|
||||
} while (false)
|
||||
|
||||
static JournalFile *test_open_internal(const char *name, JournalFileFlags flags) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
JournalFile *f;
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != NULL);
|
||||
|
||||
assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, flags, 0644, UINT64_MAX, NULL, m, NULL, &f));
|
||||
return f;
|
||||
}
|
||||
|
||||
static JournalFile *test_open(const char *name) {
|
||||
return test_open_internal(name, JOURNAL_COMPRESS);
|
||||
}
|
||||
|
||||
static JournalFile *test_open_strict(const char *name) {
|
||||
return test_open_internal(name, JOURNAL_COMPRESS | JOURNAL_STRICT_ORDER);
|
||||
}
|
||||
|
||||
static void test_close(JournalFile *f) {
|
||||
(void) journal_file_offline_close(f);
|
||||
}
|
||||
|
||||
static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint64_t *seqnum) {
|
||||
_cleanup_free_ char *p = NULL, *q = NULL;
|
||||
dual_timestamp ts;
|
||||
struct iovec iovec[2];
|
||||
size_t n_iov = 0;
|
||||
|
||||
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[n_iov++] = IOVEC_MAKE_STRING(p);
|
||||
|
||||
if (boot_id) {
|
||||
assert_se(q = strjoin("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id)));
|
||||
iovec[n_iov++] = IOVEC_MAKE_STRING(q);
|
||||
}
|
||||
|
||||
assert_ret(journal_file_append_entry(f, &ts, boot_id, iovec, n_iov, seqnum, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
static void append_unreferenced_data(JournalFile *f, const sd_id128_t *boot_id) {
|
||||
_cleanup_free_ char *q = NULL;
|
||||
dual_timestamp ts;
|
||||
struct iovec iovec;
|
||||
|
||||
assert(boot_id);
|
||||
|
||||
ts.monotonic = usec_sub_unsigned(previous_ts.monotonic, 10);
|
||||
ts.realtime = usec_sub_unsigned(previous_ts.realtime, 10);
|
||||
|
||||
assert_se(q = strjoin("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id)));
|
||||
iovec = IOVEC_MAKE_STRING(q);
|
||||
|
||||
assert_se(journal_file_append_entry(f, &ts, boot_id, &iovec, 1, NULL, NULL, NULL, NULL) == -EREMCHG);
|
||||
}
|
||||
|
||||
static void test_check_number(sd_journal *j, int n) {
|
||||
sd_id128_t boot_id;
|
||||
const void *d;
|
||||
_cleanup_free_ char *k = NULL;
|
||||
size_t l;
|
||||
int x;
|
||||
|
||||
assert_se(sd_journal_get_monotonic_usec(j, NULL, &boot_id) >= 0);
|
||||
assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
|
||||
assert_se(k = strndup(d, l));
|
||||
printf("%s %s (expected=%i)\n", SD_ID128_TO_STRING(boot_id), k, n);
|
||||
|
||||
assert_se(safe_atoi(k + STRLEN("NUMBER="), &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 *f1, *f2, *f3;
|
||||
sd_id128_t id;
|
||||
|
||||
f1 = test_open("one.journal");
|
||||
f2 = test_open("two.journal");
|
||||
f3 = test_open("three.journal");
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
log_info("boot_id: %s", SD_ID128_TO_STRING(id));
|
||||
append_number(f1, 1, &id, NULL);
|
||||
append_number(f1, 2, &id, NULL);
|
||||
append_number(f1, 3, &id, NULL);
|
||||
append_number(f2, 4, &id, NULL);
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
log_info("boot_id: %s", SD_ID128_TO_STRING(id));
|
||||
append_number(f2, 5, &id, NULL);
|
||||
append_number(f2, 6, &id, NULL);
|
||||
append_number(f3, 7, &id, NULL);
|
||||
append_number(f3, 8, &id, NULL);
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
log_info("boot_id: %s", SD_ID128_TO_STRING(id));
|
||||
append_number(f3, 9, &id, NULL);
|
||||
test_close(f1);
|
||||
test_close(f2);
|
||||
test_close(f3);
|
||||
}
|
||||
|
||||
static void setup_interleaved(void) {
|
||||
JournalFile *f1, *f2, *f3;
|
||||
sd_id128_t id;
|
||||
|
||||
f1 = test_open("one.journal");
|
||||
f2 = test_open("two.journal");
|
||||
f3 = test_open("three.journal");
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
log_info("boot_id: %s", SD_ID128_TO_STRING(id));
|
||||
append_number(f1, 1, &id, NULL);
|
||||
append_number(f2, 2, &id, NULL);
|
||||
append_number(f3, 3, &id, NULL);
|
||||
append_number(f1, 4, &id, NULL);
|
||||
append_number(f2, 5, &id, NULL);
|
||||
append_number(f3, 6, &id, NULL);
|
||||
append_number(f1, 7, &id, NULL);
|
||||
append_number(f2, 8, &id, NULL);
|
||||
append_number(f3, 9, &id, NULL);
|
||||
test_close(f1);
|
||||
test_close(f2);
|
||||
test_close(f3);
|
||||
}
|
||||
|
||||
static void setup_unreferenced_data(void) {
|
||||
JournalFile *f1, *f2, *f3;
|
||||
sd_id128_t id;
|
||||
|
||||
/* For issue #29275. */
|
||||
|
||||
f1 = test_open_strict("one.journal");
|
||||
f2 = test_open_strict("two.journal");
|
||||
f3 = test_open_strict("three.journal");
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
log_info("boot_id: %s", SD_ID128_TO_STRING(id));
|
||||
append_number(f1, 1, &id, NULL);
|
||||
append_number(f1, 2, &id, NULL);
|
||||
append_number(f1, 3, &id, NULL);
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
log_info("boot_id: %s", SD_ID128_TO_STRING(id));
|
||||
append_unreferenced_data(f1, &id);
|
||||
append_number(f2, 4, &id, NULL);
|
||||
append_number(f2, 5, &id, NULL);
|
||||
append_number(f2, 6, &id, NULL);
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
log_info("boot_id: %s", SD_ID128_TO_STRING(id));
|
||||
append_unreferenced_data(f2, &id);
|
||||
append_number(f3, 7, &id, NULL);
|
||||
append_number(f3, 8, &id, NULL);
|
||||
append_number(f3, 9, &id, NULL);
|
||||
test_close(f1);
|
||||
test_close(f2);
|
||||
test_close(f3);
|
||||
}
|
||||
|
||||
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_one(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_se(sd_journal_next(j) == 1); /* pointing to the first entry */
|
||||
test_check_numbers_down(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to head, iterate down. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_head(j));
|
||||
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
|
||||
assert_se(sd_journal_previous(j) == 0); /* no-op */
|
||||
test_check_numbers_down(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to head twice, iterate down. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_head(j));
|
||||
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
|
||||
assert_ret(sd_journal_seek_head(j));
|
||||
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
|
||||
test_check_numbers_down(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to head, move to previous, then iterate down. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_head(j));
|
||||
assert_se(sd_journal_previous(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
|
||||
test_check_numbers_down(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to head, walk several steps, then iterate down. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_head(j));
|
||||
assert_se(sd_journal_previous(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_previous(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_previous(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
|
||||
assert_se(sd_journal_previous(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_previous(j) == 0); /* no-op */
|
||||
test_check_numbers_down(j, 9);
|
||||
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_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
|
||||
test_check_numbers_up(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to tail twice, iterate up. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_tail(j));
|
||||
assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
|
||||
assert_ret(sd_journal_seek_tail(j));
|
||||
assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
|
||||
test_check_numbers_up(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to tail, move to next, then iterate up. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_tail(j));
|
||||
assert_se(sd_journal_next(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
|
||||
test_check_numbers_up(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to tail, walk several steps, then iterate up. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_tail(j));
|
||||
assert_se(sd_journal_next(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_next(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_next(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry. */
|
||||
assert_se(sd_journal_next(j) == 0); /* no-op */
|
||||
assert_se(sd_journal_next(j) == 0); /* no-op */
|
||||
test_check_numbers_up(j, 9);
|
||||
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_se(sd_journal_previous_skip(j, 9) == 9); /* pointing to the first entry. */
|
||||
test_check_numbers_down(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to tail, skip to head in a more complex way, then iterate down. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_tail(j));
|
||||
assert_se(sd_journal_next(j) == 0);
|
||||
assert_se(sd_journal_previous_skip(j, 4) == 4);
|
||||
assert_se(sd_journal_previous_skip(j, 5) == 5);
|
||||
assert_se(sd_journal_previous(j) == 0);
|
||||
assert_se(sd_journal_previous_skip(j, 5) == 0);
|
||||
assert_se(sd_journal_next(j) == 1);
|
||||
assert_se(sd_journal_previous_skip(j, 5) == 1);
|
||||
assert_se(sd_journal_next(j) == 1);
|
||||
assert_se(sd_journal_next(j) == 1);
|
||||
assert_se(sd_journal_previous(j) == 1);
|
||||
assert_se(sd_journal_next(j) == 1);
|
||||
assert_se(sd_journal_next(j) == 1);
|
||||
assert_se(sd_journal_previous_skip(j, 5) == 3);
|
||||
test_check_numbers_down(j, 9);
|
||||
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_se(sd_journal_next_skip(j, 9) == 9);
|
||||
test_check_numbers_up(j, 9);
|
||||
sd_journal_close(j);
|
||||
|
||||
/* Seek to head, skip to tail in a more complex way, then iterate up. */
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_ret(sd_journal_seek_head(j));
|
||||
assert_se(sd_journal_previous(j) == 0);
|
||||
assert_se(sd_journal_next_skip(j, 4) == 4);
|
||||
assert_se(sd_journal_next_skip(j, 5) == 5);
|
||||
assert_se(sd_journal_next(j) == 0);
|
||||
assert_se(sd_journal_next_skip(j, 5) == 0);
|
||||
assert_se(sd_journal_previous(j) == 1);
|
||||
assert_se(sd_journal_next_skip(j, 5) == 1);
|
||||
assert_se(sd_journal_previous(j) == 1);
|
||||
assert_se(sd_journal_previous(j) == 1);
|
||||
assert_se(sd_journal_next(j) == 1);
|
||||
assert_se(sd_journal_previous(j) == 1);
|
||||
assert_se(sd_journal_previous(j) == 1);
|
||||
assert_se(r = sd_journal_next_skip(j, 5) == 3);
|
||||
test_check_numbers_up(j, 9);
|
||||
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("------------------------------------------------------------");
|
||||
}
|
||||
|
||||
TEST(skip) {
|
||||
test_skip_one(setup_sequential);
|
||||
test_skip_one(setup_interleaved);
|
||||
}
|
||||
|
||||
static void test_boot_id_one(void (*setup)(void), size_t n_boots_expected) {
|
||||
char t[] = "/var/tmp/journal-boot-id-XXXXXX";
|
||||
sd_journal *j;
|
||||
_cleanup_free_ BootId *boots = NULL;
|
||||
size_t n_boots;
|
||||
|
||||
mkdtemp_chdir_chattr(t);
|
||||
|
||||
setup();
|
||||
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_se(journal_get_boots(j, &boots, &n_boots) >= 0);
|
||||
assert_se(boots);
|
||||
assert_se(n_boots == n_boots_expected);
|
||||
sd_journal_close(j);
|
||||
|
||||
FOREACH_ARRAY(b, boots, n_boots) {
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_se(journal_find_boot_by_id(j, b->id) == 1);
|
||||
sd_journal_close(j);
|
||||
}
|
||||
|
||||
for (int i = - (int) n_boots + 1; i <= (int) n_boots; i++) {
|
||||
sd_id128_t id;
|
||||
|
||||
assert_ret(sd_journal_open_directory(&j, t, 0));
|
||||
assert_se(journal_find_boot_by_offset(j, i, &id) == 1);
|
||||
if (i <= 0)
|
||||
assert_se(sd_id128_equal(id, boots[n_boots + i - 1].id));
|
||||
else
|
||||
assert_se(sd_id128_equal(id, boots[i - 1].id));
|
||||
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("------------------------------------------------------------");
|
||||
}
|
||||
|
||||
TEST(boot_id) {
|
||||
test_boot_id_one(setup_sequential, 3);
|
||||
test_boot_id_one(setup_unreferenced_data, 3);
|
||||
}
|
||||
|
||||
static void test_sequence_numbers_one(void) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
char t[] = "/var/tmp/journal-seq-XXXXXX";
|
||||
JournalFile *one, *two;
|
||||
uint64_t seqnum = 0;
|
||||
sd_id128_t seqnum_id;
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != NULL);
|
||||
|
||||
mkdtemp_chdir_chattr(t);
|
||||
|
||||
assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
|
||||
UINT64_MAX, NULL, m, NULL, &one) == 0);
|
||||
|
||||
append_number(one, 1, NULL, &seqnum);
|
||||
printf("seqnum=%"PRIu64"\n", seqnum);
|
||||
assert_se(seqnum == 1);
|
||||
append_number(one, 2, NULL, &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->tail_entry_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, JOURNAL_COMPRESS, 0644,
|
||||
UINT64_MAX, NULL, m, 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(two->header->machine_id, one->header->machine_id));
|
||||
assert_se(sd_id128_is_null(two->header->tail_entry_boot_id)); /* Not written yet. */
|
||||
assert_se(sd_id128_equal(two->header->seqnum_id, one->header->seqnum_id));
|
||||
|
||||
append_number(two, 3, NULL, &seqnum);
|
||||
printf("seqnum=%"PRIu64"\n", seqnum);
|
||||
assert_se(seqnum == 3);
|
||||
append_number(two, 4, NULL, &seqnum);
|
||||
printf("seqnum=%"PRIu64"\n", seqnum);
|
||||
assert_se(seqnum == 4);
|
||||
|
||||
/* Verify tail_entry_boot_id. */
|
||||
assert_se(sd_id128_equal(two->header->tail_entry_boot_id, one->header->tail_entry_boot_id));
|
||||
|
||||
test_close(two);
|
||||
|
||||
append_number(one, 5, NULL, &seqnum);
|
||||
printf("seqnum=%"PRIu64"\n", seqnum);
|
||||
assert_se(seqnum == 5);
|
||||
|
||||
append_number(one, 6, NULL, &seqnum);
|
||||
printf("seqnum=%"PRIu64"\n", seqnum);
|
||||
assert_se(seqnum == 6);
|
||||
|
||||
test_close(one);
|
||||
|
||||
/* If the machine-id is not initialized, the header file verification
|
||||
* (which happens when re-opening a journal file) will fail. */
|
||||
if (sd_id128_get_machine(NULL) >= 0) {
|
||||
/* restart server */
|
||||
seqnum = 0;
|
||||
|
||||
assert_se(journal_file_open(-1, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0,
|
||||
UINT64_MAX, NULL, m, NULL, &two) == 0);
|
||||
|
||||
assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
|
||||
|
||||
append_number(two, 7, NULL, &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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(sequence_numbers) {
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
test_sequence_numbers_one();
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
test_sequence_numbers_one();
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
/* 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 = saved_argc > 1;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
|
||||
@@ -1,201 +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-util.h"
|
||||
#include "journal-internal.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "tests.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) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
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;
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != 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, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &one) == 0);
|
||||
assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &two) == 0);
|
||||
assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, 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, NULL) == 0);
|
||||
else {
|
||||
if (i % 3 == 0)
|
||||
assert_se(journal_file_append_entry(two, &ts, NULL, iovec, 2, NULL, NULL, NULL, NULL) == 0);
|
||||
|
||||
assert_se(journal_file_append_entry(one, &ts, NULL, iovec, 2, NULL, NULL, NULL, NULL) == 0);
|
||||
}
|
||||
|
||||
free(p);
|
||||
free(q);
|
||||
}
|
||||
|
||||
(void) journal_file_offline_close(one);
|
||||
(void) journal_file_offline_close(two);
|
||||
(void) journal_file_offline_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 multiple times with different configurations of features. */
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_KEYED_HASH", "0", 1) >= 0);
|
||||
run_test();
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_KEYED_HASH", "1", 1) >= 0);
|
||||
run_test();
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
run_test();
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
run_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,210 +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-util.h"
|
||||
#include "journal-verify.h"
|
||||
#include "log.h"
|
||||
#include "mmap-cache.h"
|
||||
#include "rm-rf.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "tests.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) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
JournalFile *f;
|
||||
int r;
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != NULL);
|
||||
|
||||
r = journal_file_open(
|
||||
/* fd= */ -1,
|
||||
fn,
|
||||
O_RDONLY,
|
||||
JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0),
|
||||
0666,
|
||||
/* compress_threshold_bytes= */ UINT64_MAX,
|
||||
/* metrics= */ NULL,
|
||||
m,
|
||||
/* template= */ 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;
|
||||
}
|
||||
|
||||
static int run_test(const char *verification_key, ssize_t max_iterations) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
char t[] = "/var/tmp/journal-XXXXXX";
|
||||
struct stat st;
|
||||
JournalFile *f;
|
||||
JournalFile *df;
|
||||
usec_t from = 0, to = 0, total = 0;
|
||||
uint64_t start, end;
|
||||
int r;
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != NULL);
|
||||
|
||||
/* journal_file_open() requires a valid machine id */
|
||||
if (sd_id128_get_machine(NULL) < 0)
|
||||
return log_tests_skipped("No valid machine ID 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 a test journal");
|
||||
|
||||
assert_se(journal_file_open(
|
||||
/* fd= */ -1,
|
||||
"test.journal",
|
||||
O_RDWR|O_CREAT,
|
||||
JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0),
|
||||
0666,
|
||||
/* compress_threshold_bytes= */ UINT64_MAX,
|
||||
/* metrics= */ NULL,
|
||||
m,
|
||||
/* template= */ NULL,
|
||||
&df) == 0);
|
||||
|
||||
for (size_t n = 0; n < N_ENTRIES; n++) {
|
||||
_cleanup_free_ char *test = NULL;
|
||||
struct iovec iovec;
|
||||
struct dual_timestamp ts;
|
||||
|
||||
dual_timestamp_get(&ts);
|
||||
assert_se(asprintf(&test, "RANDOM=%li", random() % RANDOM_RANGE));
|
||||
iovec = IOVEC_MAKE_STRING(test);
|
||||
assert_se(journal_file_append_entry(
|
||||
df,
|
||||
&ts,
|
||||
/* boot_id= */ NULL,
|
||||
&iovec,
|
||||
/* n_iovec= */ 1,
|
||||
/* seqnum= */ NULL,
|
||||
/* seqnum_id= */ NULL,
|
||||
/* ret_object= */ NULL,
|
||||
/* ret_offset= */ NULL) == 0);
|
||||
}
|
||||
|
||||
(void) journal_file_offline_close(df);
|
||||
|
||||
log_info("Verifying with key: %s", strna(verification_key));
|
||||
|
||||
assert_se(journal_file_open(
|
||||
/* fd= */ -1,
|
||||
"test.journal",
|
||||
O_RDONLY,
|
||||
JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0),
|
||||
0666,
|
||||
/* compress_threshold_bytes= */ UINT64_MAX,
|
||||
/* metrics= */ NULL,
|
||||
m,
|
||||
/* template= */ 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);
|
||||
assert_se(stat("test.journal", &st) >= 0);
|
||||
|
||||
start = 38448 * 8 + 0;
|
||||
end = max_iterations < 0 ? (uint64_t)st.st_size * 8 : start + max_iterations;
|
||||
log_info("Toggling bits %"PRIu64 " to %"PRIu64, start, end);
|
||||
|
||||
for (uint64_t p = start; p < end; p++) {
|
||||
bit_toggle("test.journal", p);
|
||||
|
||||
if (max_iterations < 0)
|
||||
log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8);
|
||||
|
||||
r = raw_verify("test.journal", verification_key);
|
||||
/* Suppress the notice when running in the limited (CI) mode */
|
||||
if (verification_key && max_iterations < 0 && r >= 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);
|
||||
}
|
||||
|
||||
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *verification_key = NULL;
|
||||
int max_iterations = 512;
|
||||
|
||||
if (argc > 1) {
|
||||
/* Don't limit the number of iterations when the verification key
|
||||
* is provided on the command line, we want to do that only in CIs */
|
||||
verification_key = argv[1];
|
||||
max_iterations = -1;
|
||||
}
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
run_test(verification_key, max_iterations);
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
run_test(verification_key, max_iterations);
|
||||
|
||||
#if HAVE_GCRYPT
|
||||
/* If we're running without any arguments and we're compiled with gcrypt
|
||||
* check the journal verification stuff with a valid key as well */
|
||||
if (argc <= 1) {
|
||||
verification_key = "c262bd-85187f-0b1b04-877cc5/1c7af8-35a4e900";
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
run_test(verification_key, max_iterations);
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
run_test(verification_key, max_iterations);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,280 +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-util.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_one(void) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
dual_timestamp ts;
|
||||
JournalFile *f;
|
||||
struct iovec iovec;
|
||||
static const char test[] = "TEST1=1", test2[] = "TEST2=2";
|
||||
Object *o, *d;
|
||||
uint64_t p;
|
||||
sd_id128_t fake_boot_id;
|
||||
char t[] = "/var/tmp/journal-XXXXXX";
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != NULL);
|
||||
|
||||
mkdtemp_chdir_chattr(t);
|
||||
|
||||
assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, 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, NULL) == 0);
|
||||
|
||||
iovec = IOVEC_MAKE_STRING(test2);
|
||||
assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, 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, 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), &d, NULL) == 1);
|
||||
assert_se(journal_file_move_to_entry_for_data(f, d, DIRECTION_DOWN, &o, NULL) == 1);
|
||||
assert_se(le64toh(o->entry.seqnum) == 1);
|
||||
|
||||
assert_se(journal_file_move_to_entry_for_data(f, d, DIRECTION_UP, &o, NULL) == 1);
|
||||
assert_se(le64toh(o->entry.seqnum) == 3);
|
||||
|
||||
assert_se(journal_file_find_data_object(f, test2, strlen(test2), &d, NULL) == 1);
|
||||
assert_se(journal_file_move_to_entry_for_data(f, d, DIRECTION_UP, &o, NULL) == 1);
|
||||
assert_se(le64toh(o->entry.seqnum) == 2);
|
||||
|
||||
assert_se(journal_file_move_to_entry_for_data(f, d, DIRECTION_DOWN, &o, NULL) == 1);
|
||||
assert_se(le64toh(o->entry.seqnum) == 2);
|
||||
|
||||
assert_se(journal_file_find_data_object(f, "quux", 4, &d, NULL) == 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, m, JOURNAL_SEAL|JOURNAL_COMPRESS, UINT64_MAX, NULL);
|
||||
journal_file_rotate(&f, m, JOURNAL_SEAL|JOURNAL_COMPRESS, UINT64_MAX, NULL);
|
||||
|
||||
(void) journal_file_offline_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("------------------------------------------------------------");
|
||||
}
|
||||
|
||||
TEST(non_empty) {
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
test_non_empty_one();
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
test_non_empty_one();
|
||||
}
|
||||
|
||||
static void test_empty_one(void) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
JournalFile *f1, *f2, *f3, *f4;
|
||||
char t[] = "/var/tmp/journal-XXXXXX";
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != NULL);
|
||||
|
||||
mkdtemp_chdir_chattr(t);
|
||||
|
||||
assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0, 0666, UINT64_MAX, NULL, m, NULL, &f1) == 0);
|
||||
assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &f2) == 0);
|
||||
assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, NULL, &f3) == 0);
|
||||
assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, 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_offline_close(f1);
|
||||
(void) journal_file_offline_close(f2);
|
||||
(void) journal_file_offline_close(f3);
|
||||
(void) journal_file_offline_close(f4);
|
||||
}
|
||||
|
||||
TEST(empty) {
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
test_empty_one();
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
test_empty_one();
|
||||
}
|
||||
|
||||
#if HAVE_COMPRESSION
|
||||
static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
|
||||
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
|
||||
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));
|
||||
|
||||
m = mmap_cache_new();
|
||||
assert_se(m != NULL);
|
||||
|
||||
mkdtemp_chdir_chattr(t);
|
||||
|
||||
assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, compress_threshold, NULL, m, 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, 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 = COMPRESSION_FROM_OBJECT(o) != COMPRESSION_NONE;
|
||||
|
||||
(void) journal_file_offline_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_one(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));
|
||||
}
|
||||
|
||||
TEST(min_compress_size) {
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
|
||||
test_min_compress_size_one();
|
||||
|
||||
assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
|
||||
test_min_compress_size_one();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int intro(void) {
|
||||
arg_keep = saved_argc > 1;
|
||||
|
||||
/* 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");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
|
||||
Reference in New Issue
Block a user