sd-journal.c revision b4e5f9201706cbd0c83645175649119e87c2c91c
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen This file is part of systemd.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Copyright 2011 Lennart Poettering
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is free software; you can redistribute it and/or modify it
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen under the terms of the GNU General Public License as published by
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen the Free Software Foundation; either version 2 of the License, or
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen (at your option) any later version.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is distributed in the hope that it will be useful, but
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen General Public License for more details.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen You should have received a copy of the GNU General Public License
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void init_location(Location *l, JournalFile *f, Object *o) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void set_location(sd_journal *j, JournalFile *f, Object *o, uint64_t offset) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int same_field(const void *_a, size_t s, const void *_b, size_t t) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen bool a_good = false, b_good = false, different = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen for (j = 0; j < s && j < t; j++) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (a[j] == '=')
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (b[j] == '=')
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (a[j] != b[j])
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen_public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen else if (r > 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen /* Matches for the same fields we order adjacent to each
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen LIST_INSERT_AFTER(Match, matches, j->matches, after, m);
63348d13fae61fefcb29133bfae8371b33cf4b6dTom Gundersen_public_ void sd_journal_flush_matches(sd_journal *j) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int compare_order(JournalFile *af, Object *ao,
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen /* We operate on two different files here, hence we can access
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen * two objects at the same time, which we normally can't.
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen * If contents and timestamps match, these entries are
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen * identical, even if the seqnum does not match */
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) &&
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) {
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen /* If this is from the same seqnum source, compare
962b0647298b601548b049893931d2477f06ab57Tom Gundersen /* Wow! This is weird, different data but the same
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen * seqnums? Something is borked, but let's make the
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen * best of it and compare by time. */
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen /* If the boot id matches compare monotonic time */
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen /* Otherwise compare UTC time */
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen /* Finally, compare by contents */
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersenstatic int compare_with_location(JournalFile *af, Object *ao, Location *l) {
uint64_t a;
assert(l);
if (l->monotonic_set &&
l->realtime_set &&
l->xor_hash_set &&
if (l->seqnum_set &&
if (a < l->seqnum)
if (a > l->seqnum)
if (l->monotonic_set &&
if (a < l->monotonic)
if (a > l->monotonic)
if (l->realtime_set) {
if (a < l->realtime)
if (a > l->realtime)
if (l->xor_hash_set) {
if (a < l->xor_hash)
if (a > l->xor_hash)
static int find_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
uint64_t p = 0;
assert(j);
if (!j->matches) {
r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, &o, &p);
r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, &o, &p);
return r == -ENOENT ? 0 : r;
Object *c, *d;
r = journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, &c, &cp);
r = journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, &c, &cp);
if (!term_match) {
term_match = m;
to = c;
if (!to ||
to = c;
if (!to)
o = to;
p = tp;
term_match = m;
to = c;
tp = 0;
if (!to)
o = to;
p = tp;
if (ret)
*ret = o;
if (offset)
*offset = p;
static int next_with_matches(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
Object *c;
assert(j);
assert(f);
c = *ret;
if (!j->matches) {
if (ret)
*ret = c;
if (offset)
n = journal_file_entry_n_items(c);
np = 0;
uint64_t q, k;
if (!term_match) {
term_match = m;
term_result = false;
if (!term_result)
found = false;
term_match = m;
term_result = false;
term_result = true;
r = journal_file_next_entry_for_data(f, c, cp, le64toh(c->entry.items[k].object_offset), direction, &qo, &q);
if (q > np) {
np = q;
np = q;
found = false;
if (found) {
if (ret)
*ret = c;
if (offset)
if (np == 0)
c = npo;
static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
Object *c;
int compare_value, r;
assert(j);
assert(f);
if (f->current_offset > 0) {
compare_value = 0;
bool found;
found = true;
if (found) {
if (ret)
*ret = c;
if (offset)
Iterator i;
return -EINVAL;
Object *o;
uint64_t p;
bool found;
if (!new_current)
found = true;
found = k < 0;
found = k > 0;
if (found) {
new_current = f;
new_entry = o;
new_offset = p;
if (!new_current)
return -EINVAL;
while (skip > 0) {
r = sd_journal_next(j);
skip--;
return -EINVAL;
while (skip > 0) {
r = sd_journal_previous(j);
skip--;
Object *o;
return -EINVAL;
if (!cursor)
return -EINVAL;
return -EADDRNOTAVAIL;
r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
return -ENOMEM;
size_t l;
char *state;
seqnum_id_set = false,
seqnum_set = false,
boot_id_set = false,
monotonic_set = false,
realtime_set = false,
xor_hash_set = false;
return -EINVAL;
if (!cursor)
return -EINVAL;
char *item;
return -EINVAL;
if (!item)
return -ENOMEM;
seqnum_id_set = true;
seqnum_set = true;
k = -EINVAL;
boot_id_set = true;
monotonic_set = true;
k = -EINVAL;
realtime_set = true;
k = -EINVAL;
xor_hash_set = true;
k = -EINVAL;
return -EINVAL;
reset_location(j);
if (realtime_set) {
if (xor_hash_set) {
return -EINVAL;
reset_location(j);
return -EINVAL;
reset_location(j);
return -EINVAL;
reset_location(j);
return -EINVAL;
reset_location(j);
char *fn;
JournalFile *f;
assert(j);
if (dir)
if (!fn)
return -ENOMEM;
char *fn;
JournalFile *f;
assert(j);
if (dir)
if (!fn)
return -ENOMEM;
char *fn;
DIR *d;
int wd;
assert(j);
if (!fn)
return -ENOMEM;
return -errno;
if (wd > 0) {
if (r != 0 || !de)
closedir(d);
assert(j);
if (j->inotify_fd >= 0)
free(p);
int wd;
assert(j);
assert(p);
if (wd <= 0)
k = strdup(p);
free(k);
assert(j);
if (j->inotify_fd >= 0)
free(p);
sd_journal *j;
const char search_paths[] =
if (!ret)
return -EINVAL;
return -EINVAL;
return -ENOMEM;
if (j->inotify_fd < 0) {
r = -errno;
goto fail;
if (!j->files) {
r = -ENOMEM;
goto fail;
r = -ENOMEM;
goto fail;
DIR *d;
d = opendir(p);
add_root_wd(j, p);
if (r != 0 || !de)
closedir(d);
*ret = j;
fail:
sd_journal_close(j);
if (j->inotify_wd_dirs) {
if (j->inotify_wd_roots) {
if (j->files) {
JournalFile *f;
if (j->inotify_fd >= 0)
free(j);
Object *o;
JournalFile *f;
return -EINVAL;
if (!ret)
return -EINVAL;
f = j->current_file;
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
Object *o;
JournalFile *f;
return -EINVAL;
if (!ret)
return -EINVAL;
f = j->current_file;
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
if (ret_boot_id)
return -ENOENT;
_public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
JournalFile *f;
uint64_t i, n;
Object *o;
return -EINVAL;
if (!field)
return -EINVAL;
if (!data)
return -EINVAL;
if (!size)
return -EINVAL;
return -EINVAL;
f = j->current_file;
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
n = journal_file_entry_n_items(o);
size_t t;
return -EBADMSG;
#ifdef HAVE_XZ
return -EBADMSG;
return -EPROTONOSUPPORT;
t = (size_t) l;
if ((uint64_t) t != l)
return -E2BIG;
*size = t;
return -ENOENT;
JournalFile *f;
Object *o;
size_t t;
return -EINVAL;
if (!data)
return -EINVAL;
if (!size)
return -EINVAL;
f = j->current_file;
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
n = journal_file_entry_n_items(o);
if (j->current_field >= n)
return -EBADMSG;
t = (size_t) l;
if ((uint64_t) t != l)
return -E2BIG;
#ifdef HAVE_XZ
return -EBADMSG;
return -EPROTONOSUPPORT;
*size = t;
j->current_field ++;
j->current_field = 0;
return -EINVAL;
return j->inotify_fd;
assert(j);
assert(e);
} else if (e->len == 0) {
return -EINVAL;
struct inotify_event *e;
ssize_t l;
return -errno;
process_inotify_event(j, e);
l -= step;
return -EINVAL;
if (!field)
return -EINVAL;
return -ENOTSUP;
return -EINVAL;
if (!data)
return -EINVAL;
return -EINVAL;
return -ENOTSUP;