sd-journal.c revision f284860764076e2a1f0b34eb4c681bb2762f7889
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen This file is part of systemd.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen Copyright 2011 Lennart Poettering
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen systemd is free software; you can redistribute it and/or modify it
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen under the terms of the GNU Lesser General Public License as published by
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen (at your option) any later version.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen systemd is distributed in the hope that it will be useful, but
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen Lesser General Public License for more details.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen You should have received a copy of the GNU Lesser General Public License
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenstatic void init_location(Location *l, JournalFile *f, Object *o) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenstatic void set_location(sd_journal *j, JournalFile *f, Object *o, uint64_t offset) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenstatic int match_is_valid(const void *data, size_t size) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen const char *b, *p;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return false;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return false;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen for (p = b; p < b + size; p++) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (*p == '=')
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return p > b;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (*p == '_')
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return false;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return false;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenstatic bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen for (j = 0; j < s && j < t; j++) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (a[j] != b[j])
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return false;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (a[j] == '=')
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenstatic Match *match_new(Match *p, MatchType t) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen LIST_REMOVE(Match, matches, m->parent->matches, m);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen_public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* level 0: OR term
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen * level 1: AND terms
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen * level 2: OR terms
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen * level 3: concrete matches */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen j->level1 = match_new(j->level0, MATCH_AND_TERM);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen LIST_FOREACH(matches, l2, j->level1->matches) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* Exactly the same match already? Then ignore
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen * this addition */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* Same field? Then let's add this to this OR term */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (same_field(data, size, l3->data, l3->size)) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen add_here = match_new(j->level1, MATCH_OR_TERM);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen_public_ int sd_journal_add_disjunction(sd_journal *j) {
if (!j->level0)
if (!j->level1)
return -ENOMEM;
j->level1 = m;
Match *i;
bool enclose = false;
p = NULL;
t = match_make_string(i);
free(p);
return NULL;
free(p);
free(t);
return NULL;
enclose = true;
free(p);
if (enclose) {
free(p);
assert(j);
if (j->level0)
detach_location(j);
uint64_t a, b;
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 next_for_match(
sd_journal *j,
Match *m,
JournalFile *f,
Object *n;
assert(j);
assert(m);
assert(f);
Match *i;
Match *i;
bool continue_looking;
if (!m->matches)
np = 0;
continue_looking = false;
if (np == 0)
continue_looking = true;
} while (continue_looking);
if (np == 0)
if (ret)
*ret = n;
if (offset)
static int find_location_for_match(
sd_journal *j,
Match *m,
JournalFile *f,
assert(j);
assert(m);
assert(f);
if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
if (r != -ENOENT)
return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
Object *n;
Match *i;
if (np == 0)
if (ret)
*ret = n;
if (offset)
Match *i;
if (!m->matches)
static int find_location_with_matches(
sd_journal *j,
JournalFile *f,
assert(j);
assert(f);
if (!j->level0) {
if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
if (r != -ENOENT)
return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
static int next_with_matches(
sd_journal *j,
JournalFile *f,
Object *c;
assert(j);
assert(f);
c = *ret;
if (!j->level0)
return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset);
static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
Object *c;
assert(j);
assert(f);
if (f->current_offset > 0) {
bool found;
found = k > 0;
found = k < 0;
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;
if (skip == 0) {
skip--;
} while (skip > 0);
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 *path;
JournalFile *f;
assert(j);
if (!path)
return -ENOMEM;
j->current_invalidate_counter ++;
char *path;
JournalFile *f;
assert(j);
if (!path)
return -ENOMEM;
j->current_invalidate_counter ++;
char *path;
DIR *d;
Directory *m;
assert(j);
if (!path)
return -ENOMEM;
return -errno;
closedir(d);
return -ENOMEM;
m->is_root = false;
closedir(d);
free(m);
return -ENOMEM;
j->current_invalidate_counter ++;
} else if (m->is_root) {
closedir(d);
if (r != 0 || !de)
closedir(d);
DIR *d;
Directory *m;
assert(j);
assert(p);
return -EINVAL;
d = opendir(p);
return -errno;
closedir(d);
return -ENOMEM;
m->is_root = true;
if (!m->path) {
closedir(d);
free(m);
return -ENOMEM;
closedir(d);
free(m);
return -ENOMEM;
j->current_invalidate_counter ++;
} else if (!m->is_root) {
closedir(d);
if (r != 0 || !de)
closedir(d);
assert(j);
if (d->wd > 0) {
if (j->inotify_fd >= 0)
if (d->is_root)
free(d);
const char search_paths[] =
assert(j);
add_root_directory(j, p);
assert(j);
if (j->inotify_fd < 0) {
if (j->inotify_fd < 0)
return -errno;
if (!j->directories_by_wd) {
if (!j->directories_by_wd)
return -ENOMEM;
sd_journal *j;
return NULL;
if (path) {
if (!j->path) {
free(j);
return NULL;
if (!j->files) {
free(j);
return NULL;
if (!j->directories_by_path) {
free(j);
return NULL;
if (!j->mmap) {
free(j);
return NULL;
sd_journal *j;
if (!ret)
return -EINVAL;
return -EINVAL;
return -ENOMEM;
r = add_search_paths(j);
goto fail;
*ret = j;
fail:
sd_journal_close(j);
sd_journal *j;
if (!ret)
return -EINVAL;
return -EINVAL;
if (flags != 0)
return -EINVAL;
return -ENOMEM;
goto fail;
*ret = j;
fail:
sd_journal_close(j);
Directory *d;
JournalFile *f;
remove_directory(j, d);
remove_directory(j, d);
if (j->inotify_fd >= 0)
if (j->mmap)
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;
f = j->current_file;
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
if (ret_boot_id)
return -ESTALE;
if (ret)
for (p = field; *p; p++) {
_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);
uint64_t p, l;
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;
uint64_t p, l, n;
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;
if (j->inotify_fd >= 0)
return j->inotify_fd;
r = allocate_inotify(j);
if (j->path)
r = add_search_paths(j);
return j->inotify_fd;
Directory *d;
assert(j);
assert(e);
r = remove_directory(j, d);
} else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
assert(j);
bool got_something = false;
return -EINVAL;
struct inotify_event *e;
ssize_t l;
return -errno;
got_something = true;
process_inotify_event(j, e);
l -= step;
return determine_change(j);
assert(j);
if (j->inotify_fd < 0) {
r = sd_journal_get_fd(j);
return determine_change(j);
} while (r == -EINTR);
return sd_journal_process(j);
Iterator i;
JournalFile *f;
bool first = true;
return -EINVAL;
return -EINVAL;
if (r == -ENOENT)
if (first) {
if (from)
if (to)
*to = t;
first = false;
if (from)
if (to)
_public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
Iterator i;
JournalFile *f;
bool first = true;
return -EINVAL;
return -EINVAL;
if (r == -ENOENT)
if (first) {
if (from)
if (to)
*to = t;
first = false;
if (from)
if (to)
Iterator i;
JournalFile *f;
bool newline = false;
assert(j);
if (newline)
newline = true;