journal-verify.c revision 5996c7c295e073ce21d41305169132c8aa993ad0
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/***
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2012 Lennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering***/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <unistd.h>
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <sys/mman.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <fcntl.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <stddef.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "macro.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "journal-def.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "journal-file.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "journal-authenticate.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "journal-verify.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "lookup3.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "compress.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "fsprg.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int journal_file_object_verify(JournalFile *f, Object *o) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t i;
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar assert(f);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar assert(o);
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* This does various superficial tests about the length an
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * possible field values. It does not follow any references to
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * other objects. */
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
7085053a437456ab87d726f3697002dd811fdf7aDaniel Wallace if ((o->object.flags & OBJECT_COMPRESSED) &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering o->object.type != OBJECT_DATA)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (o->object.type) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case OBJECT_DATA: {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t h1, h2;
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (le64toh(o->data.entry_offset) <= 0 ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering le64toh(o->data.n_entries) <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering h1 = le64toh(o->data.hash);
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering if (o->object.flags & OBJECT_COMPRESSED) {
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering#ifdef HAVE_XZ
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering void *b = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t alloc = 0, b_size;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!uncompress_blob(o->data.payload,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering le64toh(o->object.size) - offsetof(Object, data.payload),
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann &b, &alloc, &b_size))
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann return -EBADMSG;
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann h2 = hash64(b, b_size);
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann free(b);
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann#else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EPROTONOSUPPORT;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#endif
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann } else
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann if (h1 != h2)
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann return -EBADMSG;
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann if (!VALID64(o->data.next_hash_offset) ||
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann !VALID64(o->data.next_field_offset) ||
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann !VALID64(o->data.entry_offset) ||
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann !VALID64(o->data.entry_array_offset))
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann return -EBADMSG;
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann break;
ff9b60f38bf68eba4a47cabff14547d92e083214Torstein Husebø }
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar case OBJECT_FIELD:
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if (!VALID64(o->field.next_hash_offset) ||
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar !VALID64(o->field.head_data_offset))
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar break;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar case OBJECT_ENTRY:
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if (le64toh(o->entry.seqnum) <= 0 ||
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar !VALID_REALTIME(le64toh(o->entry.realtime)) ||
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar for (i = 0; i < journal_file_entry_n_items(o); i++) {
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if (o->entry.items[i].object_offset == 0 ||
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar !VALID64(o->entry.items[i].object_offset))
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt }
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar break;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar
63229aa1abdb98aa69fda9819ed2f40c8082762bLennart Poettering case OBJECT_DATA_HASH_TABLE:
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar case OBJECT_FIELD_HASH_TABLE:
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
b344bcbbfda8fbe14dadc5aa4b5dfb3ced6d76e2Lennart Poettering return -EBADMSG;
ff49bc3212cb07d850dcfd59940539773a0be26fMichal Schmidt
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
b344bcbbfda8fbe14dadc5aa4b5dfb3ced6d76e2Lennart Poettering
ff49bc3212cb07d850dcfd59940539773a0be26fMichal Schmidt for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if (o->hash_table.items[i].head_hash_offset != 0 &&
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
63229aa1abdb98aa69fda9819ed2f40c8082762bLennart Poettering return -EBADMSG;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar if (o->hash_table.items[i].tail_hash_offset != 0 &&
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if ((o->hash_table.items[i].head_hash_offset != 0) !=
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (o->hash_table.items[i].tail_hash_offset != 0))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case OBJECT_ENTRY_ARRAY:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!VALID64(o->entry_array.next_entry_array_offset))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < journal_file_entry_array_n_items(o); i++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (o->entry_array.items[i] != 0 &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering !VALID64(o->entry_array.items[i]))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case OBJECT_TAG:
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (le64toh(o->object.size) != sizeof(TagObject))
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann return -EBADMSG;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (!VALID_EPOCH(o->tag.epoch))
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return -EBADMSG;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers break;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic void draw_progress(uint64_t p, usec_t *last_usec) {
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers unsigned n, i, j, k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t z, x;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!isatty(STDOUT_FILENO))
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers return;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers z = now(CLOCK_MONOTONIC);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers x = *last_usec;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann if (x != 0 && x + 40 * USEC_PER_MSEC > z)
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann return;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
ff9b60f38bf68eba4a47cabff14547d92e083214Torstein Husebø *last_usec = z;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers n = (3 * columns()) / 4;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers j = (n * (unsigned) p) / 65535ULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = n - j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers for (i = 0; i < j; i++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fputs("\xe2\x96\x88", stdout);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fputs(ANSI_HIGHLIGHT_OFF, stdout);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < k; i++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fputs("\xe2\x96\x91", stdout);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering fputs("\r\x1B[?25h", stdout);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fflush(stdout);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poetteringstatic void flush_progress(void) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers unsigned n, i;
94676f3e9352cbf1f72e0a512ee0d2ed83ff676dLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!isatty(STDOUT_FILENO))
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
94676f3e9352cbf1f72e0a512ee0d2ed83ff676dLennart Poettering n = (3 * columns()) / 4;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers putchar('\r');
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
94676f3e9352cbf1f72e0a512ee0d2ed83ff676dLennart Poettering for (i = 0; i < n + 5; i++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering putchar(' ');
c49b30a23583ff39daaa26696bcab478d2fee0bbLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers putchar('\r');
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering fflush(stdout);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int write_uint64(int fd, uint64_t p) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers ssize_t k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = write(fd, &p, sizeof(p));
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (k < 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -errno;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (k != sizeof(p))
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -EIO;
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return 0;
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering}
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidtstatic int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t a, b;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek assert(fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Bisection ... */
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers a = 0; b = n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while (a < b) {
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering uint64_t c, *z;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering c = (a + b) / 2;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*z == p)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (a + 1 >= b)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (p < *z)
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering b = c;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a = c;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversstatic int entry_points_to_data(
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering JournalFile *f,
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering int entry_fd,
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering uint64_t n_entries,
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering uint64_t entry_p,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t data_p) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t i, n, a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Object *o;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool found = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(entry_fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = journal_file_entry_n_items(o);
2b6bf07dd23bb467099d213c97b3875c5e453491Zbigniew Jędrzejewski-Szmek for (i = 0; i < n; i++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (le64toh(o->entry.items[i].object_offset) == data_p) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering found = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!found) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Check if this entry is also in main entry array. Since the
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek * main entry array has already been verified we can rely on
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt * its consistency.*/
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering i = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = le64toh(f->header->n_entries);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a = le64toh(f->header->entry_array_offset);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers while (i < n) {
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer uint64_t m, u;
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m = journal_file_entry_array_n_items(o);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek u = MIN(n - i, m);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (entry_p <= le64toh(o->entry_array.items[u-1])) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t x, y, z;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering x = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y = u;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while (x < y) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering z = (x + y) / 2;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (le64toh(o->entry_array.items[z]) == entry_p)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (x + 1 >= y)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (entry_p < le64toh(o->entry_array.items[z]))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y = z;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen x = z;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Entry object doesn't exist in main entry array at %llu", (unsigned long long) entry_p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering i += u;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering a = le64toh(o->entry_array.next_entry_array_offset);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int verify_data(
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering JournalFile *f,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Object *o, uint64_t p,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int entry_fd, uint64_t n_entries,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int entry_array_fd, uint64_t n_entry_arrays) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t i, n, a, last, q;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
6b2b6f30e38d67b032d6bdc6b47ae05e143e96c5Michal Schmidt assert(f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(o);
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering assert(entry_fd >= 0);
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering assert(entry_array_fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = le64toh(o->data.n_entries);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a = le64toh(o->data.entry_array_offset);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers /* We already checked this earlier */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(n > 0);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers last = q = le64toh(o->data.entry_offset);
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering r = entry_points_to_data(f, entry_fd, n_entries, q, p);
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering if (r < 0)
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering return r;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering i = 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while (i < n) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers uint64_t next, m, j;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer if (a == 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error("Array chain too short at %llu", (unsigned long long) p);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EBADMSG;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error("Invalid array at %llu", (unsigned long long) p);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EBADMSG;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering next = le64toh(o->entry_array.next_entry_array_offset);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (next != 0 && next <= a) {
c62e11ce3966c55d23520b9f0785c7e839cf7f37Lennart Poettering log_error("Array chain has cycle at %llu", (unsigned long long) p);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return -EBADMSG;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m = journal_file_entry_array_n_items(o);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering for (j = 0; i < n && j < m; i++, j++) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering q = le64toh(o->entry_array.items[j]);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (q <= last) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EBADMSG;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering last = q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = entry_points_to_data(f, entry_fd, n_entries, q, p);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Pointer might have moved, reposition */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering a = next;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return 0;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int verify_hash_table(
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering JournalFile *f,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int data_fd, uint64_t n_data,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int entry_fd, uint64_t n_entries,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int entry_array_fd, uint64_t n_entry_arrays,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering usec_t *last_usec,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering bool show_progress) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering uint64_t i, n;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(f);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(data_fd >= 0);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(entry_fd >= 0);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(entry_array_fd >= 0);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(last_usec);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering for (i = 0; i < n; i++) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering uint64_t last = 0, p;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (show_progress)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering p = le64toh(f->data_hash_table[i].head_hash_offset);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering while (p != 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering Object *o;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering uint64_t next;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error("Invalid data object at hash entry %llu of %llu",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering (unsigned long long) i, (unsigned long long) n);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EBADMSG;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
7d6884b65e6ea7317346d29bc2f6c9ba051a0cacThomas Hindoe Paaboel Andersen
7d6884b65e6ea7317346d29bc2f6c9ba051a0cacThomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
7d6884b65e6ea7317346d29bc2f6c9ba051a0cacThomas Hindoe Paaboel Andersen if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering next = le64toh(o->data.next_hash_offset);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (next != 0 && next <= p) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error("Hash chain has a cycle in hash entry %llu of %llu",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering (unsigned long long) i, (unsigned long long) n);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EBADMSG;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (le64toh(o->data.hash) % n != i) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error("Hash value mismatch in hash entry %llu of %llu",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering (unsigned long long) i, (unsigned long long) n);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EBADMSG;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
82c1d8f4eb74ddd9be2c9b9b56d9dc564c599effLennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering last = p;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering p = next;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
a86a47ce1f63476631635fbcbc10af8877172114Lennart Poettering log_error("Tail hash pointer mismatch in hash table");
a86a47ce1f63476631635fbcbc10af8877172114Lennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return 0;
2ebcf936702e8e511098711b4add885372360018Zbigniew Jędrzejewski-Szmek}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
31cf921abbeafc9dae2d5c777f3e2285e6f4c19dJan Synacekstatic int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
2ebcf936702e8e511098711b4add885372360018Zbigniew Jędrzejewski-Szmek uint64_t n, h, q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(f);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek h = hash % n;
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = le64toh(f->data_hash_table[h].head_hash_offset);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while (q != 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Object *o;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (p == q)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = le64toh(o->data.next_hash_offset);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers}
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversstatic int verify_entry(
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers JournalFile *f,
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering Object *o, uint64_t p,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int data_fd, uint64_t n_data) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t i, n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(o);
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek assert(data_fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = journal_file_entry_n_items(o);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < n; i++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t q, h;
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek Object *u;
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = le64toh(o->entry.items[i].object_offset);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering h = le64toh(o->entry.items[i].hash);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Invalid data object at entry %llu",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (unsigned long long) p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (le64toh(u->data.hash) != h) {
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen log_error("Hash mismatch for data object at entry %llu",
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen (unsigned long long) p);
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen return -EBADMSG;
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen }
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = data_object_in_hash_table(f, h, q);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0)
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return r;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r == 0) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers log_error("Data object missing from hash at entry %llu",
de33fc625725d199629ed074d6278504deb23debLennart Poettering (unsigned long long) p);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return -EBADMSG;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poetteringstatic int verify_entry_array(
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering JournalFile *f,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int data_fd, uint64_t n_data,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int entry_fd, uint64_t n_entries,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int entry_array_fd, uint64_t n_entry_arrays,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t *last_usec,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers bool show_progress) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t i = 0, a, n, last = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(data_fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(entry_fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(entry_array_fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(last_usec);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = le64toh(f->header->n_entries);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering a = le64toh(f->header->entry_array_offset);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering while (i < n) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering uint64_t next, m, j;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering Object *o;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (show_progress)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (a == 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error("Array chain too short at %llu of %llu",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (unsigned long long) i, (unsigned long long) n);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Invalid array at %llu of %llu",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (unsigned long long) i, (unsigned long long) n);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering next = le64toh(o->entry_array.next_entry_array_offset);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (next != 0 && next <= a) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Array chain has cycle at %llu of %llu",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (unsigned long long) i, (unsigned long long) n);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m = journal_file_entry_array_n_items(o);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (j = 0; i < n && j < m; i++, j++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p = le64toh(o->entry_array.items[j]);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (p <= last) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Entry array not sorted at %llu of %llu",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (unsigned long long) i, (unsigned long long) n);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering last = p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Invalid array entry at %llu of %llu",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (unsigned long long) i, (unsigned long long) n);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBADMSG;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = verify_entry(f, o, p, data_fd, n_data);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Pointer might have moved, reposition */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a = next;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint journal_file_verify(
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering JournalFile *f,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *key,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
03976f7b4a84b8b1492a549a3470b2bba8f37008Lennart Poettering bool show_progress) {
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Object *o;
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_id128_t entry_boot_id;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0, n_tags = 0;
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering usec_t last_usec = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char data_path[] = "/var/tmp/journal-data-XXXXXX",
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers entry_path[] = "/var/tmp/journal-entry-XXXXXX",
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt unsigned i;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers bool found_last;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(f);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (key) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#ifdef HAVE_GCRYPT
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = journal_file_parse_verification_key(f, key);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering log_error("Failed to parse seed.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
}
#else
return -ENOTSUP;
#endif
} else if (f->seal)
return -ENOKEY;
data_fd = mkostemp(data_path, O_CLOEXEC);
if (data_fd < 0) {
log_error("Failed to create data file: %m");
r = -errno;
goto fail;
}
unlink(data_path);
entry_fd = mkostemp(entry_path, O_CLOEXEC);
if (entry_fd < 0) {
log_error("Failed to create entry file: %m");
r = -errno;
goto fail;
}
unlink(entry_path);
entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
if (entry_array_fd < 0) {
log_error("Failed to create entry array file: %m");
r = -errno;
goto fail;
}
unlink(entry_array_path);
#ifdef HAVE_GCRYPT
if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
#else
if (f->header->compatible_flags != 0)
#endif
{
log_error("Cannot verify file with unknown extensions.");
r = -ENOTSUP;
goto fail;
}
for (i = 0; i < sizeof(f->header->reserved); i++)
if (f->header->reserved[i] != 0) {
log_error("Reserved field in non-zero.");
r = -EBADMSG;
goto fail;
}
/* First iteration: we go through all objects, verify the
* superficial structure, headers, hashes. */
p = le64toh(f->header->header_size);
while (p != 0) {
if (show_progress)
draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
r = journal_file_move_to_object(f, -1, p, &o);
if (r < 0) {
log_error("Invalid object at %llu", (unsigned long long) p);
goto fail;
}
if (p > le64toh(f->header->tail_object_offset)) {
log_error("Invalid tail object pointer");
r = -EBADMSG;
goto fail;
}
if (p == le64toh(f->header->tail_object_offset))
found_last = true;
n_objects ++;
r = journal_file_object_verify(f, o);
if (r < 0) {
log_error("Invalid object contents at %llu", (unsigned long long) p);
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
switch (o->object.type) {
case OBJECT_DATA:
r = write_uint64(data_fd, p);
if (r < 0)
goto fail;
n_data++;
break;
case OBJECT_FIELD:
n_fields++;
break;
case OBJECT_ENTRY:
if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
log_error("First entry before first tag at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
r = write_uint64(entry_fd, p);
if (r < 0)
goto fail;
if (le64toh(o->entry.realtime) < last_tag_realtime) {
log_error("Older entry after newer tag at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
if (!entry_seqnum_set &&
le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum >= le64toh(o->entry.seqnum)) {
log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
entry_seqnum = le64toh(o->entry.seqnum);
entry_seqnum_set = true;
if (entry_monotonic_set &&
sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
entry_monotonic > le64toh(o->entry.monotonic)) {
log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
entry_monotonic = le64toh(o->entry.monotonic);
entry_boot_id = o->entry.boot_id;
entry_monotonic_set = true;
if (!entry_realtime_set &&
le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
log_error("Head entry realtime timestamp incorrect");
r = -EBADMSG;
goto fail;
}
entry_realtime = le64toh(o->entry.realtime);
entry_realtime_set = true;
n_entries ++;
break;
case OBJECT_DATA_HASH_TABLE:
if (n_data_hash_tables > 1) {
log_error("More than one data hash table at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
log_error("Header fields for data hash table invalid");
r = -EBADMSG;
goto fail;
}
n_data_hash_tables++;
break;
case OBJECT_FIELD_HASH_TABLE:
if (n_field_hash_tables > 1) {
log_error("More than one field hash table at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
log_error("Header fields for field hash table invalid");
r = -EBADMSG;
goto fail;
}
n_field_hash_tables++;
break;
case OBJECT_ENTRY_ARRAY:
r = write_uint64(entry_array_fd, p);
if (r < 0)
goto fail;
if (p == le64toh(f->header->entry_array_offset)) {
if (found_main_entry_array) {
log_error("More than one main entry array at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
found_main_entry_array = true;
}
n_entry_arrays++;
break;
case OBJECT_TAG:
if (!JOURNAL_HEADER_SEALED(f->header)) {
log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.seqnum) != n_tags + 1) {
log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.epoch) < last_epoch) {
log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
#ifdef HAVE_GCRYPT
if (f->seal) {
uint64_t q, rt;
log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
/* OK, now we know the epoch. So let's now set
* it, and calculate the HMAC for everything
* since the last tag. */
r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
if (r < 0)
goto fail;
r = journal_file_hmac_start(f);
if (r < 0)
goto fail;
if (last_tag == 0) {
r = journal_file_hmac_put_header(f);
if (r < 0)
goto fail;
q = le64toh(f->header->header_size);
} else
q = last_tag;
while (q <= p) {
r = journal_file_move_to_object(f, -1, q, &o);
if (r < 0)
goto fail;
r = journal_file_hmac_put_object(f, -1, o, q);
if (r < 0)
goto fail;
q = q + ALIGN64(le64toh(o->object.size));
}
/* Position might have changed, let's reposition things */
r = journal_file_move_to_object(f, -1, p, &o);
if (r < 0)
goto fail;
if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
log_error("Tag failed verification at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
}
f->hmac_running = false;
last_tag_realtime = rt;
last_sealed_realtime = entry_realtime;
}
#endif
last_tag = p + ALIGN64(le64toh(o->object.size));
last_epoch = le64toh(o->tag.epoch);
n_tags ++;
break;
default:
n_weird ++;
}
if (p == le64toh(f->header->tail_object_offset))
p = 0;
else
p = p + ALIGN64(le64toh(o->object.size));
}
if (!found_last) {
log_error("Tail object pointer dead");
r = -EBADMSG;
goto fail;
}
if (n_objects != le64toh(f->header->n_objects)) {
log_error("Object number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_entries != le64toh(f->header->n_entries)) {
log_error("Entry number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
n_data != le64toh(f->header->n_data)) {
log_error("Data number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
n_fields != le64toh(f->header->n_fields)) {
log_error("Field number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
n_tags != le64toh(f->header->n_tags)) {
log_error("Tag number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
log_error("Entry array number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_data_hash_tables != 1) {
log_error("Missing data hash table");
r = -EBADMSG;
goto fail;
}
if (n_field_hash_tables != 1) {
log_error("Missing field hash table");
r = -EBADMSG;
goto fail;
}
if (!found_main_entry_array) {
log_error("Missing entry array");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
log_error("Invalid tail seqnum");
r = -EBADMSG;
goto fail;
}
if (entry_monotonic_set &&
(!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
log_error("Invalid tail monotonic timestamp");
r = -EBADMSG;
goto fail;
}
if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
log_error("Invalid tail realtime timestamp");
r = -EBADMSG;
goto fail;
}
/* Second iteration: we follow all objects referenced from the
* two entry points: the object hash table and the entry
* array. We also check that everything referenced (directly
* or indirectly) in the data hash table also exists in the
* entry array, and vice versa. Note that we do not care for
* unreferenced objects. We only care that everything that is
* referenced is consistent. */
r = verify_entry_array(f,
data_fd, n_data,
entry_fd, n_entries,
entry_array_fd, n_entry_arrays,
&last_usec,
show_progress);
if (r < 0)
goto fail;
r = verify_hash_table(f,
data_fd, n_data,
entry_fd, n_entries,
entry_array_fd, n_entry_arrays,
&last_usec,
show_progress);
if (r < 0)
goto fail;
if (show_progress)
flush_progress();
mmap_cache_close_fd(f->mmap, data_fd);
mmap_cache_close_fd(f->mmap, entry_fd);
mmap_cache_close_fd(f->mmap, entry_array_fd);
close_nointr_nofail(data_fd);
close_nointr_nofail(entry_fd);
close_nointr_nofail(entry_array_fd);
if (first_validated)
*first_validated = last_sealed_realtime > 0 ? le64toh(f->header->head_entry_realtime) : 0;
if (last_validated)
*last_validated = last_sealed_realtime;
if (last_contained)
*last_contained = le64toh(f->header->tail_entry_realtime);
return 0;
fail:
if (show_progress)
flush_progress();
log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
f->path,
(unsigned long long) p,
(unsigned long long) f->last_stat.st_size,
(unsigned long long) (100 * p / f->last_stat.st_size));
if (data_fd >= 0) {
mmap_cache_close_fd(f->mmap, data_fd);
close_nointr_nofail(data_fd);
}
if (entry_fd >= 0) {
mmap_cache_close_fd(f->mmap, entry_fd);
close_nointr_nofail(entry_fd);
}
if (entry_array_fd >= 0) {
mmap_cache_close_fd(f->mmap, entry_array_fd);
close_nointr_nofail(entry_array_fd);
}
return r;
}