diff --git a/src/libsystemd/sd-journal/journal-def.h b/src/libsystemd/sd-journal/journal-def.h index c972fe98ce..07851229f8 100644 --- a/src/libsystemd/sd-journal/journal-def.h +++ b/src/libsystemd/sd-journal/journal-def.h @@ -164,7 +164,7 @@ enum { STATE_OFFLINE = 0, STATE_ONLINE = 1, STATE_ARCHIVED = 2, - _STATE_MAX + _STATE_MAX, }; /* Header flags */ diff --git a/src/libsystemd/sd-journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h index 8100388973..4096f05783 100644 --- a/src/libsystemd/sd-journal/journal-file.h +++ b/src/libsystemd/sd-journal/journal-file.h @@ -46,7 +46,7 @@ typedef enum LocationType { /* We should seek to the precise location specified, and * return it, as we haven't read it yet. */ - LOCATION_SEEK + LOCATION_SEEK, } LocationType; typedef enum OfflineState { @@ -56,7 +56,7 @@ typedef enum OfflineState { OFFLINE_CANCEL, OFFLINE_AGAIN_FROM_SYNCING, OFFLINE_AGAIN_FROM_OFFLINING, - OFFLINE_DONE + OFFLINE_DONE, } OfflineState; typedef struct JournalFile { diff --git a/src/libsystemd/sd-journal/journal-internal.h b/src/libsystemd/sd-journal/journal-internal.h index e96b88a0c9..b13f7a45dc 100644 --- a/src/libsystemd/sd-journal/journal-internal.h +++ b/src/libsystemd/sd-journal/journal-internal.h @@ -25,7 +25,7 @@ typedef struct Directory Directory; typedef enum MatchType { MATCH_DISCRETE, MATCH_OR_TERM, - MATCH_AND_TERM + MATCH_AND_TERM, } MatchType; struct Match { diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c index b08e3f923d..daa9670ab4 100644 --- a/src/libsystemd/sd-journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -62,7 +62,6 @@ static void journal_file_unlink_newest_by_boot_id(sd_journal *j, JournalFile *f) static int journal_put_error(sd_journal *j, int r, const char *path) { _cleanup_free_ char *copy = NULL; - int k; /* Memorize an error we encountered, and store which * file/directory it was generated from. Note that we store @@ -84,13 +83,11 @@ static int journal_put_error(sd_journal *j, int r, const char *path) { return -ENOMEM; } - k = hashmap_ensure_put(&j->errors, NULL, INT_TO_PTR(r), copy); - if (k < 0) { - if (k == -EEXIST) - return 0; - - return k; - } + r = hashmap_ensure_put(&j->errors, NULL, INT_TO_PTR(r), copy); + if (r == -EEXIST) + return 0; + if (r < 0) + return r; TAKE_PTR(copy); return 0; @@ -675,7 +672,7 @@ static int next_for_match( uint64_t after_offset, direction_t direction, Object **ret, - uint64_t *offset) { + uint64_t *ret_offset) { int r; uint64_t np = 0; @@ -699,7 +696,7 @@ static int next_for_match( if (r <= 0) return r; - return journal_file_move_to_entry_by_offset_for_data(f, d, after_offset, direction, ret, offset); + return journal_file_move_to_entry_by_offset_for_data(f, d, after_offset, direction, ret, ret_offset); } else if (m->type == MATCH_OR_TERM) { @@ -760,19 +757,68 @@ static int next_for_match( return r; } - if (offset) - *offset = np; + if (ret_offset) + *ret_offset = np; return 1; } +static int move_by_boot_for_data( + sd_journal *j, + JournalFile *f, + direction_t direction, + sd_id128_t boot_id, + uint64_t data_offset, + Object **ret, + uint64_t *ret_offset) { + + int r; + + assert(j); + assert(f); + assert(IN_SET(direction, DIRECTION_DOWN, DIRECTION_UP)); + + for (;;) { + /* First, move to the last (or first when DIRECTION_UP) entry for the boot. */ + uint64_t p = 0; + r = journal_file_move_to_entry_by_monotonic(f, boot_id, + direction == DIRECTION_DOWN ? USEC_INFINITY : 0, + direction == DIRECTION_DOWN ? DIRECTION_UP : DIRECTION_DOWN, + NULL, &p); + if (r <= 0) + return r; + + /* Then, move to the first entry of the next boot (or the last entry of the previous boot with DIRECTION_UP). */ + Object *entry; + r = journal_file_next_entry(f, p, direction, &entry, NULL); + if (r <= 0) /* r == 0 means that no next (or previous) boot found. That is, we are at HEAD or TAIL now. */ + return r; + + assert(entry->object.type == OBJECT_ENTRY); + boot_id = entry->entry.boot_id; + + /* Note, this object cannot be reused, as journal_file_move_to_entry_by_monotonic() may invalidate the object. */ + Object *data; + r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &data); + if (r < 0) + return r; + + /* Then, move to the matching entry. */ + r = journal_file_move_to_entry_by_monotonic_for_data(f, data, boot_id, + direction == DIRECTION_DOWN ? 0 : USEC_INFINITY, direction, + ret, ret_offset); + if (r != 0) /* Here r == 0 is OK, as that means the boot contains no entry matching with the data. */ + return r; + } +} + static int find_location_for_match( sd_journal *j, Match *m, JournalFile *f, direction_t direction, Object **ret, - uint64_t *offset) { + uint64_t *ret_offset) { int r; @@ -793,16 +839,14 @@ static int find_location_for_match( if (r <= 0) return r; - /* FIXME: missing: find by monotonic */ - if (j->current_location.type == LOCATION_HEAD) - return direction == DIRECTION_DOWN ? journal_file_move_to_entry_for_data(f, d, DIRECTION_DOWN, ret, offset) : 0; + return direction == DIRECTION_DOWN ? journal_file_move_to_entry_for_data(f, d, DIRECTION_DOWN, ret, ret_offset) : 0; if (j->current_location.type == LOCATION_TAIL) - return direction == DIRECTION_UP ? journal_file_move_to_entry_for_data(f, d, DIRECTION_UP, ret, offset) : 0; + return direction == DIRECTION_UP ? journal_file_move_to_entry_for_data(f, d, DIRECTION_UP, ret, ret_offset) : 0; if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) - return journal_file_move_to_entry_by_seqnum_for_data(f, d, j->current_location.seqnum, direction, ret, offset); + return journal_file_move_to_entry_by_seqnum_for_data(f, d, j->current_location.seqnum, direction, ret, ret_offset); if (j->current_location.monotonic_set) { - r = journal_file_move_to_entry_by_monotonic_for_data(f, d, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset); + r = journal_file_move_to_entry_by_monotonic_for_data(f, d, j->current_location.boot_id, j->current_location.monotonic, direction, ret, ret_offset); if (r != 0) return r; @@ -810,11 +854,17 @@ static int find_location_for_match( r = journal_file_move_to_object(f, OBJECT_DATA, dp, &d); if (r < 0) return r; + + /* If not found, fall back to realtime if set, or go to the first entry of the next boot + * (or the last entry of the previous boot when DIRECTION_UP). */ } if (j->current_location.realtime_set) - return journal_file_move_to_entry_by_realtime_for_data(f, d, j->current_location.realtime, direction, ret, offset); + return journal_file_move_to_entry_by_realtime_for_data(f, d, j->current_location.realtime, direction, ret, ret_offset); - return journal_file_move_to_entry_for_data(f, d, direction, ret, offset); + if (j->current_location.monotonic_set) + return move_by_boot_for_data(j, f, direction, j->current_location.boot_id, dp, ret, ret_offset); + + return journal_file_move_to_entry_for_data(f, d, direction, ret, ret_offset); } else if (m->type == MATCH_OR_TERM) { uint64_t np = 0; @@ -842,8 +892,8 @@ static int find_location_for_match( return r; } - if (offset) - *offset = np; + if (ret_offset) + *ret_offset = np; return 1; @@ -869,7 +919,7 @@ static int find_location_for_match( np = cp; } - return next_for_match(j, m, f, np, direction, ret, offset); + return next_for_match(j, m, f, np, direction, ret, ret_offset); } } @@ -878,35 +928,51 @@ static int find_location_with_matches( JournalFile *f, direction_t direction, Object **ret, - uint64_t *offset) { + uint64_t *ret_offset) { int r; assert(j); assert(f); - assert(ret); - assert(offset); - if (!j->level0) { - /* No matches is simple */ + if (j->level0) + return find_location_for_match(j, j->level0, f, direction, ret, ret_offset); - if (j->current_location.type == LOCATION_HEAD) - return direction == DIRECTION_DOWN ? journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset) : 0; - if (j->current_location.type == LOCATION_TAIL) - return direction == DIRECTION_UP ? journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset) : 0; - if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) - return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset); - if (j->current_location.monotonic_set) { - r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset); - if (r != 0) - return r; - } - if (j->current_location.realtime_set) - return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset); + /* No matches is simple */ - return journal_file_next_entry(f, 0, direction, ret, offset); - } else - return find_location_for_match(j, j->level0, f, direction, ret, offset); + if (j->current_location.type == LOCATION_HEAD) + return direction == DIRECTION_DOWN ? journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, ret_offset) : 0; + if (j->current_location.type == LOCATION_TAIL) + return direction == DIRECTION_UP ? journal_file_next_entry(f, 0, DIRECTION_UP, ret, ret_offset) : 0; + if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) + return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, ret_offset); + if (j->current_location.monotonic_set) { + r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, ret_offset); + if (r != 0) + return r; + + /* If not found, fall back to realtime if set, or go to the first entry of the next boot + * (or the last entry of the previous boot when DIRECTION_UP). */ + } + if (j->current_location.realtime_set) + return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, ret_offset); + + if (j->current_location.monotonic_set) { + uint64_t p = 0; + + /* If not found in the above, first move to the last (or first when DIRECTION_UP) entry for the boot. */ + r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, + direction == DIRECTION_DOWN ? USEC_INFINITY : 0, + direction == DIRECTION_DOWN ? DIRECTION_UP : DIRECTION_DOWN, + NULL, &p); + if (r <= 0) + return r; + + /* Then, move to the next or previous boot. */ + return journal_file_next_entry(f, p, direction, ret, ret_offset); + } + + return journal_file_next_entry(f, 0, direction, ret, ret_offset); } static int next_with_matches( @@ -914,24 +980,22 @@ static int next_with_matches( JournalFile *f, direction_t direction, Object **ret, - uint64_t *offset) { + uint64_t *ret_offset) { assert(j); assert(f); - assert(ret); - assert(offset); /* No matches is easy. We simple advance the file * pointer by one. */ if (!j->level0) - return journal_file_next_entry(f, f->current_offset, direction, ret, offset); + return journal_file_next_entry(f, f->current_offset, direction, ret, ret_offset); /* If we have a match then we look for the next matching entry * with an offset at least one step larger */ return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? f->current_offset + 1 : f->current_offset - 1, - direction, ret, offset); + direction, ret, ret_offset); } static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) { @@ -967,9 +1031,18 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc journal_file_save_location(f, c, cp); } } else { - f->last_direction = direction; - r = find_location_with_matches(j, f, direction, &c, &cp); + /* LOCATION_SEEK specified to j->current_location.type here means that this is called first + * after sd_journal_seek_monotonic_usec() or friends was called. In that case, this file may + * not contain any matching entries with the user-specified location, but another file may + * contain them. If so, the second call of this function will use the seqnum, and we may find + * an entry in _this_ file with the seqnum. To prevent the second call of this function exits + * earlier by the first 'if' block of this function, do not save the direction if the current + * location is LOCATION_SEEK. */ + if (r > 0 || j->current_location.type != LOCATION_SEEK) + f->last_direction = direction; + else + assert(f->last_direction == _DIRECTION_INVALID); if (r <= 0) return r; @@ -986,11 +1059,8 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc bool found; if (j->current_location.type == LOCATION_DISCRETE) { - int k; - - k = compare_with_location(j, f, &j->current_location, j->current_file); - - found = direction == DIRECTION_DOWN ? k > 0 : k < 0; + r = compare_with_location(j, f, &j->current_location, j->current_file); + found = direction == DIRECTION_DOWN ? r > 0 : r < 0; } else found = true; @@ -1084,11 +1154,8 @@ static int real_journal_next(sd_journal *j, direction_t direction) { if (!new_file) found = true; else { - int k; - - k = compare_locations(j, f, new_file); - - found = direction == DIRECTION_DOWN ? k < 0 : k > 0; + r = compare_locations(j, f, new_file); + found = direction == DIRECTION_DOWN ? r < 0 : r > 0; } if (found) @@ -1315,7 +1382,6 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { _cleanup_free_ char *item = NULL; unsigned long long ll; sd_id128_t id; - int k = 0; r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS); if (r < 0) @@ -1330,9 +1396,9 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { switch (item[0]) { case 's': - k = sd_id128_from_string(item+2, &id); - if (k < 0) - return k; + r = sd_id128_from_string(item+2, &id); + if (r < 0) + return r; if (!sd_id128_equal(id, j->current_file->header->seqnum_id)) return 0; break; @@ -1345,9 +1411,9 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { break; case 'b': - k = sd_id128_from_string(item+2, &id); - if (k < 0) - return k; + r = sd_id128_from_string(item+2, &id); + if (r < 0) + return r; if (!sd_id128_equal(id, o->entry.boot_id)) return 0; break; diff --git a/src/libsystemd/sd-journal/test-journal-interleaving.c b/src/libsystemd/sd-journal/test-journal-interleaving.c index c1b7e23de5..ace2cb8c05 100644 --- a/src/libsystemd/sd-journal/test-journal-interleaving.c +++ b/src/libsystemd/sd-journal/test-journal-interleaving.c @@ -16,6 +16,7 @@ #include "parse-util.h" #include "random-util.h" #include "rm-rf.h" +#include "tmpfile-util.h" #include "tests.h" /* This program tests skipping around in a multi-file journal. */ @@ -23,43 +24,27 @@ 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) { +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(-EBADF, name, O_RDWR|O_CREAT, flags, 0644, UINT64_MAX, NULL, m, NULL, &f)); + ASSERT_NOT_NULL(m = mmap_cache_new()); + ASSERT_OK(journal_file_open(-EBADF, name, O_RDWR|O_CREAT, flags, 0644, UINT64_MAX, NULL, m, NULL, &f)); return f; } -static JournalFile *test_open(const char *name) { +static JournalFile* test_open(const char *name) { return test_open_internal(name, JOURNAL_COMPRESS); } -static JournalFile *test_open_strict(const char *name) { +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 char* test_done(char *t) { + if (!t) + return NULL; -static void test_done(const char *t) { log_info("Done..."); if (arg_keep) @@ -67,13 +52,16 @@ static void test_done(const char *t) { else { journal_directory_vacuum(".", 3000000, 0, 0, NULL, true); - assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); + ASSERT_OK(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL)); } log_info("------------------------------------------------------------"); + return mfree(t); } -static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint64_t *seqnum, uint64_t *ret_offset) { +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, test_done); + +static void append_number(JournalFile *f, unsigned n, const sd_id128_t *boot_id, uint64_t *seqnum, uint64_t *ret_offset) { _cleanup_free_ char *p = NULL, *q = NULL, *s = NULL; dual_timestamp ts; struct iovec iovec[3]; @@ -89,18 +77,18 @@ static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint previous_ts = ts; - assert_se(asprintf(&p, "NUMBER=%d", n) >= 0); + ASSERT_OK(asprintf(&p, "NUMBER=%u", n)); iovec[n_iov++] = IOVEC_MAKE_STRING(p); - assert_se(s = strjoin("LESS_THAN_FIVE=%d", yes_no(n < 5))); + ASSERT_NOT_NULL(s = strjoin("LESS_THAN_FIVE=", yes_no(n < 5))); iovec[n_iov++] = IOVEC_MAKE_STRING(s); if (boot_id) { - assert_se(q = strjoin("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id))); + ASSERT_NOT_NULL(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, ret_offset)); + ASSERT_OK(journal_file_append_entry(f, &ts, boot_id, iovec, n_iov, seqnum, NULL, NULL, ret_offset)); } static void append_unreferenced_data(JournalFile *f, const sd_id128_t *boot_id) { @@ -113,91 +101,82 @@ static void append_unreferenced_data(JournalFile *f, const sd_id128_t *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))); + ASSERT_NOT_NULL(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); + ASSERT_ERROR(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) { +static void test_check_number(sd_journal *j, unsigned expected) { 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_OK(sd_journal_get_monotonic_usec(j, NULL, &boot_id)); + ASSERT_OK(sd_journal_get_data(j, "NUMBER", &d, &l)); - assert_se(safe_atoi(k + STRLEN("NUMBER="), &x) >= 0); - assert_se(n == x); + _cleanup_free_ char *k = NULL; + ASSERT_NOT_NULL(k = strndup(d, l)); + printf("%s %s (expected=%u)\n", SD_ID128_TO_STRING(boot_id), k, expected); + + unsigned x; + ASSERT_OK(safe_atou(k + STRLEN("NUMBER="), &x)); + ASSERT_EQ(x, expected); } -static void test_check_numbers_down(sd_journal *j, int count) { - int i; - - for (i = 1; i <= count; i++) { - int r; +static void test_check_numbers_down(sd_journal *j, unsigned count) { + for (unsigned i = 1; i <= count; i++) { test_check_number(j, i); - assert_ret(r = sd_journal_next(j)); if (i == count) - assert_se(r == 0); + ASSERT_OK_ZERO(sd_journal_next(j)); else - assert_se(r == 1); + ASSERT_OK_POSITIVE(sd_journal_next(j)); } - } -static void test_check_numbers_up(sd_journal *j, int count) { - for (int i = count; i >= 1; i--) { - int r; +static void test_check_numbers_up(sd_journal *j, unsigned count) { + for (unsigned i = count; i >= 1; i--) { test_check_number(j, i); - assert_ret(r = sd_journal_previous(j)); if (i == 1) - assert_se(r == 0); + ASSERT_OK_ZERO(sd_journal_previous(j)); else - assert_se(r == 1); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); } } static void setup_sequential(void) { - JournalFile *f1, *f2, *f3; + _cleanup_(journal_file_offline_closep) JournalFile *f1 = NULL, *f2 = NULL, *f3 = NULL; 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); + ASSERT_OK(sd_id128_randomize(&id)); log_info("boot_id: %s", SD_ID128_TO_STRING(id)); append_number(f1, 1, &id, NULL, NULL); append_number(f1, 2, &id, NULL, NULL); append_number(f1, 3, &id, NULL, NULL); append_number(f2, 4, &id, NULL, NULL); - assert_se(sd_id128_randomize(&id) >= 0); + ASSERT_OK(sd_id128_randomize(&id)); log_info("boot_id: %s", SD_ID128_TO_STRING(id)); append_number(f2, 5, &id, NULL, NULL); append_number(f2, 6, &id, NULL, NULL); append_number(f3, 7, &id, NULL, NULL); append_number(f3, 8, &id, NULL, NULL); - assert_se(sd_id128_randomize(&id) >= 0); + ASSERT_OK(sd_id128_randomize(&id)); log_info("boot_id: %s", SD_ID128_TO_STRING(id)); append_number(f3, 9, &id, NULL, NULL); - test_close(f1); - test_close(f2); - test_close(f3); } static void setup_interleaved(void) { - JournalFile *f1, *f2, *f3; + _cleanup_(journal_file_offline_closep) JournalFile *f1 = NULL, *f2 = NULL, *f3 = NULL; 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); + ASSERT_OK(sd_id128_randomize(&id)); log_info("boot_id: %s", SD_ID128_TO_STRING(id)); append_number(f1, 1, &id, NULL, NULL); append_number(f2, 2, &id, NULL, NULL); @@ -208,13 +187,10 @@ static void setup_interleaved(void) { append_number(f1, 7, &id, NULL, NULL); append_number(f2, 8, &id, NULL, NULL); append_number(f3, 9, &id, NULL, NULL); - test_close(f1); - test_close(f2); - test_close(f3); } static void setup_unreferenced_data(void) { - JournalFile *f1, *f2, *f3; + _cleanup_(journal_file_offline_closep) JournalFile *f1 = NULL, *f2 = NULL, *f3 = NULL; sd_id128_t id; /* For issue #29275. */ @@ -222,234 +198,232 @@ static void setup_unreferenced_data(void) { 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); + ASSERT_OK(sd_id128_randomize(&id)); log_info("boot_id: %s", SD_ID128_TO_STRING(id)); append_number(f1, 1, &id, NULL, NULL); append_number(f1, 2, &id, NULL, NULL); append_number(f1, 3, &id, NULL, NULL); - assert_se(sd_id128_randomize(&id) >= 0); + ASSERT_OK(sd_id128_randomize(&id)); log_info("boot_id: %s", SD_ID128_TO_STRING(id)); append_unreferenced_data(f1, &id); append_number(f2, 4, &id, NULL, NULL); append_number(f2, 5, &id, NULL, NULL); append_number(f2, 6, &id, NULL, NULL); - assert_se(sd_id128_randomize(&id) >= 0); + ASSERT_OK(sd_id128_randomize(&id)); log_info("boot_id: %s", SD_ID128_TO_STRING(id)); append_unreferenced_data(f2, &id); append_number(f3, 7, &id, NULL, NULL); append_number(f3, 8, &id, NULL, NULL); append_number(f3, 9, &id, NULL, 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); +static void mkdtemp_chdir_chattr(const char *template, char **ret) { + _cleanup_(rm_rf_physical_and_freep) char *path = NULL; + + ASSERT_OK(mkdtemp_malloc(template, &path)); + ASSERT_OK_ERRNO(chdir(path)); /* 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); + + *ret = TAKE_PTR(path); } static void test_cursor(sd_journal *j) { _cleanup_strv_free_ char **cursors = NULL; int r; - assert_se(sd_journal_seek_head(j) >= 0); + ASSERT_OK(sd_journal_seek_head(j)); for (;;) { - r = sd_journal_next(j); - assert_se(r >= 0); + ASSERT_OK(r = sd_journal_next(j)); if (r == 0) break; _cleanup_free_ char *cursor = NULL; - assert_se(sd_journal_get_cursor(j, &cursor) >= 0); - assert_se(sd_journal_test_cursor(j, cursor) > 0); - assert_se(strv_consume(&cursors, TAKE_PTR(cursor)) >= 0); + ASSERT_OK(sd_journal_get_cursor(j, &cursor)); + ASSERT_OK_POSITIVE(sd_journal_test_cursor(j, cursor)); + ASSERT_OK(strv_consume(&cursors, TAKE_PTR(cursor))); } STRV_FOREACH(c, cursors) { - assert_se(sd_journal_seek_cursor(j, *c) >= 0); - assert_se(sd_journal_next(j) >= 0); - assert_se(sd_journal_test_cursor(j, *c) > 0); + ASSERT_OK(sd_journal_seek_cursor(j, *c)); + ASSERT_OK(sd_journal_next(j)); + ASSERT_OK_POSITIVE(sd_journal_test_cursor(j, *c)); } - assert_se(sd_journal_seek_head(j) >= 0); + ASSERT_OK(sd_journal_seek_head(j)); STRV_FOREACH(c, cursors) { - assert_se(sd_journal_next(j) >= 0); - assert_se(sd_journal_test_cursor(j, *c) > 0); + ASSERT_OK(sd_journal_next(j)); + ASSERT_OK_POSITIVE(sd_journal_test_cursor(j, *c)); } } static void test_skip_one(void (*setup)(void)) { - char t[] = "/var/tmp/journal-skip-XXXXXX"; + _cleanup_(test_donep) char *t = NULL; sd_journal *j; - int r; - mkdtemp_chdir_chattr(t); + mkdtemp_chdir_chattr("/var/tmp/journal-skip-XXXXXX", &t); setup(); /* Seek to head, iterate down. */ - assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); - assert_ret(sd_journal_seek_head(j)); - assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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 */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); /* pointing to the first entry */ + ASSERT_OK_ZERO(sd_journal_previous(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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 */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); /* pointing to the first entry */ + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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 */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_ZERO(sd_journal_previous(j)); /* no-op */ + ASSERT_OK_POSITIVE(sd_journal_next(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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 */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_ZERO(sd_journal_previous(j)); /* no-op */ + ASSERT_OK_ZERO(sd_journal_previous(j)); /* no-op */ + ASSERT_OK_ZERO(sd_journal_previous(j)); /* no-op */ + ASSERT_OK_POSITIVE(sd_journal_next(j)); /* pointing to the first entry */ + ASSERT_OK_ZERO(sd_journal_previous(j)); /* no-op */ + ASSERT_OK_ZERO(sd_journal_previous(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - assert_ret(sd_journal_seek_tail(j)); - assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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 */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); /* pointing to the last entry */ + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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 */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_OK_ZERO(sd_journal_next(j)); /* no-op */ + ASSERT_OK_POSITIVE(sd_journal_previous(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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 */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_OK_ZERO(sd_journal_next(j)); /* no-op */ + ASSERT_OK_ZERO(sd_journal_next(j)); /* no-op */ + ASSERT_OK_ZERO(sd_journal_next(j)); /* no-op */ + ASSERT_OK_POSITIVE(sd_journal_previous(j)); /* pointing to the last entry. */ + ASSERT_OK_ZERO(sd_journal_next(j)); /* no-op */ + ASSERT_OK_ZERO(sd_journal_next(j)); /* 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, SD_JOURNAL_ASSUME_IMMUTABLE)); - assert_ret(sd_journal_seek_tail(j)); - assert_se(sd_journal_previous_skip(j, 9) == 9); /* pointing to the first entry. */ + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_EQ(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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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); + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_OK_ZERO(sd_journal_next(j)); + ASSERT_EQ(sd_journal_previous_skip(j, 4), 4); + ASSERT_EQ(sd_journal_previous_skip(j, 5), 5); + ASSERT_OK_ZERO(sd_journal_previous(j)); + ASSERT_OK_ZERO(sd_journal_previous_skip(j, 5)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); + ASSERT_OK_POSITIVE(sd_journal_previous_skip(j, 5)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); + ASSERT_EQ(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, SD_JOURNAL_ASSUME_IMMUTABLE)); - assert_ret(sd_journal_seek_head(j)); - assert_se(sd_journal_next_skip(j, 9) == 9); + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_EQ(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, SD_JOURNAL_ASSUME_IMMUTABLE)); - 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); + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_ZERO(sd_journal_previous(j)); + ASSERT_EQ(sd_journal_next_skip(j, 4), 4); + ASSERT_EQ(sd_journal_next_skip(j, 5), 5); + ASSERT_OK_ZERO(sd_journal_next(j)); + ASSERT_OK_ZERO(sd_journal_next_skip(j, 5)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + ASSERT_OK_POSITIVE(sd_journal_next_skip(j, 5)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + ASSERT_EQ(sd_journal_next_skip(j, 5), 3); test_check_numbers_up(j, 9); sd_journal_close(j); /* For issue #31516. */ - assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); test_cursor(j); sd_journal_flush_matches(j); - assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0); + ASSERT_OK(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX)); test_cursor(j); sd_journal_flush_matches(j); - assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=no", SIZE_MAX) >= 0); + ASSERT_OK(sd_journal_add_match(j, "LESS_THAN_FIVE=no", SIZE_MAX)); test_cursor(j); sd_journal_flush_matches(j); - assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=hoge", SIZE_MAX) >= 0); + ASSERT_OK(sd_journal_add_match(j, "LESS_THAN_FIVE=hoge", SIZE_MAX)); test_cursor(j); sd_journal_flush_matches(j); - assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0); - assert_se(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX) >= 0); + ASSERT_OK(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX)); + ASSERT_OK(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX)); test_cursor(j); sd_journal_flush_matches(j); - assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0); - assert_se(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX) >= 0); - assert_se(sd_journal_add_match(j, "NUMBER=4", SIZE_MAX) >= 0); - assert_se(sd_journal_add_match(j, "NUMBER=5", SIZE_MAX) >= 0); - assert_se(sd_journal_add_match(j, "NUMBER=6", SIZE_MAX) >= 0); + ASSERT_OK(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX)); + ASSERT_OK(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX)); + ASSERT_OK(sd_journal_add_match(j, "NUMBER=4", SIZE_MAX)); + ASSERT_OK(sd_journal_add_match(j, "NUMBER=5", SIZE_MAX)); + ASSERT_OK(sd_journal_add_match(j, "NUMBER=6", SIZE_MAX)); test_cursor(j); - - test_done(t); + sd_journal_close(j); } TEST(skip) { @@ -458,40 +432,40 @@ TEST(skip) { } static void test_boot_id_one(void (*setup)(void), size_t n_ids_expected) { - char t[] = "/var/tmp/journal-boot-id-XXXXXX"; + _cleanup_(test_donep) char *t = NULL; _cleanup_(sd_journal_closep) sd_journal *j = NULL; _cleanup_free_ LogId *ids = NULL; size_t n_ids; - mkdtemp_chdir_chattr(t); + mkdtemp_chdir_chattr("/var/tmp/journal-boot-id-XXXXXX", &t); setup(); - assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); - assert_se(journal_get_boots( + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + ASSERT_OK(journal_get_boots( j, /* advance_older = */ false, /* max_ids = */ SIZE_MAX, - &ids, &n_ids) >= 0); - assert_se(ids); - assert_se(n_ids == n_ids_expected); + &ids, &n_ids)); + ASSERT_NOT_NULL(ids); + ASSERT_EQ(n_ids, n_ids_expected); for (size_t i = 0; i < n_ids; i++) { sd_id128_t id; /* positive offset */ - assert_se(journal_find_boot(j, SD_ID128_NULL, (int) (i + 1), &id) == 1); - assert_se(sd_id128_equal(id, ids[i].id)); + ASSERT_OK_POSITIVE(journal_find_boot(j, SD_ID128_NULL, (int) (i + 1), &id)); + ASSERT_TRUE(sd_id128_equal(id, ids[i].id)); /* negative offset */ - assert_se(journal_find_boot(j, SD_ID128_NULL, (int) (i + 1) - (int) n_ids, &id) == 1); - assert_se(sd_id128_equal(id, ids[i].id)); + ASSERT_OK_POSITIVE(journal_find_boot(j, SD_ID128_NULL, (int) (i + 1) - (int) n_ids, &id)); + ASSERT_TRUE(sd_id128_equal(id, ids[i].id)); for (size_t k = 0; k < n_ids; k++) { int offset = (int) k - (int) i; /* relative offset */ - assert_se(journal_find_boot(j, ids[i].id, offset, &id) == 1); - assert_se(sd_id128_equal(id, ids[k].id)); + ASSERT_OK_POSITIVE(journal_find_boot(j, ids[i].id, offset, &id)); + ASSERT_TRUE(sd_id128_equal(id, ids[k].id)); } } @@ -499,30 +473,28 @@ static void test_boot_id_one(void (*setup)(void), size_t n_ids_expected) { _cleanup_free_ LogId *ids_limited = NULL; size_t n_ids_limited; - assert_se(journal_get_boots( + ASSERT_OK(journal_get_boots( j, /* advance_older = */ false, /* max_ids = */ i, - &ids_limited, &n_ids_limited) >= 0); - assert_se(ids_limited || i == 0); - assert_se(n_ids_limited == MIN(i, n_ids_expected)); - assert_se(memcmp_safe(ids, ids_limited, n_ids_limited * sizeof(LogId)) == 0); + &ids_limited, &n_ids_limited)); + ASSERT_TRUE(ids_limited || i == 0); + ASSERT_EQ(n_ids_limited, MIN(i, n_ids_expected)); + ASSERT_EQ(memcmp_safe(ids, ids_limited, n_ids_limited * sizeof(LogId)), 0); } for (size_t i = 0; i <= n_ids_expected + 1; i++) { _cleanup_free_ LogId *ids_limited = NULL; size_t n_ids_limited; - assert_se(journal_get_boots( + ASSERT_OK(journal_get_boots( j, /* advance_older = */ true, /* max_ids = */ i, - &ids_limited, &n_ids_limited) >= 0); - assert_se(ids_limited || i == 0); - assert_se(n_ids_limited == MIN(i, n_ids_expected)); + &ids_limited, &n_ids_limited)); + ASSERT_TRUE(ids_limited || i == 0); + ASSERT_EQ(n_ids_limited, MIN(i, n_ids_expected)); for (size_t k = 0; k < n_ids_limited; k++) - assert_se(memcmp(&ids[n_ids - k - 1], &ids_limited[k], sizeof(LogId)) == 0); + ASSERT_EQ(memcmp(&ids[n_ids - k - 1], &ids_limited[k], sizeof(LogId)), 0); } - - test_done(t); } TEST(boot_id) { @@ -531,95 +503,89 @@ TEST(boot_id) { } static void test_sequence_numbers_one(void) { + _cleanup_(test_donep) char *t = NULL; + _cleanup_(journal_file_offline_closep) JournalFile *one = NULL, *two = NULL; _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); + ASSERT_NOT_NULL(m = mmap_cache_new()); - mkdtemp_chdir_chattr(t); + mkdtemp_chdir_chattr("/var/tmp/journal-seq-XXXXXX", &t); - assert_se(journal_file_open(-EBADF, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644, - UINT64_MAX, NULL, m, NULL, &one) == 0); + ASSERT_OK(journal_file_open(-EBADF, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644, + UINT64_MAX, NULL, m, NULL, &one)); append_number(one, 1, NULL, &seqnum, NULL); printf("seqnum=%"PRIu64"\n", seqnum); - assert_se(seqnum == 1); + ASSERT_EQ(seqnum, UINT64_C(1)); append_number(one, 2, NULL, &seqnum, NULL); printf("seqnum=%"PRIu64"\n", seqnum); - assert_se(seqnum == 2); + ASSERT_EQ(seqnum, UINT64_C(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)); + ASSERT_EQ(one->header->state, STATE_ONLINE); + ASSERT_FALSE(sd_id128_equal(one->header->file_id, one->header->machine_id)); + ASSERT_FALSE(sd_id128_equal(one->header->file_id, one->header->tail_entry_boot_id)); + ASSERT_TRUE(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(-EBADF, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644, - UINT64_MAX, NULL, m, one, &two) == 0); + ASSERT_OK(journal_file_open(-EBADF, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644, + UINT64_MAX, NULL, m, one, &two)); - 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)); + ASSERT_EQ(two->header->state, STATE_ONLINE); + ASSERT_FALSE(sd_id128_equal(two->header->file_id, one->header->file_id)); + ASSERT_TRUE(sd_id128_equal(two->header->machine_id, one->header->machine_id)); + ASSERT_TRUE(sd_id128_is_null(two->header->tail_entry_boot_id)); /* Not written yet. */ + ASSERT_TRUE(sd_id128_equal(two->header->seqnum_id, one->header->seqnum_id)); append_number(two, 3, NULL, &seqnum, NULL); printf("seqnum=%"PRIu64"\n", seqnum); - assert_se(seqnum == 3); + ASSERT_EQ(seqnum, UINT64_C(3)); append_number(two, 4, NULL, &seqnum, NULL); printf("seqnum=%"PRIu64"\n", seqnum); - assert_se(seqnum == 4); + ASSERT_EQ(seqnum, UINT64_C(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); + ASSERT_TRUE(sd_id128_equal(two->header->tail_entry_boot_id, one->header->tail_entry_boot_id)); append_number(one, 5, NULL, &seqnum, NULL); printf("seqnum=%"PRIu64"\n", seqnum); - assert_se(seqnum == 5); + ASSERT_EQ(seqnum, UINT64_C(5)); append_number(one, 6, NULL, &seqnum, NULL); printf("seqnum=%"PRIu64"\n", seqnum); - assert_se(seqnum == 6); - - test_close(one); + ASSERT_EQ(seqnum, UINT64_C(6)); /* If the machine-id is not initialized, the header file verification * (which happens when reopening a journal file) will fail. */ if (sd_id128_get_machine(NULL) >= 0) { + two = journal_file_offline_close(two); + /* restart server */ seqnum = 0; - assert_se(journal_file_open(-EBADF, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0, - UINT64_MAX, NULL, m, NULL, &two) == 0); + ASSERT_OK(journal_file_open(-EBADF, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0, + UINT64_MAX, NULL, m, NULL, &two)); - assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id)); + ASSERT_TRUE(sd_id128_equal(two->header->seqnum_id, seqnum_id)); append_number(two, 7, NULL, &seqnum, NULL); printf("seqnum=%"PRIu64"\n", seqnum); - assert_se(seqnum == 5); + ASSERT_EQ(seqnum, UINT64_C(5)); - /* So..., here we have the same seqnum in two files with the - * same seqnum_id. */ - - test_close(two); + /* So..., here we have the same seqnum in two files with the same seqnum_id. */ } - - test_done(t); } TEST(sequence_numbers) { - assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0); + ASSERT_OK_ERRNO(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1)); test_sequence_numbers_one(); - assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0); + ASSERT_OK_ERRNO(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1)); test_sequence_numbers_one(); + + ASSERT_OK_ERRNO(unsetenv("SYSTEMD_JOURNAL_COMPACT")); } static int expected_result(uint64_t needle, const uint64_t *candidates, const uint64_t *offset, size_t n, direction_t direction, uint64_t *ret) { @@ -699,14 +665,14 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_DOWN, NULL, &p); e = expected_result(i, seqnum, offset, n, DIRECTION_DOWN, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); p = 0; r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_UP, NULL, &p); e = expected_result(i, seqnum, offset, n, DIRECTION_UP, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); } /* by seqnum (random) */ @@ -716,8 +682,8 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_DOWN, NULL, &p); e = expected_result(i, seqnum, offset, n, DIRECTION_DOWN, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); } for (size_t trial = 0; trial < 3 * n; trial++) { uint64_t i = random_u64_range(n + 2); @@ -725,8 +691,8 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_UP, NULL, &p); e = expected_result(i, seqnum, offset, n, DIRECTION_UP, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); } /* by offset (sequential) */ @@ -734,38 +700,38 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_move_to_entry_by_offset(f, offset[i] - 1, DIRECTION_DOWN, NULL, &p); e = expected_result(offset[i] - 1, offset, offset, n, DIRECTION_DOWN, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); p = 0; r = journal_file_move_to_entry_by_offset(f, offset[i], DIRECTION_DOWN, NULL, &p); e = expected_result(offset[i], offset, offset, n, DIRECTION_DOWN, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); p = 0; r = journal_file_move_to_entry_by_offset(f, offset[i] + 1, DIRECTION_DOWN, NULL, &p); e = expected_result(offset[i] + 1, offset, offset, n, DIRECTION_DOWN, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); p = 0; r = journal_file_move_to_entry_by_offset(f, offset[i] - 1, DIRECTION_UP, NULL, &p); e = expected_result(offset[i] - 1, offset, offset, n, DIRECTION_UP, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); p = 0; r = journal_file_move_to_entry_by_offset(f, offset[i], DIRECTION_UP, NULL, &p); e = expected_result(offset[i], offset, offset, n, DIRECTION_UP, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); p = 0; r = journal_file_move_to_entry_by_offset(f, offset[i] + 1, DIRECTION_UP, NULL, &p); e = expected_result(offset[i] + 1, offset, offset, n, DIRECTION_UP, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); } /* by offset (random) */ @@ -775,8 +741,8 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_move_to_entry_by_offset(f, i, DIRECTION_DOWN, NULL, &p); e = expected_result(i, offset, offset, n, DIRECTION_DOWN, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); } for (size_t trial = 0; trial < 3 * n; trial++) { uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2); @@ -784,8 +750,8 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_move_to_entry_by_offset(f, i, DIRECTION_UP, NULL, &p); e = expected_result(i, offset, offset, n, DIRECTION_UP, &q); - assert_se(r == e); - assert_se(p == q); + ASSERT_EQ(r, e); + ASSERT_EQ(p, q); } /* by journal_file_next_entry() */ @@ -793,50 +759,50 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_next_entry(f, offset[i] - 2, DIRECTION_DOWN, NULL, &p); e = expected_result_next(offset[i] - 2, offset_candidates, offset, n, DIRECTION_DOWN, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); p = 0; r = journal_file_next_entry(f, offset[i] - 1, DIRECTION_DOWN, NULL, &p); e = expected_result_next(offset[i] - 1, offset_candidates, offset, n, DIRECTION_DOWN, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); p = 0; r = journal_file_next_entry(f, offset[i], DIRECTION_DOWN, NULL, &p); e = expected_result_next(offset[i], offset_candidates, offset, n, DIRECTION_DOWN, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); p = 0; r = journal_file_next_entry(f, offset[i] + 1, DIRECTION_DOWN, NULL, &p); e = expected_result_next(offset[i] + 1, offset_candidates, offset, n, DIRECTION_DOWN, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); p = 0; r = journal_file_next_entry(f, offset[i] - 1, DIRECTION_UP, NULL, &p); e = expected_result_next(offset[i] - 1, offset_candidates, offset, n, DIRECTION_UP, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); p = 0; r = journal_file_next_entry(f, offset[i], DIRECTION_UP, NULL, &p); e = expected_result_next(offset[i], offset_candidates, offset, n, DIRECTION_UP, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); p = 0; r = journal_file_next_entry(f, offset[i] + 1, DIRECTION_UP, NULL, &p); e = expected_result_next(offset[i] + 1, offset_candidates, offset, n, DIRECTION_UP, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); p = 0; r = journal_file_next_entry(f, offset[i] + 2, DIRECTION_UP, NULL, &p); e = expected_result_next(offset[i] + 2, offset_candidates, offset, n, DIRECTION_UP, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); } for (size_t trial = 0; trial < 3 * n; trial++) { uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2); @@ -844,8 +810,8 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_next_entry(f, i, DIRECTION_DOWN, NULL, &p); e = expected_result_next(i, offset_candidates, offset, n, DIRECTION_DOWN, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); } for (size_t trial = 0; trial < 3 * n; trial++) { uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2); @@ -853,62 +819,54 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse p = 0; r = journal_file_next_entry(f, i, DIRECTION_UP, NULL, &p); e = expected_result_next(i, offset_candidates, offset, n, DIRECTION_UP, &q); - assert_se(e == 0 ? r <= 0 : r > 0); - assert_se(p == q); + ASSERT_EQ(e == 0, r <= 0); + ASSERT_EQ(p, q); } } static void test_generic_array_bisect_one(size_t n, size_t num_corrupted) { + _cleanup_(test_donep) char *t = NULL; _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL; - char t[] = "/var/tmp/journal-seq-XXXXXX"; _cleanup_free_ uint64_t *seqnum = NULL, *offset = NULL, *offset_candidates = NULL; - JournalFile *f; + _cleanup_(journal_file_offline_closep) JournalFile *f = NULL; log_info("/* %s(%zu, %zu) */", __func__, n, num_corrupted); - assert_se(m = mmap_cache_new()); + ASSERT_NOT_NULL(m = mmap_cache_new()); - mkdtemp_chdir_chattr(t); + mkdtemp_chdir_chattr("/var/tmp/journal-seq-XXXXXX", &t); - assert_se(journal_file_open(-EBADF, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644, - UINT64_MAX, NULL, m, NULL, &f) == 0); + ASSERT_OK(journal_file_open(-EBADF, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644, + UINT64_MAX, NULL, m, NULL, &f)); - assert_se(seqnum = new0(uint64_t, n)); - assert_se(offset = new0(uint64_t, n)); + ASSERT_NOT_NULL(seqnum = new0(uint64_t, n)); + ASSERT_NOT_NULL(offset = new0(uint64_t, n)); for (size_t i = 0; i < n; i++) { append_number(f, i, NULL, seqnum + i, offset + i); - if (i == 0) { - assert_se(seqnum[i] > 0); - assert_se(offset[i] > 0); - } else { - assert_se(seqnum[i] > seqnum[i-1]); - assert_se(offset[i] > offset[i-1]); - } + ASSERT_GT(seqnum[i], i == 0 ? 0 : seqnum[i-1]); + ASSERT_GT(offset[i], i == 0 ? 0 : offset[i-1]); } - assert_se(offset_candidates = newdup(uint64_t, offset, n)); + ASSERT_NOT_NULL(offset_candidates = newdup(uint64_t, offset, n)); verify(f, seqnum, offset_candidates, offset, n); /* Reset chain cache. */ - assert_se(journal_file_move_to_entry_by_offset(f, offset[0], DIRECTION_DOWN, NULL, NULL) > 0); + ASSERT_OK_POSITIVE(journal_file_move_to_entry_by_offset(f, offset[0], DIRECTION_DOWN, NULL, NULL)); /* make journal corrupted by clearing seqnum. */ for (size_t i = n - num_corrupted; i < n; i++) { Object *o; - assert_se(journal_file_move_to_object(f, OBJECT_ENTRY, offset[i], &o) >= 0); - assert_se(o); + ASSERT_OK(journal_file_move_to_object(f, OBJECT_ENTRY, offset[i], &o)); + ASSERT_NOT_NULL(o); o->entry.seqnum = 0; seqnum[i] = 0; offset_candidates[i] = 0; } verify(f, seqnum, offset_candidates, offset, n); - - test_close(f); - test_done(t); } TEST(generic_array_bisect) { @@ -919,6 +877,449 @@ TEST(generic_array_bisect) { test_generic_array_bisect_one(100, 40); } +typedef struct TestEntry { + uint64_t seqnum; + sd_id128_t seqnum_id; + sd_id128_t boot_id; + dual_timestamp ts; + unsigned number; + unsigned data; +} TestEntry; + +static bool find_entry_monotonic_one( + const TestEntry *e, + bool next, + sd_id128_t boot_id, + usec_t usec, + unsigned data, + bool *boot_found) { + + assert(e); + assert(boot_found); + + if (sd_id128_equal(boot_id, e->boot_id)) + *boot_found = true; + + if (data != 0 && data != e->data) + return false; + + if (sd_id128_equal(boot_id, e->boot_id)) + return next ? usec <= e->ts.monotonic : usec >= e->ts.monotonic; + + return *boot_found; +} + +static size_t find_entry_monotonic( + const TestEntry *entries, + size_t n_entries, + bool next, + sd_id128_t boot_id, + usec_t usec, + unsigned data) { + + bool boot_found = false; + + assert(entries || n_entries == 0); + + for (size_t i = 0; i < n_entries; i++) { + size_t j = next ? i : n_entries - i - 1; + const TestEntry *e = &entries[j]; + + if (find_entry_monotonic_one(e, next, boot_id, usec, data, &boot_found)) + return j; + } + + return SIZE_MAX; +} + +static size_t find_entry_realtime( + const TestEntry *entries, + size_t n_entries, + bool next, + usec_t usec, + unsigned data) { + + assert(entries || n_entries == 0); + + for (size_t i = 0; i < n_entries; i++) { + size_t j = next ? i : n_entries - i - 1; + const TestEntry *e = &entries[j]; + + if (data != 0 && data != e->data) + continue; + + if (next ? usec <= e->ts.realtime : usec >= e->ts.realtime) + return j; + } + + return SIZE_MAX; +} + +static size_t next_entry( + const TestEntry *entries, + size_t n_entries, + bool next, + size_t prev, + unsigned data) { + + assert(entries || n_entries == 0); + + if (next) + for (size_t i = prev + 1; i < n_entries; i++) { + const TestEntry *e = &entries[i]; + + if (data != 0 && data != e->data) + continue; + + return i; + } + else + for (size_t i = prev; i > 0; i--) { + const TestEntry *e = &entries[i-1]; + + if (data != 0 && data != e->data) + continue; + + return i-1; + } + + return SIZE_MAX; +} + +static void verify_entry(sd_journal *j, const TestEntry *entry) { + _cleanup_free_ char *s = NULL, *e = NULL; + sd_id128_t id; + usec_t t; + const void *d; + size_t l; + + assert(j); + assert(entry); + + ASSERT_OK(sd_journal_get_monotonic_usec(j, &t, &id)); + ASSERT_STREQ(SD_ID128_TO_STRING(id), SD_ID128_TO_STRING(entry->boot_id)); + ASSERT_EQ(t, entry->ts.monotonic); + + ASSERT_OK(sd_journal_get_realtime_usec(j, &t)); + ASSERT_EQ(t, entry->ts.realtime); + + ASSERT_OK(sd_journal_get_data(j, "NUMBER", &d, &l)); + ASSERT_NOT_NULL(s = strndup(d, l)); + ASSERT_OK(asprintf(&e, "NUMBER=%u", entry->number)); + ASSERT_STREQ(s, e); + + s = mfree(s); + e = mfree(e); + + ASSERT_OK(sd_journal_get_data(j, "DATA", &d, &l)); + ASSERT_NOT_NULL(s = strndup(d, l)); + ASSERT_OK(asprintf(&e, "DATA=%u", entry->data)); + ASSERT_STREQ(s, e); +} + +static void test_sd_journal_seek_monotonic_usec( + sd_journal *j, + const TestEntry *entries, + size_t n_entries, + bool next, + sd_id128_t boot_id, + usec_t usec, + unsigned data) { + + assert(j); + assert(entries || n_entries == 0); + + log_debug("/* %s(next=%s, boot_id=%s, usec="USEC_FMT") */", + __func__, yes_no(next), SD_ID128_TO_STRING(boot_id), usec); + + ASSERT_OK(sd_journal_seek_monotonic_usec(j, boot_id, usec)); + + for (size_t i = find_entry_monotonic(entries, n_entries, next, boot_id, usec, data); + i != SIZE_MAX; + i = next_entry(entries, n_entries, next, i, data)) { + + if (next) + ASSERT_OK_POSITIVE(sd_journal_next(j)); + else + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + + verify_entry(j, &entries[i]); + } + + if (next) + ASSERT_OK_ZERO(sd_journal_next(j)); + else + ASSERT_OK_ZERO(sd_journal_previous(j)); +} + +static void test_sd_journal_seek_realtime_usec( + sd_journal *j, + const TestEntry *entries, + size_t n_entries, + bool next, + usec_t usec, + unsigned data) { + + assert(j); + assert(entries || n_entries == 0); + + log_debug("/* %s(next=%s, usec="USEC_FMT") */", + __func__, yes_no(next), usec); + + ASSERT_OK(sd_journal_seek_realtime_usec(j, usec)); + + for (size_t i = find_entry_realtime(entries, n_entries, next, usec, data); + i != SIZE_MAX; + i = next_entry(entries, n_entries, next, i, data)) { + + if (next) + ASSERT_OK_POSITIVE(sd_journal_next(j)); + else + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + + verify_entry(j, &entries[i]); + } + + if (next) + ASSERT_OK_ZERO(sd_journal_next(j)); + else + ASSERT_OK_ZERO(sd_journal_previous(j)); +} + +static void append_test_entry_full( + JournalFile **f, + MMapCache *m, + TestEntry **entries, + size_t *n_entries, + uint64_t *seqnum, + sd_id128_t *seqnum_id, + const sd_id128_t *boot_id, + const dual_timestamp *ts, + unsigned *number, + unsigned data, + bool expect_rotate) { + + struct iovec iovec[3]; + size_t n_iovec = 0; + + assert(f); + assert(*f); + assert(entries); + assert(n_entries); + assert(*entries || *n_entries == 0); + assert(seqnum); + assert(seqnum_id); + assert(boot_id); + assert(ts); + assert(number); + + (*number)++; + + const char *q = strjoina("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id)); + iovec[n_iovec++] = IOVEC_MAKE_STRING(q); + + _cleanup_free_ char *n = NULL; + ASSERT_OK(asprintf(&n, "NUMBER=%u", *number)); + iovec[n_iovec++] = IOVEC_MAKE_STRING(n); + + _cleanup_free_ char *d = NULL; + ASSERT_OK(asprintf(&d, "DATA=%u", data)); + iovec[n_iovec++] = IOVEC_MAKE_STRING(d); + + if (expect_rotate) { + ASSERT_ERROR(journal_file_append_entry( + *f, + ts, + boot_id, + iovec, n_iovec, + seqnum, + seqnum_id, + /* ret_object = */ NULL, + /* ret_offset = */ NULL), EREMCHG); + + ASSERT_OK(journal_file_rotate( + f, + m, + /* file_flags = */ JOURNAL_STRICT_ORDER, + /* compress_threshold_bytes = */ UINT64_MAX, + /* deferred_closes = */ NULL)); + } + + ASSERT_OK(journal_file_append_entry( + *f, + ts, + boot_id, + iovec, n_iovec, + seqnum, + seqnum_id, + /* ret_object = */ NULL, + /* ret_offset = */ NULL)); + + ASSERT_NOT_NULL(GREEDY_REALLOC(*entries, *n_entries + 1)); + (*entries)[(*n_entries)++] = (TestEntry) { + .seqnum = *seqnum, + .seqnum_id = *seqnum_id, + .boot_id = *boot_id, + .ts = *ts, + .number = *number, + .data = data, + }; +} + +static void append_test_entry( + JournalFile *f, + TestEntry **entries, + size_t *n_entries, + uint64_t *seqnum, + sd_id128_t *seqnum_id, + const sd_id128_t *boot_id, + const dual_timestamp *ts, + unsigned *number, + unsigned data) { + + append_test_entry_full(&f, NULL, entries, n_entries, seqnum, seqnum_id, boot_id, ts, number, data, /* expect_rotate = */ false); +} + +TEST(seek_time) { + _cleanup_(test_donep) char *t = NULL; + _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL; + _cleanup_free_ TestEntry *entries = NULL; + size_t n_entries = 0; + JournalFile *f; + + mkdtemp_chdir_chattr("/var/tmp/journal-seek-time-XXXXXX", &t); + + ASSERT_NOT_NULL(m = mmap_cache_new()); + + ASSERT_OK(journal_file_open( + -EBADF, + "test.journal", + O_RDWR|O_CREAT, + JOURNAL_STRICT_ORDER, + 0644, + /* compress_threshold_bytes = */ UINT64_MAX, + /* metrics = */ NULL, + m, + /* template = */ NULL, + &f)); + + uint64_t seqnum = 1; + sd_id128_t seqnum_id, boot_id; + ASSERT_OK(sd_id128_randomize(&seqnum_id)); + ASSERT_OK(sd_id128_randomize(&boot_id)); + + dual_timestamp base, ts; + dual_timestamp_now(&base); + + unsigned n = 0; + + ts = base; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 200); + + /* realtime goes to backward */ + ts.realtime -= 100; + ts.monotonic += 10; + append_test_entry_full(&f, m, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 200, /* expect_rotate = */ true); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 200); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + /* realtime goes to forward */ + ts.realtime += 100; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 200); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + /* reboot */ + ASSERT_OK(sd_id128_randomize(&boot_id)); + ts.realtime += 10; + ts.monotonic -= 1000; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 200); + + ts.realtime += 10; + ts.monotonic += 10; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 200); + + /* reboot */ + ASSERT_OK(sd_id128_randomize(&boot_id)); + ts.realtime += 10; + ts.monotonic -= 2000; + append_test_entry(f, &entries, &n_entries, &seqnum, &seqnum_id, &boot_id, &ts, &n, 100); + + journal_file_offline_close(f); + + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + ASSERT_OK(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE)); + + log_debug("Testing sequential read"); + ASSERT_OK(sd_journal_seek_head(j)); + ASSERT_OK_POSITIVE(sd_journal_next(j)); + test_check_numbers_down(j, n); + + ASSERT_OK(sd_journal_seek_tail(j)); + ASSERT_OK_POSITIVE(sd_journal_previous(j)); + test_check_numbers_up(j, n); + + unsigned data; + FOREACH_ARGUMENT(data, 0, 100, 200, 300) { + + sd_journal_flush_matches(j); + + if (data == 0) + log_info("no match"); + else { + log_info("match: DATA=%u", data); + _cleanup_free_ char *match_str = NULL; + ASSERT_OK(asprintf(&match_str, "DATA=%u", data)); + ASSERT_OK(sd_journal_add_match(j, match_str, SIZE_MAX)); + } + + FOREACH_ARRAY(e, entries, n_entries) { + test_sd_journal_seek_monotonic_usec(j, entries, n_entries, /* next = */ true, e->boot_id, e->ts.monotonic - 1, data); + test_sd_journal_seek_monotonic_usec(j, entries, n_entries, /* next = */ true, e->boot_id, e->ts.monotonic, data); + test_sd_journal_seek_monotonic_usec(j, entries, n_entries, /* next = */ true, e->boot_id, e->ts.monotonic + 1, data); + test_sd_journal_seek_monotonic_usec(j, entries, n_entries, /* next = */ false, e->boot_id, e->ts.monotonic - 1, data); + test_sd_journal_seek_monotonic_usec(j, entries, n_entries, /* next = */ false, e->boot_id, e->ts.monotonic, data); + test_sd_journal_seek_monotonic_usec(j, entries, n_entries, /* next = */ false, e->boot_id, e->ts.monotonic + 1, data); + + test_sd_journal_seek_realtime_usec(j, entries, n_entries, /* next = */ true, e->ts.monotonic - 1, data); + test_sd_journal_seek_realtime_usec(j, entries, n_entries, /* next = */ true, e->ts.monotonic, data); + test_sd_journal_seek_realtime_usec(j, entries, n_entries, /* next = */ true, e->ts.monotonic + 1, data); + test_sd_journal_seek_realtime_usec(j, entries, n_entries, /* next = */ false, e->ts.monotonic - 1, data); + test_sd_journal_seek_realtime_usec(j, entries, n_entries, /* next = */ false, e->ts.monotonic, data); + test_sd_journal_seek_realtime_usec(j, entries, n_entries, /* next = */ false, e->ts.monotonic + 1, data); + } + } +} + static int intro(void) { /* journal_file_open() requires a valid machine id */ if (access("/etc/machine-id", F_OK) != 0) diff --git a/src/resolve/test-dns-cache.c b/src/resolve/test-dns-cache.c index dc9152e3f7..2413ad795f 100644 --- a/src/resolve/test-dns-cache.c +++ b/src/resolve/test-dns-cache.c @@ -555,7 +555,7 @@ TEST(dns_cache_lookup_success) { key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); ASSERT_NOT_NULL(key); query_flags = 0; - ASSERT_TRUE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); + ASSERT_OK_POSITIVE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); ASSERT_EQ(cache.n_hit, 1u); ASSERT_EQ(cache.n_miss, 0u); @@ -592,7 +592,7 @@ TEST(dns_cache_lookup_clamp_ttl) { key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); ASSERT_NOT_NULL(key); query_flags = SD_RESOLVED_CLAMP_TTL; - ASSERT_TRUE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); + ASSERT_OK_POSITIVE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); ASSERT_EQ(cache.n_hit, 1u); ASSERT_EQ(cache.n_miss, 0u); @@ -635,7 +635,7 @@ TEST(dns_cache_lookup_returns_most_recent_response) { key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); ASSERT_NOT_NULL(key); query_flags = 0; - ASSERT_TRUE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); + ASSERT_OK_POSITIVE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); ASSERT_EQ(cache.n_hit, 1u); ASSERT_EQ(cache.n_miss, 0u); @@ -680,7 +680,7 @@ TEST(dns_cache_lookup_retains_multiple_answers_from_one_response) { key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); ASSERT_NOT_NULL(key); query_flags = 0; - ASSERT_TRUE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); + ASSERT_OK_POSITIVE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); ASSERT_EQ(cache.n_hit, 1u); ASSERT_EQ(cache.n_miss, 0u); @@ -724,7 +724,7 @@ TEST(dns_cache_lookup_nxdomain) { key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); ASSERT_NOT_NULL(key); query_flags = 0; - ASSERT_TRUE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); + ASSERT_OK_POSITIVE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); ASSERT_EQ(cache.n_hit, 1u); ASSERT_EQ(cache.n_miss, 0u); @@ -809,7 +809,7 @@ TEST(dns_cache_lookup_mdns_multiple_shared_responses_are_cached) { key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "example.com"); ASSERT_NOT_NULL(key); query_flags = 0; - ASSERT_TRUE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); + ASSERT_OK_POSITIVE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); dns_resource_key_unref(key); ASSERT_EQ(cache.n_hit, 1u); @@ -865,7 +865,7 @@ TEST(dns_cache_lookup_mdns_multiple_unshared_responses_are_not_cached) { key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "example.com"); ASSERT_NOT_NULL(key); query_flags = 0; - ASSERT_TRUE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); + ASSERT_OK_POSITIVE(dns_cache_lookup(&cache, key, query_flags, &ret_rcode, &ret_answer, &ret_full_packet, &ret_query_flags, NULL)); dns_resource_key_unref(key); ASSERT_EQ(cache.n_hit, 1u); diff --git a/src/shared/tests.h b/src/shared/tests.h index 121d4f0edd..d4d9aa998b 100644 --- a/src/shared/tests.h +++ b/src/shared/tests.h @@ -217,6 +217,39 @@ static inline int run_test_table(void) { } \ }) +/* For funtions that return a boolean on success and a negative errno on failure. */ +#define ASSERT_OK_POSITIVE(expr) \ + ({ \ + typeof(expr) _result = (expr); \ + if (_result < 0) { \ + log_error_errno(_result, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \ + PROJECT_FILE, __LINE__, #expr); \ + abort(); \ + } \ + if (_result == 0) { \ + log_error("%s:%i: Assertion failed: expected \"%s\" to be positive, but it is zero.", \ + PROJECT_FILE, __LINE__, #expr); \ + abort(); \ + } \ + }) + +#define ASSERT_OK_ZERO(expr) \ + ({ \ + typeof(expr) _result = (expr); \ + if (_result < 0) { \ + log_error_errno(_result, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \ + PROJECT_FILE, __LINE__, #expr); \ + abort(); \ + } \ + if (_result != 0) { \ + char _sexpr[DECIMAL_STR_MAX(typeof(expr))]; \ + xsprintf(_sexpr, DECIMAL_STR_FMT(_result), _result); \ + log_error("%s:%i: Assertion failed: expected \"%s\" to be zero, but it is %s.", \ + PROJECT_FILE, __LINE__, #expr, _sexpr); \ + abort(); \ + } \ + }) + #define ASSERT_OK_ERRNO(expr) \ ({ \ typeof(expr) _result = (expr); \ diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 3d5b0cfeed..b56f5b86e4 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -1117,6 +1117,18 @@ TEST(ASSERT) { ASSERT_SIGNAL(ASSERT_OK(-1), SIGABRT); ASSERT_SIGNAL(ASSERT_OK(-ENOANO), SIGABRT); + ASSERT_OK_POSITIVE(1); + ASSERT_OK_POSITIVE(255); + ASSERT_SIGNAL(ASSERT_OK_POSITIVE(0), SIGABRT); + ASSERT_SIGNAL(ASSERT_OK_POSITIVE(-1), SIGABRT); + ASSERT_SIGNAL(ASSERT_OK_POSITIVE(-ENOANO), SIGABRT); + + ASSERT_OK_ZERO(0); + ASSERT_SIGNAL(ASSERT_OK_ZERO(1), SIGABRT); + ASSERT_SIGNAL(ASSERT_OK_ZERO(255), SIGABRT); + ASSERT_SIGNAL(ASSERT_OK_ZERO(-1), SIGABRT); + ASSERT_SIGNAL(ASSERT_OK_ZERO(-ENOANO), SIGABRT); + ASSERT_OK_ERRNO(0 >= 0); ASSERT_OK_ERRNO(255 >= 0); ASSERT_OK_ERRNO(printf("Hello world\n"));