X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fsd-journal.c;h=d580b8e76869fdf3dde25ee38f167c606ee49696;hp=1f4ad0ff649d73eb7ac5478bb5b2765a851e431a;hb=1cc101f1e59ca2f5e87dea48ac9ed98c6f077b3b;hpb=161e54f8719c4a11440d762276cbccbeb1736f8c diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 1f4ad0ff6..d580b8e76 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -43,32 +43,34 @@ struct sd_journal { Hashmap *files; JournalFile *current_file; + uint64_t current_field; LIST_HEAD(Match, matches); }; -int sd_journal_add_match(sd_journal *j, const char *field, const void *data, size_t size) { +int sd_journal_add_match(sd_journal *j, const void *data, size_t size) { Match *m; - char *e; assert(j); - assert(field); - assert(data || size == 0); + + if (size <= 0) + return -EINVAL; + + assert(data); m = new0(Match, 1); if (!m) return -ENOMEM; - m->size = strlen(field) + 1 + size; + m->size = size; + m->data = malloc(m->size); if (!m->data) { free(m); return -ENOMEM; } - e = stpcpy(m->data, field); - *(e++) = '='; - memcpy(e, data, size); + memcpy(m->data, data, size); LIST_PREPEND(Match, matches, j->matches, m); return 0; @@ -87,10 +89,22 @@ void sd_journal_flush_matches(sd_journal *j) { } static int compare_order(JournalFile *af, Object *ao, uint64_t ap, - JournalFile *bf, Object *bo, uint64_t bp) { + JournalFile *bf, Object *bo, uint64_t bp) { uint64_t a, b; + /* We operate on two different files here, hence we can access + * two objects at the same time, which we normally can't. + * + * If contents and timestamps match, these entries are + * identical, even if the seqnum does not match */ + + if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) && + ao->entry.monotonic == bo->entry.monotonic && + ao->entry.realtime == bo->entry.realtime && + ao->entry.xor_hash == bo->entry.xor_hash) + return 0; + if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) { /* If this is from the same seqnum source, compare @@ -98,23 +112,47 @@ static int compare_order(JournalFile *af, Object *ao, uint64_t ap, a = le64toh(ao->entry.seqnum); b = le64toh(bo->entry.seqnum); + if (a < b) + return -1; + if (a > b) + return 1; - } else if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) { + /* Wow! This is weird, different data but the same + * seqnums? Something is borked, but let's make the + * best of it and compare by time. */ + } + + if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) { /* If the boot id matches compare monotonic time */ a = le64toh(ao->entry.monotonic); b = le64toh(bo->entry.monotonic); - } else { - - /* Otherwise compare UTC time */ - a = le64toh(ao->entry.realtime); - b = le64toh(ao->entry.realtime); + if (a < b) + return -1; + if (a > b) + return 1; } - return - a < b ? -1 : - a > b ? +1 : 0; + /* Otherwise compare UTC time */ + a = le64toh(ao->entry.realtime); + b = le64toh(ao->entry.realtime); + + if (a < b) + return -1; + if (a > b) + return 1; + + /* Finally, compare by contents */ + a = le64toh(ao->entry.xor_hash); + b = le64toh(ao->entry.xor_hash); + + if (a < b) + return -1; + if (a > b) + return 1; + + return 0; } int sd_journal_next(sd_journal *j) { @@ -143,7 +181,8 @@ int sd_journal_next(sd_journal *j) { else if (r == 0) continue; - if (!new_current || compare_order(new_current, new_entry, new_offset, f, o, p) > 0) { + if (!new_current || + compare_order(new_current, new_entry, new_offset, f, o, p) > 0) { new_current = f; new_entry = o; new_offset = p; @@ -153,7 +192,34 @@ int sd_journal_next(sd_journal *j) { if (new_current) { j->current_file = new_current; j->current_file->current_offset = new_offset; - j->current_file->current_field = 0; + j->current_field = 0; + + /* Skip over any identical entries in the other files too */ + + HASHMAP_FOREACH(f, j->files, i) { + Object *o; + uint64_t p; + + if (j->current_file == f) + continue; + + if (f->current_offset > 0) { + r = journal_file_move_to_object(f, f->current_offset, OBJECT_ENTRY, &o); + if (r < 0) + return r; + } else + o = NULL; + + r = journal_file_next_entry(f, o, &o, &p); + if (r < 0) + return r; + else if (r == 0) + continue; + + if (compare_order(new_current, new_entry, new_offset, f, o, p) == 0) + f->current_offset = p; + } + return 1; } @@ -196,7 +262,34 @@ int sd_journal_previous(sd_journal *j) { if (new_current) { j->current_file = new_current; j->current_file->current_offset = new_offset; - j->current_file->current_field = 0; + j->current_field = 0; + + /* Skip over any identical entries in the other files too */ + + HASHMAP_FOREACH(f, j->files, i) { + Object *o; + uint64_t p; + + if (j->current_file == f) + continue; + + if (f->current_offset > 0) { + r = journal_file_move_to_object(f, f->current_offset, OBJECT_ENTRY, &o); + if (r < 0) + return r; + } else + o = NULL; + + r = journal_file_prev_entry(f, o, &o, &p); + if (r < 0) + return r; + else if (r == 0) + continue; + + if (compare_order(new_current, new_entry, new_offset, f, o, p) == 0) + f->current_offset = p; + } + return 1; } @@ -395,6 +488,8 @@ void sd_journal_close(sd_journal *j) { hashmap_free(j->files); } + sd_journal_flush_matches(j); + free(j); } @@ -539,10 +634,10 @@ int sd_journal_iterate_fields(sd_journal *j, const void **data, size_t *size) { return r; n = journal_file_entry_n_items(o); - if (f->current_field >= n) + if (j->current_field >= n) return 0; - p = le64toh(o->entry.items[f->current_field].object_offset); + p = le64toh(o->entry.items[j->current_field].object_offset); r = journal_file_move_to_object(f, p, OBJECT_DATA, &o); if (r < 0) return r; @@ -557,7 +652,17 @@ int sd_journal_iterate_fields(sd_journal *j, const void **data, size_t *size) { *data = o->data.payload; *size = t; - f->current_field ++; + j->current_field ++; return 1; } + +int sd_journal_seek_head(sd_journal *j) { + assert(j); + return -EINVAL; +} + +int sd_journal_seek_tail(sd_journal *j) { + assert(j); + return -EINVAL; +}