sd-journal.c revision de2c390731e563db0ee383bfd0073fdbef643ca2
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering This file is part of systemd.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Copyright 2011 Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is free software; you can redistribute it and/or modify it
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering under the terms of the GNU Lesser General Public License as published by
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (at your option) any later version.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is distributed in the hope that it will be useful, but
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Lesser General Public License for more details.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering You should have received a copy of the GNU Lesser General Public License
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic void detach_location(sd_journal *j) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic void reset_location(sd_journal *j) {
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poetteringstatic void init_location(Location *l, JournalFile *f, Object *o) {
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering l->realtime = le64toh(o->entry.realtime);
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering l->monotonic = le64toh(o->entry.monotonic);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering l->xor_hash = le64toh(o->entry.xor_hash);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poetteringstatic void set_location(sd_journal *j, JournalFile *f, Object *o, uint64_t offset) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering init_location(&j->current_location, f, o);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic int match_is_valid(const void *data, size_t size) {
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poettering const char *b, *p;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering for (p = b; p < b + size; p++) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (*p == '=')
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (*p == '_')
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering for (j = 0; j < s && j < t; j++) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (a[j] != b[j])
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (a[j] == '=')
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic Match *match_new(Match *p, MatchType t) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering LIST_PREPEND(Match, matches, p->matches, m);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering LIST_REMOVE(Match, matches, m->parent->matches, m);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic void match_free_if_empty(Match *m) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering_public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering /* level 0: OR term
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * level 1: AND terms
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * level 2: OR terms
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * level 3: concrete matches */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering j->level0 = match_new(NULL, MATCH_OR_TERM);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering j->level1 = match_new(j->level0, MATCH_AND_TERM);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering assert(j->level0->type == MATCH_OR_TERM);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering assert(j->level1->type == MATCH_AND_TERM);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering LIST_FOREACH(matches, l2, j->level1->matches) {
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering /* Exactly the same match already? Then ignore
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering * this addition */
259d2e762041d8d50c2a17bfea90b1a96f6b880bLennart Poettering /* Same field? Then let's add this to this OR term */
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (same_field(data, size, l3->data, l3->size)) {
86b9b8e70d54e79db3ff4f67bbd5280ecfc82537Lennart Poettering add_here = match_new(j->level1, MATCH_OR_TERM);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering_public_ int sd_journal_add_disjunction(sd_journal *j) {
Match *m;
assert(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;
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)
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;