journal-file.c revision fb0951b02ebf51a93acf12721d8857d31ce57ba3
aabc6c87d90e439be4440430ee6439d43cc393edKryštof Tulinger/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
along with systemd; If not, see <http://www.gnu.org/licenses/>.
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stddef.h>
#ifdef HAVE_XATTR
#include "journal-def.h"
#include "journal-file.h"
#include "journal-authenticate.h"
#include "lookup3.h"
#include "compress.h"
#include "fsprg.h"
assert(f);
#ifdef HAVE_GCRYPT
if (f->header) {
if (f->fd >= 0)
if (f->mmap)
#ifdef HAVE_XZ
#ifdef HAVE_GCRYPT
if (f->fss_file)
else if (f->fsprg_state)
if (f->hmac)
free(f);
Header h;
ssize_t k;
assert(f);
zero(h);
h.compatible_flags =
if (template) {
return -errno;
return -EIO;
assert(f);
f->tail_entry_monotonic_valid = true;
assert(f);
return -EBADMSG;
#ifdef HAVE_XZ
return -EPROTONOSUPPORT;
return -EPROTONOSUPPORT;
if (f->writable) {
#ifdef HAVE_GCRYPT
return -EPROTONOSUPPORT;
return -EPROTONOSUPPORT;
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
if ((le64toh(f->header->header_size) + le64toh(f->header->arena_size)) > (uint64_t) f->last_stat.st_size)
return -ENODATA;
if (le64toh(f->header->tail_object_offset) > (le64toh(f->header->header_size) + le64toh(f->header->arena_size)))
return -ENODATA;
return -ENODATA;
return -ENODATA;
if (f->writable) {
return -EHOSTDOWN;
return -EBUSY;
return -ESHUTDOWN;
return -EBUSY;
assert(f);
old_size =
return -E2BIG;
available = 0;
return -E2BIG;
return -errno;
static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
assert(f);
if (size <= 0)
return -EINVAL;
return -EADDRNOTAVAIL;
return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret);
return sizeof(ObjectHeader);
Object *o;
uint64_t s;
unsigned context;
assert(f);
return -EFAULT;
o = (Object*) t;
if (s < sizeof(ObjectHeader))
return -EBADMSG;
return -EBADMSG;
if (s < minimum_header_size(o))
return -EBADMSG;
return -EBADMSG;
if (s > sizeof(ObjectHeader)) {
o = (Object*) t;
*ret = o;
uint64_t r;
assert(f);
if (seqnum) {
*seqnum = r;
int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) {
uint64_t p;
assert(f);
o = (Object*) t;
*ret = o;
*offset = p;
uint64_t s, p;
Object *o;
assert(f);
if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
r = journal_file_append_object(f,
uint64_t s, p;
Object *o;
assert(f);
r = journal_file_append_object(f,
uint64_t s, p;
assert(f);
r = journal_file_move_to(f,
f->data_hash_table = t;
uint64_t s, p;
assert(f);
r = journal_file_move_to(f,
f->field_hash_table = t;
uint64_t p, h;
assert(f);
assert(o);
return -EINVAL;
JournalFile *f,
assert(f);
return -EBADMSG;
Object *o;
goto next;
#ifdef HAVE_XZ
return -EBADMSG;
return -EBADMSG;
if (ret)
*ret = o;
if (offset)
*offset = p;
return -EPROTONOSUPPORT;
if (ret)
*ret = o;
if (offset)
*offset = p;
next:
JournalFile *f,
assert(f);
return journal_file_find_data_object_with_hash(f,
static int journal_file_append_data(
JournalFile *f,
Object *o;
bool compressed = false;
assert(f);
if (ret)
*ret = o;
if (offset)
*offset = p;
#ifdef HAVE_XZ
if (f->compress &&
if (compressed) {
#ifdef HAVE_GCRYPT
if (ret)
*ret = o;
if (offset)
*offset = p;
assert(o);
assert(o);
assert(o);
uint64_t p) {
Object *o;
assert(f);
assert(p > 0);
n = journal_file_entry_array_n_items(o);
ap = a;
if (hidx > n)
#ifdef HAVE_GCRYPT
if (ap == 0)
uint64_t p) {
assert(f);
assert(p > 0);
if (*idx == 0)
le64_t i;
uint64_t p;
assert(f);
assert(o);
return -EINVAL;
return link_entry_into_array_plus_one(f,
offset);
uint64_t n, i;
assert(f);
assert(o);
return -EINVAL;
r = link_entry_into_array(f,
offset);
/* log_debug("=> %s seqnr=%lu n_entries=%lu", f->path, (unsigned long) o->entry.seqnum, (unsigned long) f->header->n_entries); */
f->tail_entry_monotonic_valid = true;
n = journal_file_entry_n_items(o);
static int journal_file_append_entry_internal(
JournalFile *f,
Object *o;
assert(f);
#ifdef HAVE_GCRYPT
if (ret)
*ret = o;
if (offset)
assert(f);
int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqnum, Object **ret, uint64_t *offset) {
assert(f);
if (!f->writable)
return -EPERM;
if (!ts) {
if (f->tail_entry_monotonic_valid &&
return -EINVAL;
#ifdef HAVE_GCRYPT
for (i = 0; i < n_iovec; i++) {
uint64_t p;
Object *o;
uint64_t i,
Object *o;
uint64_t p = 0, a;
assert(f);
a = first;
uint64_t n;
n = journal_file_entry_array_n_items(o);
if (ret)
*ret = o;
if (offset)
*offset = p;
uint64_t i,
Object *o;
assert(f);
if (ret)
*ret = o;
if (offset)
uint64_t n,
bool subtract_one = false;
assert(f);
a = first;
if (right <= 0)
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT) {
left = 0;
subtract_one = true;
i = left;
goto found;
return -EBADMSG;
if (r == TEST_FOUND)
if (r == TEST_RIGHT)
right = i;
subtract_one = true;
goto found;
if (subtract_one && t == 0 && i == 0)
if (subtract_one && i == 0)
p = last_p;
else if (subtract_one)
if (ret)
*ret = o;
if (offset)
*offset = p;
if (idx)
uint64_t n,
bool step_back = false;
Object *o;
assert(f);
if (r == TEST_FOUND)
if (r == TEST_LEFT)
if (r == TEST_RIGHT) {
goto found;
if (r == 0 && step_back)
goto found;
if (r > 0 && idx)
(*idx) ++;
if (ret)
*ret = o;
if (offset)
if (idx)
*idx = 0;
assert(f);
assert(p > 0);
if (p == needle)
return TEST_FOUND;
else if (p < needle)
return TEST_LEFT;
return TEST_RIGHT;
JournalFile *f,
uint64_t p,
return generic_array_bisect(f,
Object *o;
assert(f);
assert(p > 0);
return TEST_FOUND;
return TEST_LEFT;
return TEST_RIGHT;
JournalFile *f,
return generic_array_bisect(f,
Object *o;
assert(f);
assert(p > 0);
return TEST_FOUND;
return TEST_LEFT;
return TEST_RIGHT;
JournalFile *f,
return generic_array_bisect(f,
Object *o;
assert(f);
assert(p > 0);
return TEST_FOUND;
return TEST_LEFT;
return TEST_RIGHT;
JournalFile *f,
Object *o;
assert(f);
return -ENOENT;
return generic_array_bisect_plus_one(f,
JournalFile *f,
uint64_t i, n;
assert(f);
assert(p > 0 || !o);
return -EINVAL;
r = generic_array_bisect(f,
return generic_array_get(f,
JournalFile *f,
uint64_t i, n;
assert(f);
assert(o);
assert(p > 0);
return -EINVAL;
r = generic_array_bisect(f,
if (skip < 0) {
return -EBADMSG;
return generic_array_get(f,
JournalFile *f,
uint64_t n, i;
Object *d;
assert(f);
assert(p > 0 || !o);
return -EINVAL;
return generic_array_get_plus_one(f,
JournalFile *f,
uint64_t p,
Object *d;
assert(f);
return generic_array_bisect_plus_one(f,
JournalFile *f,
Object *o, *d;
uint64_t b, z;
assert(f);
return -ENOENT;
uint64_t p, q;
if (ret)
if (offset)
*offset = q;
JournalFile *f,
Object *d;
assert(f);
return generic_array_bisect_plus_one(f,
JournalFile *f,
Object *d;
assert(f);
return generic_array_bisect_plus_one(f,
Object *o;
uint64_t p;
assert(f);
goto fail;
case OBJECT_UNUSED:
case OBJECT_DATA:
case OBJECT_ENTRY:
case OBJECT_FIELD_HASH_TABLE:
case OBJECT_DATA_HASH_TABLE:
case OBJECT_ENTRY_ARRAY:
case OBJECT_TAG:
fail:
assert(f);
f->path,
100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))));
100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))));
int journal_file_open(
const char *fname,
int flags,
bool compress,
bool seal,
JournalFile *f;
bool newly_created = false;
return -EINVAL;
return -EINVAL;
return -ENOMEM;
#ifdef HAVE_XZ
#ifdef HAVE_GCRYPT
if (mmap_cache)
if (!f->mmap) {
r = -ENOMEM;
goto fail;
if (!f->path) {
r = -ENOMEM;
goto fail;
if (f->fd < 0) {
r = -errno;
goto fail;
r = -errno;
goto fail;
#ifdef HAVE_XATTR
#ifdef HAVE_GCRYPT
if (f->seal) {
r = journal_file_fss_load(f);
f->seal = false;
goto fail;
r = -errno;
goto fail;
newly_created = true;
r = -EIO;
goto fail;
r = -errno;
goto fail;
if (!newly_created) {
r = journal_file_verify_header(f);
goto fail;
#ifdef HAVE_GCRYPT
r = journal_file_fss_load(f);
goto fail;
if (f->writable) {
if (metrics) {
} else if (template)
r = journal_file_refresh_header(f);
goto fail;
#ifdef HAVE_GCRYPT
r = journal_file_hmac_setup(f);
goto fail;
if (newly_created) {
goto fail;
goto fail;
#ifdef HAVE_GCRYPT
r = journal_file_append_first_tag(f);
goto fail;
goto fail;
r = journal_file_map_data_hash_table(f);
goto fail;
*ret = f;
fail:
size_t l;
assert(f);
assert(*f);
old_file = *f;
return -EINVAL;
return -EINVAL;
return -ENOMEM;
free(p);
return -errno;
r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file);
*f = new_file;
const char *fname,
int flags,
bool compress,
bool seal,
size_t l;
random_ull()) < 0)
return -ENOMEM;
free(p);
return -errno;
int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
uint64_t i, n;
assert(o);
assert(p);
return -EPERM;
return -EINVAL;
n = journal_file_entry_n_items(o);
uint64_t l, h;
size_t t;
void *data;
Object *u;
return -EBADMSG;
t = (size_t) l;
if ((uint64_t) t != l)
return -E2BIG;
#ifdef HAVE_XZ
if (!uncompress_blob(o->data.payload, l, &from->compress_buffer, &from->compress_buffer_size, &rsize))
return -EBADMSG;
l = rsize;
return -EPROTONOSUPPORT;
assert(m);
if (fs_size > 0) {
if (fs_size > 0) {
assert(f);
if (from) {
return -ENOENT;
if (to) {
return -ENOENT;
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, usec_t *from, usec_t *to) {
Object *o;
uint64_t p;
assert(f);
if (from) {
if (to) {
r = generic_array_get_plus_one(f,
&o, NULL);
assert(f);
if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) {
log_debug("Data hash table of %s has a fill level at %.1f (%llu of %llu items, %llu file size, %llu bytes per hash table item), suggesting rotation.",
f->path,
100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))),
if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) {
log_debug("Field hash table of %s has a fill level at %.1f (%llu of %llu items), suggesting rotation.",
f->path,
100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))),
if (max_file_usec > 0) {
usec_t t, h;
if (h > 0 && t > h + max_file_usec)