1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "journal-def.h"
29 #include "journal-file.h"
30 #include "journal-authenticate.h"
31 #include "journal-verify.h"
38 * - evolve key even if nothing happened in regular intervals
39 * - add macro for accessing flags
41 * - Allow building without libgcrypt
47 static int journal_file_object_verify(JournalFile *f, Object *o) {
53 /* This does various superficial tests about the length an
54 * possible field values. It does not follow any references to
57 if ((o->object.flags & OBJECT_COMPRESSED) &&
58 o->object.type != OBJECT_DATA)
61 switch (o->object.type) {
66 if (le64toh(o->data.entry_offset) <= 0 ||
67 le64toh(o->data.n_entries) <= 0)
70 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
73 h1 = le64toh(o->data.hash);
75 if (o->object.flags & OBJECT_COMPRESSED) {
77 uint64_t alloc = 0, b_size;
79 if (!uncompress_blob(o->data.payload,
80 le64toh(o->object.size) - offsetof(Object, data.payload),
84 h2 = hash64(b, b_size);
87 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
92 if (!VALID64(o->data.next_hash_offset) ||
93 !VALID64(o->data.next_field_offset) ||
94 !VALID64(o->data.entry_offset) ||
95 !VALID64(o->data.entry_array_offset))
102 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
105 if (!VALID64(o->field.next_hash_offset) ||
106 !VALID64(o->field.head_data_offset))
111 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
114 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
117 if (le64toh(o->entry.seqnum) <= 0 ||
118 !VALID_REALTIME(le64toh(o->entry.realtime)) ||
119 !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
122 for (i = 0; i < journal_file_entry_n_items(o); i++) {
123 if (o->entry.items[i].object_offset == 0 ||
124 !VALID64(o->entry.items[i].object_offset))
130 case OBJECT_DATA_HASH_TABLE:
131 case OBJECT_FIELD_HASH_TABLE:
132 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
135 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
138 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
139 if (o->hash_table.items[i].head_hash_offset != 0 &&
140 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
142 if (o->hash_table.items[i].tail_hash_offset != 0 &&
143 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
146 if ((o->hash_table.items[i].head_hash_offset != 0) !=
147 (o->hash_table.items[i].tail_hash_offset != 0))
153 case OBJECT_ENTRY_ARRAY:
154 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
157 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
160 if (!VALID64(o->entry_array.next_entry_array_offset))
163 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
164 if (o->entry_array.items[i] != 0 &&
165 !VALID64(o->entry_array.items[i]))
171 if (le64toh(o->object.size) != sizeof(TagObject))
174 if (!VALID_EPOCH(o->tag.epoch))
183 static void draw_progress(uint64_t p, usec_t *last_usec) {
187 if (!isatty(STDOUT_FILENO))
190 z = now(CLOCK_MONOTONIC);
193 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
198 n = (3 * columns()) / 4;
199 j = (n * (unsigned) p) / 65535ULL;
202 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
204 for (i = 0; i < j; i++)
205 fputs("\xe2\x96\x88", stdout);
207 fputs(ANSI_HIGHLIGHT_OFF, stdout);
209 for (i = 0; i < k; i++)
210 fputs("\xe2\x96\x91", stdout);
212 printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
214 fputs("\r\x1B[?25h", stdout);
218 static void flush_progress(void) {
221 if (!isatty(STDOUT_FILENO))
224 n = (3 * columns()) / 4;
228 for (i = 0; i < n + 5; i++)
235 static int write_uint64(int fd, uint64_t p) {
238 k = write(fd, &p, sizeof(p));
247 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
262 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
278 static int entry_points_to_data(
291 assert(entry_fd >= 0);
293 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
294 log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
298 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
302 n = journal_file_entry_n_items(o);
303 for (i = 0; i < n; i++)
304 if (le64toh(o->entry.items[i].object_offset) == data_p) {
310 log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
314 /* Check if this entry is also in main entry array. Since the
315 * main entry array has already been verified we can rely on
318 n = le64toh(f->header->n_entries);
319 a = le64toh(f->header->entry_array_offset);
325 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
329 m = journal_file_entry_array_n_items(o);
330 for (j = 0; i < n && j < m; i++, j++)
331 if (le64toh(o->entry_array.items[j]) == entry_p)
334 a = le64toh(o->entry_array.next_entry_array_offset);
340 static int verify_data(
342 Object *o, uint64_t p,
343 int entry_fd, uint64_t n_entries,
344 int entry_array_fd, uint64_t n_entry_arrays) {
346 uint64_t i, n, a, last, q;
351 assert(entry_fd >= 0);
352 assert(entry_array_fd >= 0);
354 n = le64toh(o->data.n_entries);
355 a = le64toh(o->data.entry_array_offset);
357 /* We already checked this earlier */
360 last = q = le64toh(o->data.entry_offset);
361 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
370 log_error("Array chain too short at %llu", (unsigned long long) p);
374 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
375 log_error("Invalid array at %llu", (unsigned long long) p);
379 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
383 next = le64toh(o->entry_array.next_entry_array_offset);
384 if (next != 0 && next <= a) {
385 log_error("Array chain has cycle at %llu", (unsigned long long) p);
389 m = journal_file_entry_array_n_items(o);
390 for (j = 0; i < n && j < m; i++, j++) {
392 q = le64toh(o->entry_array.items[j]);
394 log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
399 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
403 /* Pointer might have moved, reposition */
404 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
415 static int verify_hash_table(
417 int data_fd, uint64_t n_data,
418 int entry_fd, uint64_t n_entries,
419 int entry_array_fd, uint64_t n_entry_arrays,
421 bool show_progress) {
427 assert(data_fd >= 0);
428 assert(entry_fd >= 0);
429 assert(entry_array_fd >= 0);
432 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
433 for (i = 0; i < n; i++) {
434 uint64_t last = 0, p;
437 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
439 p = le64toh(f->data_hash_table[i].head_hash_offset);
444 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
445 log_error("Invalid data object at hash entry %llu of %llu",
446 (unsigned long long) i, (unsigned long long) n);
450 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
454 next = le64toh(o->data.next_hash_offset);
455 if (next != 0 && next <= p) {
456 log_error("Hash chain has a cycle in hash entry %llu of %llu",
457 (unsigned long long) i, (unsigned long long) n);
461 if (le64toh(o->data.hash) % n != i) {
462 log_error("Hash value mismatch in hash entry %llu of %llu",
463 (unsigned long long) i, (unsigned long long) n);
467 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
475 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
476 log_error("Tail hash pointer mismatch in hash table");
484 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
489 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
492 q = le64toh(f->data_hash_table[h].head_hash_offset);
499 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
503 q = le64toh(o->data.next_hash_offset);
509 static int verify_entry(
511 Object *o, uint64_t p,
512 int data_fd, uint64_t n_data) {
519 assert(data_fd >= 0);
521 n = journal_file_entry_n_items(o);
522 for (i = 0; i < n; i++) {
526 q = le64toh(o->entry.items[i].object_offset);
527 h = le64toh(o->entry.items[i].hash);
529 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
530 log_error("Invalid data object at entry %llu",
531 (unsigned long long) p);
535 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
539 if (le64toh(u->data.hash) != h) {
540 log_error("Hash mismatch for data object at entry %llu",
541 (unsigned long long) p);
545 r = data_object_in_hash_table(f, h, q);
549 log_error("Data object missing from hash at entry %llu",
550 (unsigned long long) p);
558 static int verify_entry_array(
560 int data_fd, uint64_t n_data,
561 int entry_fd, uint64_t n_entries,
562 int entry_array_fd, uint64_t n_entry_arrays,
564 bool show_progress) {
566 uint64_t i = 0, a, n, last = 0;
570 assert(data_fd >= 0);
571 assert(entry_fd >= 0);
572 assert(entry_array_fd >= 0);
575 n = le64toh(f->header->n_entries);
576 a = le64toh(f->header->entry_array_offset);
582 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
585 log_error("Array chain too short at %llu of %llu",
586 (unsigned long long) i, (unsigned long long) n);
590 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
591 log_error("Invalid array at %llu of %llu",
592 (unsigned long long) i, (unsigned long long) n);
596 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
600 next = le64toh(o->entry_array.next_entry_array_offset);
601 if (next != 0 && next <= a) {
602 log_error("Array chain has cycle at %llu of %llu",
603 (unsigned long long) i, (unsigned long long) n);
607 m = journal_file_entry_array_n_items(o);
608 for (j = 0; i < n && j < m; i++, j++) {
611 p = le64toh(o->entry_array.items[j]);
613 log_error("Entry array not sorted at %llu of %llu",
614 (unsigned long long) i, (unsigned long long) n);
619 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
620 log_error("Invalid array entry at %llu of %llu",
621 (unsigned long long) i, (unsigned long long) n);
625 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
629 r = verify_entry(f, o, p, data_fd, n_data);
633 /* Pointer might have moved, reposition */
634 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
645 static int journal_file_parse_verification_key(JournalFile *f, const char *key) {
650 unsigned long long start, interval;
652 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
653 seed = malloc(seed_size);
658 for (c = 0; c < seed_size; c++) {
677 seed[c] = (uint8_t) (x * 16 + y);
686 r = sscanf(k, "%llx-%llx", &start, &interval);
692 f->fsprg_seed = seed;
693 f->fsprg_seed_size = seed_size;
695 f->fss_start_usec = start * interval;
696 f->fss_interval_usec = interval;
701 int journal_file_verify(
704 usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
705 bool show_progress) {
708 uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0;
709 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
710 sd_id128_t entry_boot_id;
711 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
712 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;
713 usec_t last_usec = 0;
714 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
715 char data_path[] = "/var/tmp/journal-data-XXXXXX",
716 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
717 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
724 r = journal_file_parse_verification_key(f, key);
726 log_error("Failed to parse seed.");
732 data_fd = mkostemp(data_path, O_CLOEXEC);
734 log_error("Failed to create data file: %m");
740 entry_fd = mkostemp(entry_path, O_CLOEXEC);
742 log_error("Failed to create entry file: %m");
748 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
749 if (entry_array_fd < 0) {
750 log_error("Failed to create entry array file: %m");
754 unlink(entry_array_path);
757 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
759 if (f->header->compatible_flags != 0)
762 log_error("Cannot verify file with unknown extensions.");
767 for (i = 0; i < sizeof(f->header->reserved); i++)
768 if (f->header->reserved[i] != 0) {
769 log_error("Reserved field in non-zero.");
774 /* First iteration: we go through all objects, verify the
775 * superficial structure, headers, hashes. */
777 p = le64toh(f->header->header_size);
780 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
782 r = journal_file_move_to_object(f, -1, p, &o);
784 log_error("Invalid object at %llu", (unsigned long long) p);
788 if (p > le64toh(f->header->tail_object_offset)) {
789 log_error("Invalid tail object pointer");
794 if (p == le64toh(f->header->tail_object_offset))
799 r = journal_file_object_verify(f, o);
801 log_error("Invalid object contents at %llu", (unsigned long long) p);
805 if (o->object.flags & OBJECT_COMPRESSED &&
806 !(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) {
807 log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
812 switch (o->object.type) {
815 r = write_uint64(data_fd, p);
827 if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) && n_tags <= 0) {
828 log_error("First entry before first tag at %llu", (unsigned long long) p);
833 r = write_uint64(entry_fd, p);
837 if (last_tag_realtime > le64toh(o->entry.realtime)) {
838 log_error("Older entry after newer tag at %llu", (unsigned long long) p);
843 if (!entry_seqnum_set &&
844 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
845 log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
850 if (entry_seqnum_set &&
851 entry_seqnum >= le64toh(o->entry.seqnum)) {
852 log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
857 entry_seqnum = le64toh(o->entry.seqnum);
858 entry_seqnum_set = true;
860 if (entry_monotonic_set &&
861 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
862 entry_monotonic > le64toh(o->entry.monotonic)) {
863 log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
868 entry_monotonic = le64toh(o->entry.monotonic);
869 entry_boot_id = o->entry.boot_id;
870 entry_monotonic_set = true;
872 if (!entry_realtime_set &&
873 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
874 log_error("Head entry realtime timestamp incorrect");
879 entry_realtime = le64toh(o->entry.realtime);
880 entry_realtime_set = true;
885 case OBJECT_DATA_HASH_TABLE:
886 if (n_data_hash_tables > 1) {
887 log_error("More than one data hash table at %llu", (unsigned long long) p);
892 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
893 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
894 log_error("Header fields for data hash table invalid");
899 n_data_hash_tables++;
902 case OBJECT_FIELD_HASH_TABLE:
903 if (n_field_hash_tables > 1) {
904 log_error("More than one field hash table at %llu", (unsigned long long) p);
909 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
910 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
911 log_error("Header fields for field hash table invalid");
916 n_field_hash_tables++;
919 case OBJECT_ENTRY_ARRAY:
920 r = write_uint64(entry_array_fd, p);
924 if (p == le64toh(f->header->entry_array_offset)) {
925 if (found_main_entry_array) {
926 log_error("More than one main entry array at %llu", (unsigned long long) p);
931 found_main_entry_array = true;
940 if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) {
941 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
946 if (le64toh(o->tag.seqnum) != n_tags + 1) {
947 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
952 if (le64toh(o->tag.epoch) < last_epoch) {
953 log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
959 log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
961 rt = (o->tag.epoch + 1) * f->fss_interval_usec + f->fss_start_usec;
962 if (entry_realtime_set && entry_realtime >= rt) {
963 log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
968 /* OK, now we know the epoch. So let's now set
969 * it, and calculate the HMAC for everything
970 * since the last tag. */
971 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
975 r = journal_file_hmac_start(f);
980 r = journal_file_hmac_put_header(f);
984 q = le64toh(f->header->header_size);
989 r = journal_file_move_to_object(f, -1, q, &o);
993 r = journal_file_hmac_put_object(f, -1, q);
997 q = q + ALIGN64(le64toh(o->object.size));
1000 /* Position might have changed, let's reposition things */
1001 r = journal_file_move_to_object(f, -1, p, &o);
1005 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1006 log_error("Tag failed verification at %llu", (unsigned long long) p);
1011 f->hmac_running = false;
1012 last_tag_realtime = rt;
1015 last_tag = p + ALIGN64(le64toh(o->object.size));
1016 last_epoch = le64toh(o->tag.epoch);
1026 if (p == le64toh(f->header->tail_object_offset))
1029 p = p + ALIGN64(le64toh(o->object.size));
1033 log_error("Tail object pointer dead");
1038 if (n_objects != le64toh(f->header->n_objects)) {
1039 log_error("Object number mismatch");
1044 if (n_entries != le64toh(f->header->n_entries)) {
1045 log_error("Entry number mismatch");
1050 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1051 n_data != le64toh(f->header->n_data)) {
1052 log_error("Data number mismatch");
1057 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1058 n_fields != le64toh(f->header->n_fields)) {
1059 log_error("Field number mismatch");
1064 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1065 n_tags != le64toh(f->header->n_tags)) {
1066 log_error("Tag number mismatch");
1071 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1072 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1073 log_error("Entry array number mismatch");
1078 if (n_data_hash_tables != 1) {
1079 log_error("Missing data hash table");
1084 if (n_field_hash_tables != 1) {
1085 log_error("Missing field hash table");
1090 if (!found_main_entry_array) {
1091 log_error("Missing entry array");
1096 if (entry_seqnum_set &&
1097 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1098 log_error("Invalid tail seqnum");
1103 if (entry_monotonic_set &&
1104 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1105 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1106 log_error("Invalid tail monotonic timestamp");
1111 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1112 log_error("Invalid tail realtime timestamp");
1117 /* Second iteration: we follow all objects referenced from the
1118 * two entry points: the object hash table and the entry
1119 * array. We also check that everything referenced (directly
1120 * or indirectly) in the data hash table also exists in the
1121 * entry array, and vice versa. Note that we do not care for
1122 * unreferenced objects. We only care that everything that is
1123 * referenced is consistent. */
1125 r = verify_entry_array(f,
1127 entry_fd, n_entries,
1128 entry_array_fd, n_entry_arrays,
1134 r = verify_hash_table(f,
1136 entry_fd, n_entries,
1137 entry_array_fd, n_entry_arrays,
1146 mmap_cache_close_fd(f->mmap, data_fd);
1147 mmap_cache_close_fd(f->mmap, entry_fd);
1148 mmap_cache_close_fd(f->mmap, entry_array_fd);
1150 close_nointr_nofail(data_fd);
1151 close_nointr_nofail(entry_fd);
1152 close_nointr_nofail(entry_array_fd);
1154 if (first_validated)
1155 *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
1157 *last_validated = last_tag_realtime;
1159 *last_contained = le64toh(f->header->tail_entry_realtime);
1167 log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
1169 (unsigned long long) p,
1170 (unsigned long long) f->last_stat.st_size,
1171 (unsigned long long) (100 * p / f->last_stat.st_size));
1174 mmap_cache_close_fd(f->mmap, data_fd);
1175 close_nointr_nofail(data_fd);
1178 if (entry_fd >= 0) {
1179 mmap_cache_close_fd(f->mmap, entry_fd);
1180 close_nointr_nofail(entry_fd);
1183 if (entry_array_fd >= 0) {
1184 mmap_cache_close_fd(f->mmap, entry_array_fd);
1185 close_nointr_nofail(entry_array_fd);