X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fsd-journal.c;h=fa04bfdfc87eb15c6f885ebdffc845ec3b20f633;hp=16ed4239cee2a1e716d15f7319e5d8c2999b1693;hb=99613ec5d7f0c6e30801457f60c2cab7d8e50d8d;hpb=5e6870eab5aa00675e4cd2f914fd1c25642fc964 diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 16ed4239c..fa04bfdfc 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "sd-journal.h" #include "journal-def.h" @@ -35,9 +37,18 @@ #include "lookup3.h" #include "compress.h" #include "journal-internal.h" +#include "missing.h" +#include "catalog.h" +#include "replace-var.h" #define JOURNAL_FILES_MAX 1024 +#define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC) + +#define REPLACE_VAR_MAX 256 + +#define DEFAULT_DATA_THRESHOLD (64*1024) + static void detach_location(sd_journal *j) { Iterator i; JournalFile *f; @@ -947,7 +958,7 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) { (unsigned long long) le64toh(o->entry.xor_hash)) < 0) return -ENOMEM; - return 1; + return 0; } _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { @@ -1184,6 +1195,25 @@ _public_ int sd_journal_seek_tail(sd_journal *j) { return 0; } +static void check_network(sd_journal *j, int fd) { + struct statfs sfs; + + assert(j); + + if (j->on_network) + return; + + if (fstatfs(fd, &sfs) < 0) + return; + + j->on_network = + (long)sfs.f_type == (long)CIFS_MAGIC_NUMBER || + sfs.f_type == CODA_SUPER_MAGIC || + sfs.f_type == NCP_SUPER_MAGIC || + sfs.f_type == NFS_SUPER_MAGIC || + sfs.f_type == SMB_SUPER_MAGIC; +} + static int add_file(sd_journal *j, const char *prefix, const char *filename) { char *path; int r; @@ -1233,6 +1263,8 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { return r; } + check_network(j, f->fd); + j->current_invalidate_counter ++; log_debug("File %s got added.", f->path); @@ -1261,6 +1293,16 @@ static int remove_file(sd_journal *j, const char *prefix, const char *filename) log_debug("File %s got removed.", f->path); + if (j->current_file == f) { + j->current_file = NULL; + j->current_field = 0; + } + + if (j->unique_file == f) { + j->unique_file = NULL; + j->unique_offset = 0; + } + journal_file_close(f); j->current_invalidate_counter ++; @@ -1279,10 +1321,12 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) assert(prefix); assert(dirname); + log_debug("Considering %s/%s.", prefix, dirname); + if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && (sd_id128_from_string(dirname, &id) < 0 || sd_id128_get_machine(&mid) < 0 || - !sd_id128_equal(id, mid))) + !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run")))) return 0; path = strjoin(prefix, "/", dirname, NULL); @@ -1356,6 +1400,8 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) } } + check_network(j, dirfd(d)); + closedir(d); return 0; @@ -1443,6 +1489,8 @@ static int add_root_directory(sd_journal *j, const char *p) { } } + check_network(j, dirfd(d)); + closedir(d); return 0; @@ -1516,6 +1564,7 @@ static sd_journal *journal_new(int flags, const char *path) { j->inotify_fd = -1; j->flags = flags; + j->data_threshold = DEFAULT_DATA_THRESHOLD; if (path) { j->path = strdup(path); @@ -1641,6 +1690,7 @@ _public_ void sd_journal_close(sd_journal *j) { mmap_cache_unref(j->mmap); free(j->path); + free(j->unique_field); free(j); } @@ -1793,7 +1843,8 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** uint64_t rsize; if (!uncompress_blob(o->data.payload, l, - &f->compress_buffer, &f->compress_buffer_size, &rsize)) + &f->compress_buffer, &f->compress_buffer_size, &rsize, + j->data_threshold)) return -EBADMSG; *data = f->compress_buffer; @@ -1828,13 +1879,43 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** return -ENOENT; } +static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) { + size_t t; + uint64_t l; + + l = le64toh(o->object.size) - offsetof(Object, data.payload); + t = (size_t) l; + + /* We can't read objects larger than 4G on a 32bit machine */ + if ((uint64_t) t != l) + return -E2BIG; + + if (o->object.flags & OBJECT_COMPRESSED) { +#ifdef HAVE_XZ + uint64_t rsize; + + if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold)) + return -EBADMSG; + + *data = f->compress_buffer; + *size = (size_t) rsize; +#else + return -EPROTONOSUPPORT; +#endif + } else { + *data = o->data.payload; + *size = t; + } + + return 0; +} + _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) { JournalFile *f; - uint64_t p, l, n; + uint64_t p, n; le64_t le_hash; int r; Object *o; - size_t t; if (!j) return -EINVAL; @@ -1867,29 +1948,9 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t if (le_hash != o->data.hash) return -EBADMSG; - l = le64toh(o->object.size) - offsetof(Object, data.payload); - t = (size_t) l; - - /* We can't read objects larger than 4G on a 32bit machine */ - if ((uint64_t) t != l) - return -E2BIG; - - if (o->object.flags & OBJECT_COMPRESSED) { -#ifdef HAVE_XZ - uint64_t rsize; - - if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize)) - return -EBADMSG; - - *data = f->compress_buffer; - *size = (size_t) rsize; -#else - return -EPROTONOSUPPORT; -#endif - } else { - *data = o->data.payload; - *size = t; - } + r = return_data(j, f, o, data, size); + if (r < 0) + return r; j->current_field ++; @@ -2058,6 +2119,14 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { return determine_change(j); } + if (j->on_network) { + /* If we are on the network we need to regularly check + * for changes manually */ + + if (timeout_usec == (uint64_t) -1 || timeout_usec > JOURNAL_FILES_RECHECK_USEC) + timeout_usec = JOURNAL_FILES_RECHECK_USEC; + } + do { r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec); } while (r == -EINTR); @@ -2100,7 +2169,7 @@ _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, if (from) *from = MIN(fr, *from); if (to) - *to = MIN(t, *to); + *to = MAX(t, *to); } } @@ -2139,7 +2208,7 @@ _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot if (from) *from = MIN(fr, *from); if (to) - *to = MIN(t, *to); + *to = MAX(t, *to); } } @@ -2186,27 +2255,228 @@ _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) { return 0; } -/* _public_ int sd_journal_query_unique(sd_journal *j, const char *field) { */ -/* if (!j) */ -/* return -EINVAL; */ -/* if (!field) */ -/* return -EINVAL; */ +_public_ int sd_journal_query_unique(sd_journal *j, const char *field) { + char *f; -/* return -ENOTSUP; */ -/* } */ + if (!j) + return -EINVAL; + if (isempty(field)) + return -EINVAL; + if (!field_is_valid(field)) + return -EINVAL; + + f = strdup(field); + if (!f) + return -ENOMEM; + + free(j->unique_field); + j->unique_field = f; + j->unique_file = NULL; + j->unique_offset = 0; + + return 0; +} -/* _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) { */ -/* if (!j) */ -/* return -EINVAL; */ -/* if (!data) */ -/* return -EINVAL; */ -/* if (!l) */ -/* return -EINVAL; */ +_public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) { + Object *o; + size_t k; + int r; -/* return -ENOTSUP; */ -/* } */ + if (!j) + return -EINVAL; + if (!data) + return -EINVAL; + if (!l) + return -EINVAL; + if (!j->unique_field) + return -EINVAL; + + k = strlen(j->unique_field); + + if (!j->unique_file) { + j->unique_file = hashmap_first(j->files); + if (!j->unique_file) + return 0; + j->unique_offset = 0; + } -/* _public_ void sd_journal_restart_unique(sd_journal *j) { */ -/* if (!j) */ -/* return; */ -/* } */ + for (;;) { + JournalFile *of; + Iterator i; + const void *odata; + size_t ol; + bool found; + + /* Proceed to next data object in the field's linked list */ + if (j->unique_offset == 0) { + r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL); + if (r < 0) + return r; + + j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0; + } else { + r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o); + if (r < 0) + return r; + + j->unique_offset = le64toh(o->data.next_field_offset); + } + + /* We reached the end of the list? Then start again, with the next file */ + if (j->unique_offset == 0) { + JournalFile *n; + + n = hashmap_next(j->files, j->unique_file->path); + if (!n) + return 0; + + j->unique_file = n; + 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 */ + r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o); + if (r < 0) + return r; + + /* Let's do the type check by hand, since we used 0 context above. */ + if (o->object.type != OBJECT_DATA) + return -EBADMSG; + + r = return_data(j, j->unique_file, o, &odata, &ol); + if (r < 0) + return r; + + /* OK, now let's see if we already returned this data + * object by checking if it exists in the earlier + * traversed files. */ + found = false; + HASHMAP_FOREACH(of, j->files, i) { + Object *oo; + uint64_t op; + + if (of == j->unique_file) + break; + + /* Skip this file it didn't have any fields + * indexed */ + if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && + le64toh(of->header->n_fields) <= 0) + continue; + + r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op); + if (r < 0) + return r; + + if (r > 0) + found = true; + } + + if (found) + continue; + + r = return_data(j, j->unique_file, o, data, l); + if (r < 0) + return r; + + return 1; + } +} + +_public_ void sd_journal_restart_unique(sd_journal *j) { + if (!j) + return; + + j->unique_file = NULL; + j->unique_offset = 0; +} + +_public_ int sd_journal_reliable_fd(sd_journal *j) { + if (!j) + return -EINVAL; + + return !j->on_network; +} + +static char *lookup_field(const char *field, void *userdata) { + sd_journal *j = userdata; + const void *data; + size_t size, d; + int r; + + assert(field); + assert(j); + + r = sd_journal_get_data(j, field, &data, &size); + if (r < 0 || + size > REPLACE_VAR_MAX) + return strdup(field); + + d = strlen(field) + 1; + + return strndup((const char*) data + d, size - d); +} + +_public_ int sd_journal_get_catalog(sd_journal *j, char **ret) { + const void *data; + size_t size; + sd_id128_t id; + _cleanup_free_ char *text = NULL, *cid = NULL; + char *t; + int r; + + if (!j) + return -EINVAL; + if (!ret) + return -EINVAL; + + r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size); + if (r < 0) + return r; + + cid = strndup((const char*) data + 11, size - 11); + if (!cid) + return -ENOMEM; + + r = sd_id128_from_string(cid, &id); + if (r < 0) + return r; + + r = catalog_get(id, &text); + if (r < 0) + return r; + + t = replace_var(text, lookup_field, j); + if (!t) + return -ENOMEM; + + *ret = t; + return 0; +} + +_public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) { + if (!ret) + return -EINVAL; + + return catalog_get(id, ret); +} + +_public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) { + if (!j) + return -EINVAL; + + j->data_threshold = sz; + return 0; +} + +_public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) { + if (!j) + return -EINVAL; + if (!sz) + return -EINVAL; + + *sz = j->data_threshold; + return 0; +}