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 * - write bit mucking test
39 * - evolve key even if nothing happened in regular intervals
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 le64toh(o->entry.realtime) <= 0)
121 for (i = 0; i < journal_file_entry_n_items(o); i++) {
122 if (o->entry.items[i].object_offset == 0 ||
123 !VALID64(o->entry.items[i].object_offset))
129 case OBJECT_DATA_HASH_TABLE:
130 case OBJECT_FIELD_HASH_TABLE:
131 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
134 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
137 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
138 if (o->hash_table.items[i].head_hash_offset != 0 &&
139 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
141 if (o->hash_table.items[i].tail_hash_offset != 0 &&
142 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
145 if ((o->hash_table.items[i].head_hash_offset != 0) !=
146 (o->hash_table.items[i].tail_hash_offset != 0))
152 case OBJECT_ENTRY_ARRAY:
153 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
156 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
159 if (!VALID64(o->entry_array.next_entry_array_offset))
162 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
163 if (o->entry_array.items[i] != 0 &&
164 !VALID64(o->entry_array.items[i]))
170 if (le64toh(o->object.size) != sizeof(TagObject))
178 static void draw_progress(uint64_t p, usec_t *last_usec) {
182 if (!isatty(STDOUT_FILENO))
185 z = now(CLOCK_MONOTONIC);
188 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
193 n = (3 * columns()) / 4;
194 j = (n * (unsigned) p) / 65535ULL;
197 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
199 for (i = 0; i < j; i++)
200 fputs("\xe2\x96\x88", stdout);
202 fputs(ANSI_HIGHLIGHT_OFF, stdout);
204 for (i = 0; i < k; i++)
205 fputs("\xe2\x96\x91", stdout);
207 printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
209 fputs("\r\x1B[?25h", stdout);
213 static void flush_progress(void) {
216 if (!isatty(STDOUT_FILENO))
219 n = (3 * columns()) / 4;
223 for (i = 0; i < n + 5; i++)
230 static int write_uint64(int fd, uint64_t p) {
233 k = write(fd, &p, sizeof(p));
242 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
257 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
273 static int entry_points_to_data(
286 assert(entry_fd >= 0);
288 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
289 log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
293 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
297 n = journal_file_entry_n_items(o);
298 for (i = 0; i < n; i++)
299 if (le64toh(o->entry.items[i].object_offset) == data_p) {
305 log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
309 /* Check if this entry is also in main entry array. Since the
310 * main entry array has already been verified we can rely on
313 n = le64toh(f->header->n_entries);
314 a = le64toh(f->header->entry_array_offset);
320 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
324 m = journal_file_entry_array_n_items(o);
325 for (j = 0; i < n && j < m; i++, j++)
326 if (le64toh(o->entry_array.items[j]) == entry_p)
329 a = le64toh(o->entry_array.next_entry_array_offset);
335 static int verify_data(
337 Object *o, uint64_t p,
338 int entry_fd, uint64_t n_entries,
339 int entry_array_fd, uint64_t n_entry_arrays) {
341 uint64_t i, n, a, last, q;
346 assert(entry_fd >= 0);
347 assert(entry_array_fd >= 0);
349 n = le64toh(o->data.n_entries);
350 a = le64toh(o->data.entry_array_offset);
352 /* We already checked this earlier */
355 last = q = le64toh(o->data.entry_offset);
356 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
365 log_error("Array chain too short at %llu", (unsigned long long) p);
369 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
370 log_error("Invalid array at %llu", (unsigned long long) p);
374 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
378 next = le64toh(o->entry_array.next_entry_array_offset);
379 if (next != 0 && next <= a) {
380 log_error("Array chain has cycle at %llu", (unsigned long long) p);
384 m = journal_file_entry_array_n_items(o);
385 for (j = 0; i < n && j < m; i++, j++) {
387 q = le64toh(o->entry_array.items[j]);
389 log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
394 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
398 /* Pointer might have moved, reposition */
399 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
410 static int verify_hash_table(
412 int data_fd, uint64_t n_data,
413 int entry_fd, uint64_t n_entries,
414 int entry_array_fd, uint64_t n_entry_arrays,
416 bool show_progress) {
422 assert(data_fd >= 0);
423 assert(entry_fd >= 0);
424 assert(entry_array_fd >= 0);
427 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
428 for (i = 0; i < n; i++) {
429 uint64_t last = 0, p;
432 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
434 p = le64toh(f->data_hash_table[i].head_hash_offset);
439 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
440 log_error("Invalid data object at hash entry %llu of %llu",
441 (unsigned long long) i, (unsigned long long) n);
445 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
449 next = le64toh(o->data.next_hash_offset);
450 if (next != 0 && next <= p) {
451 log_error("Hash chain has a cycle in hash entry %llu of %llu",
452 (unsigned long long) i, (unsigned long long) n);
456 if (le64toh(o->data.hash) % n != i) {
457 log_error("Hash value mismatch in hash entry %llu of %llu",
458 (unsigned long long) i, (unsigned long long) n);
462 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
470 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
471 log_error("Tail hash pointer mismatch in hash table");
479 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
484 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
487 q = le64toh(f->data_hash_table[h].head_hash_offset);
494 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
498 q = le64toh(o->data.next_hash_offset);
504 static int verify_entry(
506 Object *o, uint64_t p,
507 int data_fd, uint64_t n_data) {
514 assert(data_fd >= 0);
516 n = journal_file_entry_n_items(o);
517 for (i = 0; i < n; i++) {
521 q = le64toh(o->entry.items[i].object_offset);
522 h = le64toh(o->entry.items[i].hash);
524 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
525 log_error("Invalid data object at entry %llu",
526 (unsigned long long) p);
530 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
534 if (le64toh(u->data.hash) != h) {
535 log_error("Hash mismatch for data object at entry %llu",
536 (unsigned long long) p);
540 r = data_object_in_hash_table(f, h, q);
544 log_error("Data object missing from hash at entry %llu",
545 (unsigned long long) p);
553 static int verify_entry_array(
555 int data_fd, uint64_t n_data,
556 int entry_fd, uint64_t n_entries,
557 int entry_array_fd, uint64_t n_entry_arrays,
559 bool show_progress) {
561 uint64_t i = 0, a, n, last = 0;
565 assert(data_fd >= 0);
566 assert(entry_fd >= 0);
567 assert(entry_array_fd >= 0);
570 n = le64toh(f->header->n_entries);
571 a = le64toh(f->header->entry_array_offset);
577 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
580 log_error("Array chain too short at %llu of %llu",
581 (unsigned long long) i, (unsigned long long) n);
585 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
586 log_error("Invalid array at %llu of %llu",
587 (unsigned long long) i, (unsigned long long) n);
591 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
595 next = le64toh(o->entry_array.next_entry_array_offset);
596 if (next != 0 && next <= a) {
597 log_error("Array chain has cycle at %llu of %llu",
598 (unsigned long long) i, (unsigned long long) n);
602 m = journal_file_entry_array_n_items(o);
603 for (j = 0; i < n && j < m; i++, j++) {
606 p = le64toh(o->entry_array.items[j]);
608 log_error("Entry array not sorted at %llu of %llu",
609 (unsigned long long) i, (unsigned long long) n);
614 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
615 log_error("Invalid array entry at %llu of %llu",
616 (unsigned long long) i, (unsigned long long) n);
620 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
624 r = verify_entry(f, o, p, data_fd, n_data);
628 /* Pointer might have moved, reposition */
629 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
640 static int journal_file_parse_verification_key(JournalFile *f, const char *key) {
645 unsigned long long start, interval;
647 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
648 seed = malloc(seed_size);
653 for (c = 0; c < seed_size; c++) {
672 seed[c] = (uint8_t) (x * 16 + y);
681 r = sscanf(k, "%llx-%llx", &start, &interval);
687 f->fsprg_seed = seed;
688 f->fsprg_seed_size = seed_size;
690 f->fss_start_usec = start * interval;
691 f->fss_interval_usec = interval;
696 int journal_file_verify(
699 usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
700 bool show_progress) {
703 uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0;
704 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
705 sd_id128_t entry_boot_id;
706 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
707 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;
708 usec_t last_usec = 0;
709 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
710 char data_path[] = "/var/tmp/journal-data-XXXXXX",
711 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
712 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
719 r = journal_file_parse_verification_key(f, key);
721 log_error("Failed to parse seed.");
727 data_fd = mkostemp(data_path, O_CLOEXEC);
729 log_error("Failed to create data file: %m");
735 entry_fd = mkostemp(entry_path, O_CLOEXEC);
737 log_error("Failed to create entry file: %m");
743 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
744 if (entry_array_fd < 0) {
745 log_error("Failed to create entry array file: %m");
749 unlink(entry_array_path);
752 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
754 if (f->header->compatible_flags != 0)
757 log_error("Cannot verify file with unknown extensions.");
762 for (i = 0; i < sizeof(f->header->reserved); i++)
763 if (f->header->reserved[i] != 0) {
764 log_error("Reserved field in non-zero.");
769 /* First iteration: we go through all objects, verify the
770 * superficial structure, headers, hashes. */
772 p = le64toh(f->header->header_size);
775 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
777 r = journal_file_move_to_object(f, -1, p, &o);
779 log_error("Invalid object at %llu", (unsigned long long) p);
783 if (p > le64toh(f->header->tail_object_offset)) {
784 log_error("Invalid tail object pointer");
789 if (p == le64toh(f->header->tail_object_offset))
794 r = journal_file_object_verify(f, o);
796 log_error("Invalid object contents at %llu", (unsigned long long) p);
800 if (o->object.flags & OBJECT_COMPRESSED &&
801 !(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) {
802 log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
807 switch (o->object.type) {
810 r = write_uint64(data_fd, p);
822 if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) && n_tags <= 0) {
823 log_error("First entry before first tag at %llu", (unsigned long long) p);
828 r = write_uint64(entry_fd, p);
832 if (last_tag_realtime > le64toh(o->entry.realtime)) {
833 log_error("Older entry after newer tag at %llu", (unsigned long long) p);
838 if (!entry_seqnum_set &&
839 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
840 log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
845 if (entry_seqnum_set &&
846 entry_seqnum >= le64toh(o->entry.seqnum)) {
847 log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
852 entry_seqnum = le64toh(o->entry.seqnum);
853 entry_seqnum_set = true;
855 if (entry_monotonic_set &&
856 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
857 entry_monotonic > le64toh(o->entry.monotonic)) {
858 log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
863 entry_monotonic = le64toh(o->entry.monotonic);
864 entry_boot_id = o->entry.boot_id;
865 entry_monotonic_set = true;
867 if (!entry_realtime_set &&
868 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
869 log_error("Head entry realtime timestamp incorrect");
874 entry_realtime = le64toh(o->entry.realtime);
875 entry_realtime_set = true;
880 case OBJECT_DATA_HASH_TABLE:
881 if (n_data_hash_tables > 1) {
882 log_error("More than one data hash table at %llu", (unsigned long long) p);
887 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
888 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
889 log_error("Header fields for data hash table invalid");
894 n_data_hash_tables++;
897 case OBJECT_FIELD_HASH_TABLE:
898 if (n_field_hash_tables > 1) {
899 log_error("More than one field hash table at %llu", (unsigned long long) p);
904 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
905 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
906 log_error("Header fields for field hash table invalid");
911 n_field_hash_tables++;
914 case OBJECT_ENTRY_ARRAY:
915 r = write_uint64(entry_array_fd, p);
919 if (p == le64toh(f->header->entry_array_offset)) {
920 if (found_main_entry_array) {
921 log_error("More than one main entry array at %llu", (unsigned long long) p);
926 found_main_entry_array = true;
935 if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) {
936 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
941 if (le64toh(o->tag.seqnum) != n_tags + 1) {
942 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
947 if (le64toh(o->tag.epoch) < last_epoch) {
948 log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
954 log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
956 rt = (o->tag.epoch + 1) * f->fss_interval_usec + f->fss_start_usec;
957 if (entry_realtime_set && entry_realtime >= rt) {
958 log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
963 /* OK, now we know the epoch. So let's now set
964 * it, and calculate the HMAC for everything
965 * since the last tag. */
966 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
970 r = journal_file_hmac_start(f);
975 r = journal_file_hmac_put_header(f);
979 q = le64toh(f->header->header_size);
984 r = journal_file_move_to_object(f, -1, q, &o);
988 r = journal_file_hmac_put_object(f, -1, q);
992 q = q + ALIGN64(le64toh(o->object.size));
995 /* Position might have changed, let's reposition things */
996 r = journal_file_move_to_object(f, -1, p, &o);
1000 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1001 log_error("Tag failed verification at %llu", (unsigned long long) p);
1006 f->hmac_running = false;
1007 last_tag_realtime = rt;
1010 last_tag = p + ALIGN64(le64toh(o->object.size));
1011 last_epoch = le64toh(o->tag.epoch);
1021 if (p == le64toh(f->header->tail_object_offset))
1024 p = p + ALIGN64(le64toh(o->object.size));
1028 log_error("Tail object pointer dead");
1033 if (n_objects != le64toh(f->header->n_objects)) {
1034 log_error("Object number mismatch");
1039 if (n_entries != le64toh(f->header->n_entries)) {
1040 log_error("Entry number mismatch");
1045 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1046 n_data != le64toh(f->header->n_data)) {
1047 log_error("Data number mismatch");
1052 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1053 n_fields != le64toh(f->header->n_fields)) {
1054 log_error("Field number mismatch");
1059 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1060 n_tags != le64toh(f->header->n_tags)) {
1061 log_error("Tag number mismatch");
1066 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1067 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1068 log_error("Entry array number mismatch");
1073 if (n_data_hash_tables != 1) {
1074 log_error("Missing data hash table");
1079 if (n_field_hash_tables != 1) {
1080 log_error("Missing field hash table");
1085 if (!found_main_entry_array) {
1086 log_error("Missing entry array");
1091 if (entry_seqnum_set &&
1092 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1093 log_error("Invalid tail seqnum");
1098 if (entry_monotonic_set &&
1099 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1100 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1101 log_error("Invalid tail monotonic timestamp");
1106 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1107 log_error("Invalid tail realtime timestamp");
1112 /* Second iteration: we follow all objects referenced from the
1113 * two entry points: the object hash table and the entry
1114 * array. We also check that everything referenced (directly
1115 * or indirectly) in the data hash table also exists in the
1116 * entry array, and vice versa. Note that we do not care for
1117 * unreferenced objects. We only care that everything that is
1118 * referenced is consistent. */
1120 r = verify_entry_array(f,
1122 entry_fd, n_entries,
1123 entry_array_fd, n_entry_arrays,
1129 r = verify_hash_table(f,
1131 entry_fd, n_entries,
1132 entry_array_fd, n_entry_arrays,
1141 mmap_cache_close_fd(f->mmap, data_fd);
1142 mmap_cache_close_fd(f->mmap, entry_fd);
1143 mmap_cache_close_fd(f->mmap, entry_array_fd);
1145 close_nointr_nofail(data_fd);
1146 close_nointr_nofail(entry_fd);
1147 close_nointr_nofail(entry_array_fd);
1149 if (first_validated)
1150 *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
1152 *last_validated = last_tag_realtime;
1154 *last_contained = le64toh(f->header->tail_entry_realtime);
1162 log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
1164 (unsigned long long) p,
1165 (unsigned long long) f->last_stat.st_size,
1166 (unsigned long long) (100 * p / f->last_stat.st_size));
1169 mmap_cache_close_fd(f->mmap, data_fd);
1170 close_nointr_nofail(data_fd);
1173 if (entry_fd >= 0) {
1174 mmap_cache_close_fd(f->mmap, entry_fd);
1175 close_nointr_nofail(entry_fd);
1178 if (entry_array_fd >= 0) {
1179 mmap_cache_close_fd(f->mmap, entry_array_fd);
1180 close_nointr_nofail(entry_array_fd);