sd-journal.c revision 360af4cf6f18469df97c11af4cd5696e0ca8b3ef
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2011 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <unistd.h>
#include "sd-journal.h"
#include "journal-def.h"
#include "journal-file.h"
#include "hashmap.h"
#include "list.h"
#include "strv.h"
#include "path-util.h"
#include "lookup3.h"
#include "compress.h"
#include "journal-internal.h"
#include "missing.h"
#include "catalog.h"
#include "replace-var.h"
#include "fileio.h"
#define JOURNAL_FILES_MAX 1024
#define REPLACE_VAR_MAX 256
static bool journal_pid_changed(sd_journal *j) {
assert(j);
/* We don't support people creating a journal object and
* keeping it around over a fork(). Let's complain. */
return j->original_pid != getpid();
}
/* We return an error here only if we didn't manage to
memorize the real error. */
static int set_put_error(sd_journal *j, int r) {
int k;
if (r >= 0)
return r;
if (k < 0)
return k;
}
static void detach_location(sd_journal *j) {
Iterator i;
JournalFile *f;
assert(j);
j->current_file = NULL;
j->current_field = 0;
HASHMAP_FOREACH(f, j->files, i)
f->current_offset = 0;
}
static void reset_location(sd_journal *j) {
assert(j);
detach_location(j);
zero(j->current_location);
}
assert(l);
assert(f);
}
assert(j);
assert(f);
assert(o);
j->current_file = f;
j->current_field = 0;
f->last_direction = direction;
f->current_offset = offset;
}
const char *b, *p;
if (size < 2)
return false;
return false;
b = data;
for (p = b; p < b + size; p++) {
if (*p == '=')
return p > b;
if (*p == '_')
continue;
if (*p >= 'A' && *p <= 'Z')
continue;
if (*p >= '0' && *p <= '9')
continue;
return false;
}
return false;
}
size_t j;
for (j = 0; j < s && j < t; j++) {
if (a[j] != b[j])
return false;
if (a[j] == '=')
return true;
}
assert_not_reached("\"=\" not found");
}
Match *m;
if (!m)
return NULL;
m->type = t;
if (p) {
m->parent = p;
}
return m;
}
static void match_free(Match *m) {
assert(m);
while (m->matches)
match_free(m->matches);
if (m->parent)
free(m);
}
static void match_free_if_empty(Match *m) {
if (!m || m->matches)
return;
match_free(m);
}
assert_return(j, -EINVAL);
if (size == 0)
/* level 0: AND term
* level 1: OR terms
* level 2: AND terms
* level 3: OR terms
* level 4: concrete matches */
if (!j->level0) {
if (!j->level0)
return -ENOMEM;
}
if (!j->level1) {
if (!j->level1)
return -ENOMEM;
}
if (!j->level2) {
if (!j->level2)
return -ENOMEM;
}
/* Exactly the same match already? Then ignore
* this addition */
return 0;
/* Same field? Then let's add this to this OR term */
break;
}
}
if (add_here)
break;
}
if (!add_here) {
if (!add_here)
goto fail;
}
if (!m)
goto fail;
if (!m->data)
goto fail;
detach_location(j);
return 0;
fail:
return -ENOMEM;
}
assert_return(j, -EINVAL);
if (!j->level0)
return 0;
if (!j->level1)
return 0;
return 0;
return 0;
}
assert_return(j, -EINVAL);
if (!j->level0)
return 0;
if (!j->level1)
return 0;
if (!j->level2)
return 0;
return 0;
return 0;
}
static char *match_make_string(Match *m) {
char *p, *r;
Match *i;
bool enclose = false;
if (!m)
return strdup("none");
if (m->type == MATCH_DISCRETE)
p = NULL;
char *t, *k;
t = match_make_string(i);
if (!t) {
free(p);
return NULL;
}
if (p) {
free(p);
free(t);
if (!k)
return NULL;
p = k;
enclose = true;
} else
p = t;
}
if (enclose) {
free(p);
return r;
}
return p;
}
char *journal_make_match_string(sd_journal *j) {
assert(j);
return match_make_string(j->level0);
}
if (!j)
return;
if (j->level0)
match_free(j->level0);
detach_location(j);
}
uint64_t a, b;
int r;
/* The mmap cache might invalidate the object from the first
* file if we look at the one from the second file. Hence
* temporarily copy the header of the first one, and look at
* that only. */
if (r < 0)
/* We operate on two different files here, hence we can access
* two objects at the same time, which we normally can't.
*
* If contents and timestamps match, these entries are
* identical, even if the seqnum does not match */
return 0;
/* If this is from the same seqnum source, compare
* seqnums */
if (a < b)
return -1;
if (a > b)
return 1;
/* Wow! This is weird, different data but the same
* seqnums? Something is borked, but let's make the
* best of it and compare by time. */
}
/* If the boot id matches, compare monotonic time */
if (a < b)
return -1;
if (a > b)
return 1;
}
/* Otherwise, compare UTC time */
if (a < b)
return -1;
if (a > b)
return 1;
/* Finally, compare by contents */
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
}
uint64_t a;
assert(l);
if (l->monotonic_set &&
l->realtime_set &&
l->xor_hash_set &&
return 0;
if (l->seqnum_set &&
if (a < l->seqnum)
return -1;
if (a > l->seqnum)
return 1;
}
if (l->monotonic_set &&
if (a < l->monotonic)
return -1;
if (a > l->monotonic)
return 1;
}
if (l->realtime_set) {
if (a < l->realtime)
return -1;
if (a > l->realtime)
return 1;
}
if (l->xor_hash_set) {
if (a < l->xor_hash)
return -1;
if (a > l->xor_hash)
return 1;
}
return 0;
}
static int next_for_match(
sd_journal *j,
Match *m,
JournalFile *f,
int r;
Object *n;
assert(j);
assert(m);
assert(f);
if (m->type == MATCH_DISCRETE) {
if (r <= 0)
return r;
} else if (m->type == MATCH_OR_TERM) {
Match *i;
/* Find the earliest match beyond after_offset */
if (r < 0)
return r;
else if (r > 0) {
}
}
if (np == 0)
return 0;
} else if (m->type == MATCH_AND_TERM) {
Match *i, *last_moved;
/* Always jump to the next matching entry and repeat
* this until we find an offset that matches for all
* matches. */
if (!m->matches)
return 0;
if (r <= 0)
return r;
last_moved = m->matches;
if (r <= 0)
return r;
last_moved = i;
}
}
}
if (r < 0)
return r;
if (ret)
*ret = n;
if (offset)
return 1;
}
static int find_location_for_match(
sd_journal *j,
Match *m,
JournalFile *f,
int r;
assert(j);
assert(m);
assert(f);
if (m->type == MATCH_DISCRETE) {
if (r <= 0)
return r;
/* FIXME: missing: find by monotonic */
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);
if (j->current_location.monotonic_set) {
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 r;
}
if (j->current_location.realtime_set)
return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
} else if (m->type == MATCH_OR_TERM) {
Object *n;
Match *i;
/* Find the earliest match */
if (r < 0)
return r;
else if (r > 0) {
}
}
if (np == 0)
return 0;
if (r < 0)
return r;
if (ret)
*ret = n;
if (offset)
return 1;
} else {
Match *i;
/* First jump to the last match, and then find the
* next one where all matches match */
if (!m->matches)
return 0;
if (r <= 0)
return r;
}
}
}
static int find_location_with_matches(
sd_journal *j,
JournalFile *f,
int r;
assert(j);
assert(f);
if (!j->level0) {
/* No matches is simple */
if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
if (j->current_location.monotonic_set) {
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 r;
}
if (j->current_location.realtime_set)
return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
} else
}
static int next_with_matches(
sd_journal *j,
JournalFile *f,
Object *c;
assert(j);
assert(f);
c = *ret;
/* No matches is easy. We simple advance the file
* pointer by one. */
if (!j->level0)
/* If we have a match then we look for the next matching entry
* with an offset at least one step larger */
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;
int r;
assert(j);
assert(f);
cp = f->current_offset;
if (r < 0)
return r;
if (r <= 0)
return r;
} else {
if (r <= 0)
return r;
}
/* OK, we found the spot, now let's advance until an entry
* that is actually different from what we were previously
* looking at. This is necessary to handle entries which exist
* in two (or more) journal files, and which shall all be
* suppressed but one. */
for (;;) {
bool found;
int k;
k = compare_with_location(f, c, &j->current_location);
if (direction == DIRECTION_DOWN)
found = k > 0;
else
found = k < 0;
} else
found = true;
if (found) {
if (ret)
*ret = c;
if (offset)
return 1;
}
if (r <= 0)
return r;
}
}
uint64_t new_offset = 0;
uint64_t p = 0;
Iterator i;
Object *o;
int r;
assert_return(j, -EINVAL);
HASHMAP_FOREACH(f, j->files, i) {
bool found;
r = next_beyond_location(j, f, direction, &o, &p);
if (r < 0) {
remove_file_real(j, f);
continue;
} else if (r == 0)
continue;
if (!new_file)
found = true;
else {
int k;
}
if (found) {
new_file = f;
new_offset = p;
}
}
if (!new_file)
return 0;
if (r < 0)
return r;
return 1;
}
return real_journal_next(j, DIRECTION_DOWN);
}
return real_journal_next(j, DIRECTION_UP);
}
int c = 0, r;
assert_return(j, -EINVAL);
if (skip == 0) {
/* If this is not a discrete skip, then at least
* resolve the current location */
return real_journal_next(j, direction);
return 0;
}
do {
r = real_journal_next(j, direction);
if (r < 0)
return r;
if (r == 0)
return c;
skip--;
c++;
} while (skip > 0);
return c;
}
}
}
Object *o;
int r;
assert_return(j, -EINVAL);
return -EADDRNOTAVAIL;
r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
if (r < 0)
return r;
return -ENOMEM;
return 0;
}
size_t l;
bool
seqnum_id_set = false,
seqnum_set = false,
boot_id_set = false,
monotonic_set = false,
realtime_set = false,
xor_hash_set = false;
assert_return(j, -EINVAL);
char *item;
int k = 0;
return -EINVAL;
if (!item)
return -ENOMEM;
switch (word[0]) {
case 's':
seqnum_id_set = true;
break;
case 'i':
seqnum_set = true;
k = -EINVAL;
break;
case 'b':
boot_id_set = true;
break;
case 'm':
monotonic_set = true;
k = -EINVAL;
break;
case 't':
realtime_set = true;
k = -EINVAL;
break;
case 'x':
xor_hash_set = true;
k = -EINVAL;
break;
}
if (k < 0)
return k;
}
if ((!seqnum_set || !seqnum_id_set) &&
(!monotonic_set || !boot_id_set) &&
return -EINVAL;
reset_location(j);
if (realtime_set) {
j->current_location.realtime_set = true;
}
if (seqnum_set && seqnum_id_set) {
j->current_location.seqnum_set = true;
}
if (monotonic_set && boot_id_set) {
j->current_location.monotonic_set = true;
}
if (xor_hash_set) {
j->current_location.xor_hash_set = true;
}
return 0;
}
int r;
size_t l;
Object *o;
assert_return(j, -EINVAL);
return -EADDRNOTAVAIL;
r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
if (r < 0)
return r;
unsigned long long ll;
int k = 0;
return -EINVAL;
if (!item)
return -ENOMEM;
switch (word[0]) {
case 's':
if (k < 0)
return k;
return 0;
break;
case 'i':
return -EINVAL;
return 0;
break;
case 'b':
if (k < 0)
return k;
return 0;
break;
case 'm':
return -EINVAL;
return 0;
break;
case 't':
return -EINVAL;
return 0;
break;
case 'x':
return -EINVAL;
return 0;
break;
}
}
return 1;
}
assert_return(j, -EINVAL);
reset_location(j);
j->current_location.monotonic_set = true;
return 0;
}
assert_return(j, -EINVAL);
reset_location(j);
j->current_location.realtime_set = true;
return 0;
}
assert_return(j, -EINVAL);
reset_location(j);
return 0;
}
assert_return(j, -EINVAL);
reset_location(j);
return 0;
}
assert(j);
if (j->on_network)
return;
return;
j->on_network =
}
}
return false;
/* no flags set → every type is OK */
return true;
return true;
if (flags & SD_JOURNAL_CURRENT_USER) {
< (int) sizeof(prefix));
return true;
}
return false;
}
JournalFile *f = NULL;
int r;
assert(j);
return 0;
return set_put_error(j, -ETOOMANYREFS);
}
if (r < 0)
return r;
/* journal_file_dump(f); */
if (r < 0) {
return r;
}
check_network(j, f->fd);
j->current_invalidate_counter ++;
return 0;
}
int r;
assert(j);
if (j->no_new_files ||
return 0;
if (!path)
return -ENOMEM;
r = add_any_file(j, path);
if (r == -ENOENT)
return 0;
return 0;
}
_cleanup_free_ char *path;
JournalFile *f;
assert(j);
if (!path)
return -ENOMEM;
if (!f)
return 0;
remove_file_real(j, f);
return 0;
}
assert(j);
assert(f);
if (j->current_file == f) {
j->current_file = NULL;
j->current_field = 0;
}
if (j->unique_file == f) {
/* Jump to the next unique_file or NULL if that one was last */
j->unique_offset = 0;
if (!j->unique_file)
j->unique_file_lost = true;
}
j->current_invalidate_counter ++;
}
int r;
Directory *m;
assert(j);
if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
sd_id128_get_machine(&mid) < 0 ||
return 0;
if (!path)
return -ENOMEM;
if (!d) {
return 0;
return -errno;
}
if (!m) {
if (!m)
return -ENOMEM;
m->is_root = false;
free(m);
return -ENOMEM;
}
j->current_invalidate_counter ++;
} else if (m->is_root)
return 0;
if (m->wd <= 0 && j->inotify_fd >= 0) {
}
for (;;) {
errno = 0;
r = -errno;
return r;
}
if (!de)
break;
if (r < 0) {
log_debug("Failed to add file %s/%s: %s",
r = set_put_error(j, r);
if (r < 0)
return r;
}
}
}
check_network(j, dirfd(d));
return 0;
}
static int add_root_directory(sd_journal *j, const char *p) {
Directory *m;
int r;
assert(j);
assert(p);
if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
!path_startswith(p, "/run"))
return -EINVAL;
if (j->prefix)
p = strappenda(j->prefix, p);
d = opendir(p);
if (!d)
return -errno;
m = hashmap_get(j->directories_by_path, p);
if (!m) {
if (!m)
return -ENOMEM;
m->is_root = true;
if (!m->path) {
free(m);
return -ENOMEM;
}
free(m);
return -ENOMEM;
}
j->current_invalidate_counter ++;
} else if (!m->is_root)
return 0;
if (m->wd <= 0 && j->inotify_fd >= 0) {
}
if (j->no_new_files)
return 0;
for (;;) {
errno = 0;
r = -errno;
return r;
}
if (!de)
break;
if (r < 0) {
log_debug("Failed to add file %s/%s: %s",
r = set_put_error(j, r);
if (r < 0)
return r;
}
if (r < 0)
}
}
check_network(j, dirfd(d));
return 0;
}
assert(j);
if (d->wd > 0) {
if (j->inotify_fd >= 0)
}
if (d->is_root)
else
free(d);
return 0;
}
static int add_search_paths(sd_journal *j) {
int r;
const char search_paths[] =
const char *p;
assert(j);
/* We ignore most errors here, since the idea is to only open
* what's actually accessible, and ignore the rest. */
NULSTR_FOREACH(p, search_paths) {
r = add_root_directory(j, p);
if (r < 0 && r != -ENOENT) {
r = set_put_error(j, r);
if (r < 0)
return r;
}
}
return 0;
}
static int add_current_paths(sd_journal *j) {
Iterator i;
JournalFile *f;
assert(j);
assert(j->no_new_files);
/* Simply adds all directories for files we have open as
* "root" directories. We don't expect errors here, so we
* treat them as fatal. */
HASHMAP_FOREACH(f, j->files, i) {
_cleanup_free_ char *dir;
int r;
if (!dir)
return -ENOMEM;
r = add_root_directory(j, dir);
if (r < 0) {
set_put_error(j, r);
return r;
}
}
return 0;
}
static int allocate_inotify(sd_journal *j) {
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;
}
return 0;
}
sd_journal *j;
if (!j)
return NULL;
j->original_pid = getpid();
j->inotify_fd = -1;
if (path) {
if (!j->path)
goto fail;
}
j->mmap = mmap_cache_new();
goto fail;
return j;
fail:
sd_journal_close(j);
return NULL;
}
sd_journal *j;
int r;
assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL);
if (!j)
return -ENOMEM;
r = add_search_paths(j);
if (r < 0)
goto fail;
*ret = j;
return 0;
fail:
sd_journal_close(j);
return r;
}
sd_journal *j;
char *p;
int r;
if (r == -ENOENT)
return -EHOSTDOWN;
if (r < 0)
return r;
if (!root)
return -ENODATA;
return -EIO;
if (!j)
return -ENOMEM;
r = add_search_paths(j);
if (r < 0)
goto fail;
*ret = j;
return 0;
fail:
sd_journal_close(j);
return r;
}
sd_journal *j;
int r;
if (!j)
return -ENOMEM;
r = add_root_directory(j, path);
if (r < 0) {
set_put_error(j, r);
goto fail;
}
*ret = j;
return 0;
fail:
sd_journal_close(j);
return r;
}
sd_journal *j;
const char **path;
int r;
if (!j)
return -ENOMEM;
r = add_any_file(j, *path);
if (r < 0) {
goto fail;
}
}
j->no_new_files = true;
*ret = j;
return 0;
fail:
sd_journal_close(j);
return r;
}
Directory *d;
JournalFile *f;
if (!j)
return;
while ((f = hashmap_steal_first(j->files)))
hashmap_free(j->files);
while ((d = hashmap_first(j->directories_by_path)))
remove_directory(j, d);
while ((d = hashmap_first(j->directories_by_wd)))
remove_directory(j, d);
safe_close(j->inotify_fd);
if (j->mmap) {
log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
mmap_cache_unref(j->mmap);
}
free(j->unique_field);
free(j);
}
Object *o;
JournalFile *f;
int r;
assert_return(j, -EINVAL);
f = j->current_file;
if (!f)
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
if (r < 0)
return r;
return 0;
}
Object *o;
JournalFile *f;
int r;
assert_return(j, -EINVAL);
f = j->current_file;
if (!f)
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
if (r < 0)
return r;
if (ret_boot_id)
else {
r = sd_id128_get_boot(&id);
if (r < 0)
return r;
return -ESTALE;
}
if (ret)
return 0;
}
static bool field_is_valid(const char *field) {
const char *p;
return false;
return false;
for (p = field; *p; p++) {
if (*p == '_')
continue;
if (*p >= 'A' && *p <= 'Z')
continue;
if (*p >= '0' && *p <= '9')
continue;
return false;
}
return true;
}
_public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
JournalFile *f;
uint64_t i, n;
int r;
Object *o;
assert_return(j, -EINVAL);
f = j->current_file;
if (!f)
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
if (r < 0)
return r;
n = journal_file_entry_n_items(o);
for (i = 0; i < n; i++) {
uint64_t p, l;
size_t t;
int compression;
r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
if (r < 0)
return r;
return -EBADMSG;
if (compression) {
&f->compress_buffer, &f->compress_buffer_size,
j->data_threshold);
if (r < 0)
return r;
*data = f->compress_buffer;
return 0;
}
#else
return -EPROTONOSUPPORT;
#endif
} else if (l >= field_length+1 &&
t = (size_t) l;
if ((uint64_t) t != l)
return -E2BIG;
*size = t;
return 0;
}
if (r < 0)
return r;
}
return -ENOENT;
}
size_t t;
uint64_t l;
int compression;
t = (size_t) l;
/* We can't read objects larger than 4G on a 32bit machine */
if ((uint64_t) t != l)
return -E2BIG;
if (compression) {
int r;
if (r < 0)
return r;
*data = f->compress_buffer;
#else
return -EPROTONOSUPPORT;
#endif
} else {
*size = t;
}
return 0;
}
JournalFile *f;
uint64_t p, n;
int r;
Object *o;
assert_return(j, -EINVAL);
f = j->current_file;
if (!f)
return -EADDRNOTAVAIL;
if (f->current_offset <= 0)
return -EADDRNOTAVAIL;
if (r < 0)
return r;
n = journal_file_entry_n_items(o);
if (j->current_field >= n)
return 0;
r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
if (r < 0)
return r;
return -EBADMSG;
if (r < 0)
return r;
j->current_field ++;
return 1;
}
if (!j)
return;
j->current_field = 0;
}
int r;
assert_return(j, -EINVAL);
if (j->inotify_fd >= 0)
return j->inotify_fd;
r = allocate_inotify(j);
if (r < 0)
return r;
/* Iterate through all dirs again, to add them to the
* inotify */
if (j->no_new_files)
r = add_current_paths(j);
else if (j->path)
r = add_root_directory(j, j->path);
else
r = add_search_paths(j);
if (r < 0)
return r;
return j->inotify_fd;
}
int fd;
assert_return(j, -EINVAL);
fd = sd_journal_get_fd(j);
if (fd < 0)
return fd;
return POLLIN;
}
int fd;
assert_return(j, -EINVAL);
fd = sd_journal_get_fd(j);
if (fd < 0)
return fd;
if (!j->on_network) {
return 0;
}
/* If we are on the network we need to regularly check for
* changes manually */
return 1;
}
Directory *d;
int r;
assert(j);
assert(e);
/* Is this a subdirectory we watch? */
if (d) {
/* Event for a journal file */
if (r < 0) {
log_debug("Failed to add file %s/%s: %s",
set_put_error(j, r);
}
if (r < 0)
}
/* Event for a subdirectory */
r = remove_directory(j, d);
if (r < 0)
}
} else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
/* Event for root directory */
if (r < 0)
}
}
return;
}
if (e->mask & IN_IGNORED)
return;
log_warning("Unknown inotify event.");
}
static int determine_change(sd_journal *j) {
bool b;
assert(j);
b = j->current_invalidate_counter != j->last_invalidate_counter;
return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
}
bool got_something = false;
assert_return(j, -EINVAL);
for (;;) {
struct inotify_event *e;
ssize_t l;
if (l < 0) {
return -errno;
}
got_something = true;
e = (struct inotify_event*) buffer;
while (l > 0) {
process_inotify_event(j, e);
l -= step;
}
}
}
int r;
uint64_t t;
assert_return(j, -EINVAL);
if (j->inotify_fd < 0) {
/* This is the first invocation, hence create the
* inotify watch */
r = sd_journal_get_fd(j);
if (r < 0)
return r;
/* The journal might have changed since the context
* object was created and we weren't watching before,
* hence don't wait for anything, and return
* immediately. */
return determine_change(j);
}
r = sd_journal_get_timeout(j, &t);
if (r < 0)
return r;
if (t != (uint64_t) -1) {
usec_t n;
n = now(CLOCK_MONOTONIC);
t = t > n ? t - n : 0;
timeout_usec = t;
}
do {
} while (r == -EINTR);
if (r < 0)
return r;
return sd_journal_process(j);
}
Iterator i;
JournalFile *f;
bool first = true;
int r;
assert_return(j, -EINVAL);
HASHMAP_FOREACH(f, j->files, i) {
r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
if (r == -ENOENT)
continue;
if (r < 0)
return r;
if (r == 0)
continue;
if (first) {
tmax = t;
first = false;
} else {
}
}
if (from)
if (to)
return first ? 0 : 1;
}
_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 found = false;
int r;
assert_return(j, -EINVAL);
HASHMAP_FOREACH(f, j->files, i) {
if (r == -ENOENT)
continue;
if (r < 0)
return r;
if (r == 0)
continue;
if (found) {
if (from)
if (to)
} else {
if (from)
if (to)
*to = t;
found = true;
}
}
return found;
}
void journal_print_header(sd_journal *j) {
Iterator i;
JournalFile *f;
bool newline = false;
assert(j);
HASHMAP_FOREACH(f, j->files, i) {
if (newline)
putchar('\n');
else
newline = true;
}
}
Iterator i;
JournalFile *f;
assert_return(j, -EINVAL);
HASHMAP_FOREACH(f, j->files, i) {
return -errno;
}
return 0;
}
char *f;
assert_return(j, -EINVAL);
if (!f)
return -ENOMEM;
free(j->unique_field);
j->unique_field = f;
j->unique_file = NULL;
j->unique_offset = 0;
j->unique_file_lost = false;
return 0;
}
size_t k;
assert_return(j, -EINVAL);
assert_return(l, -EINVAL);
k = strlen(j->unique_field);
if (!j->unique_file) {
if (j->unique_file_lost)
return 0;
if (!j->unique_file)
return 0;
j->unique_offset = 0;
}
for (;;) {
Iterator i;
Object *o;
const void *odata;
bool found;
int r;
/* Proceed to next data object in the field's linked list */
if (j->unique_offset == 0) {
if (r < 0)
return r;
} else {
if (r < 0)
return r;
}
/* We reached the end of the list? Then start again, with the next file */
if (j->unique_offset == 0) {
if (!j->unique_file)
return 0;
continue;
}
/* We do not use the type context here, but 0 instead,
* so that we can look at this data object at the same
* time as one on another file */
if (r < 0)
return r;
/* Let's do the type check by hand, since we used 0 context above. */
return -EBADMSG;
}
if (r < 0)
return r;
if (r < 0)
return r;
/* Check if we have at least the field name and "=". */
if (ol <= k) {
ol, k + 1);
return -EBADMSG;
}
j->unique_field);
return -EBADMSG;
}
/* OK, now let's see if we already returned this data
* object by checking if it exists in the earlier
* traversed files. */
found = false;
if (of == j->unique_file)
break;
/* Skip this file it didn't have any fields
* indexed */
continue;
if (r < 0)
return r;
if (r > 0)
found = true;
}
if (found)
continue;
if (r < 0)
return r;
if (r < 0)
return r;
return 1;
}
}
if (!j)
return;
j->unique_file = NULL;
j->unique_offset = 0;
j->unique_file_lost = false;
}
assert_return(j, -EINVAL);
return !j->on_network;
}
sd_journal *j = userdata;
const void *data;
int r;
assert(j);
if (r < 0 ||
}
const void *data;
char *t;
int r;
assert_return(j, -EINVAL);
if (r < 0)
return r;
if (!cid)
return -ENOMEM;
if (r < 0)
return r;
if (r < 0)
return r;
if (!t)
return -ENOMEM;
*ret = t;
return 0;
}
}
assert_return(j, -EINVAL);
j->data_threshold = sz;
return 0;
}
assert_return(j, -EINVAL);
*sz = j->data_threshold;
return 0;
}