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=b9ec90230d74d0c9b7413594920ef328cfed7bb9;hp=b55cf37e50d93c609b0726e065d5bab4d7a990c2;hb=fa1c4b518ec7d8ec2d647213ee651cde4d6c9d7e;hpb=b6741478e7661c7e580e5dcfd6a6fccd1899c1d0 diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index b55cf37e5..b9ec90230 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -51,6 +51,8 @@ #define DEFAULT_DATA_THRESHOLD (64*1024) +static void remove_file_real(sd_journal *j, JournalFile *f); + static bool journal_pid_changed(sd_journal *j) { assert(j); @@ -464,7 +466,7 @@ static int compare_entry_order(JournalFile *af, Object *_ao, if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) { - /* If the boot id matches compare monotonic time */ + /* If the boot id matches, compare monotonic time */ a = le64toh(ao->entry.monotonic); b = le64toh(bo->entry.monotonic); @@ -474,7 +476,7 @@ static int compare_entry_order(JournalFile *af, Object *_ao, return 1; } - /* Otherwise compare UTC time */ + /* Otherwise, compare UTC time */ a = le64toh(ao->entry.realtime); b = le64toh(bo->entry.realtime); @@ -871,9 +873,9 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc static int real_journal_next(sd_journal *j, direction_t direction) { JournalFile *f, *new_file = NULL; uint64_t new_offset = 0; - Object *o; - uint64_t p; + uint64_t p = 0; Iterator i; + Object *o; int r; assert_return(j, -EINVAL); @@ -885,6 +887,7 @@ static int real_journal_next(sd_journal *j, direction_t direction) { r = next_beyond_location(j, f, direction, &o, &p); if (r < 0) { log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r)); + remove_file_real(j, f); continue; } else if (r == 0) continue; @@ -994,7 +997,7 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) { } _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { - char *w, *state; + const char *word, *state; size_t l; unsigned long long seqnum, monotonic, realtime, xor_hash; bool @@ -1010,18 +1013,18 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { assert_return(!journal_pid_changed(j), -ECHILD); assert_return(!isempty(cursor), -EINVAL); - FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) { + FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) { char *item; int k = 0; - if (l < 2 || w[1] != '=') + if (l < 2 || word[1] != '=') return -EINVAL; - item = strndup(w, l); + item = strndup(word, l); if (!item) return -ENOMEM; - switch (w[0]) { + switch (word[0]) { case 's': seqnum_id_set = true; @@ -1100,7 +1103,7 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { int r; - char *w, *state; + const char *word, *state; size_t l; Object *o; @@ -1115,20 +1118,20 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { if (r < 0) return r; - FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) { + FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) { _cleanup_free_ char *item = NULL; sd_id128_t id; unsigned long long ll; int k = 0; - if (l < 2 || w[1] != '=') + if (l < 2 || word[1] != '=') return -EINVAL; - item = strndup(w, l); + item = strndup(word, l); if (!item) return -ENOMEM; - switch (w[0]) { + switch (word[0]) { case 's': k = sd_id128_from_string(item+2, &id); @@ -1270,7 +1273,7 @@ static bool file_type_wanted(int flags, const char *filename) { if (flags & SD_JOURNAL_CURRENT_USER) { char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1]; - assert_se(snprintf(prefix, sizeof(prefix), "user-%lu", (unsigned long) getuid()) + assert_se(snprintf(prefix, sizeof(prefix), "user-"UID_FMT, getuid()) < (int) sizeof(prefix)); if (file_has_type_prefix(prefix, filename)) @@ -1281,7 +1284,7 @@ static bool file_type_wanted(int flags, const char *filename) { } static int add_any_file(sd_journal *j, const char *path) { - JournalFile *f; + JournalFile *f = NULL; int r; assert(j); @@ -1339,7 +1342,7 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { } static int remove_file(sd_journal *j, const char *prefix, const char *filename) { - char *path; + _cleanup_free_ char *path; JournalFile *f; assert(j); @@ -1351,10 +1354,17 @@ static int remove_file(sd_journal *j, const char *prefix, const char *filename) return -ENOMEM; f = hashmap_get(j->files, path); - free(path); if (!f) return 0; + remove_file_real(j, f); + return 0; +} + +static void remove_file_real(sd_journal *j, JournalFile *f) { + assert(j); + assert(f); + hashmap_remove(j->files, f->path); log_debug("File %s removed.", f->path); @@ -1372,8 +1382,6 @@ static int remove_file(sd_journal *j, const char *prefix, const char *filename) journal_file_close(f); j->current_invalidate_counter ++; - - return 0; } static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { @@ -1442,10 +1450,15 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) for (;;) { struct dirent *de; - union dirent_storage buf; - r = readdir_r(d, &buf.de, &de); - if (r != 0 || !de) + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + r = -errno; + log_debug("Failed to read directory %s: %m", m->path); + return r; + } + if (!de) break; if (dirent_is_file_with_suffix(de, ".journal") || @@ -1466,7 +1479,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) return 0; } -static int add_root_directory(sd_journal *j, const char *p, const char *prefix) { +static int add_root_directory(sd_journal *j, const char *p) { _cleanup_closedir_ DIR *d = NULL; Directory *m; int r; @@ -1478,8 +1491,8 @@ static int add_root_directory(sd_journal *j, const char *p, const char *prefix) !path_startswith(p, "/run")) return -EINVAL; - if (prefix) - p = strappenda(prefix, p); + if (j->prefix) + p = strappenda(j->prefix, p); d = opendir(p); if (!d) @@ -1526,11 +1539,16 @@ static int add_root_directory(sd_journal *j, const char *p, const char *prefix) for (;;) { struct dirent *de; - union dirent_storage buf; sd_id128_t id; - r = readdir_r(d, &buf.de, &de); - if (r != 0 || !de) + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + r = -errno; + log_debug("Failed to read directory %s: %m", m->path); + return r; + } + if (!de) break; if (dirent_is_file_with_suffix(de, ".journal") || @@ -1580,7 +1598,7 @@ static int remove_directory(sd_journal *j, Directory *d) { return 0; } -static int add_search_paths(sd_journal *j, const char *prefix) { +static int add_search_paths(sd_journal *j) { int r; const char search_paths[] = "/run/log/journal\0" @@ -1593,7 +1611,7 @@ static int add_search_paths(sd_journal *j, const char *prefix) { * what's actually accessible, and ignore the rest. */ NULSTR_FOREACH(p, search_paths) { - r = add_root_directory(j, p, prefix); + r = add_root_directory(j, p); if (r < 0 && r != -ENOENT) { r = set_put_error(j, r); if (r < 0) @@ -1616,14 +1634,14 @@ static int add_current_paths(sd_journal *j) { * treat them as fatal. */ HASHMAP_FOREACH(f, j->files, i) { - int r; _cleanup_free_ char *dir; + int r; dir = dirname_malloc(f->path); if (!dir) return -ENOMEM; - r = add_root_directory(j, dir, NULL); + r = add_root_directory(j, dir); if (r < 0) { set_put_error(j, r); return r; @@ -1694,7 +1712,7 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) { if (!j) return -ENOMEM; - r = add_search_paths(j, NULL); + r = add_search_paths(j); if (r < 0) goto fail; @@ -1734,7 +1752,10 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in if (!j) return -ENOMEM; - r = add_search_paths(j, root); + j->prefix = root; + root = NULL; + + r = add_search_paths(j); if (r < 0) goto fail; @@ -1758,7 +1779,7 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f if (!j) return -ENOMEM; - r = add_root_directory(j, path, NULL); + r = add_root_directory(j, path); if (r < 0) { set_put_error(j, r); goto fail; @@ -1827,8 +1848,7 @@ _public_ void sd_journal_close(sd_journal *j) { hashmap_free(j->directories_by_path); hashmap_free(j->directories_by_wd); - if (j->inotify_fd >= 0) - close_nointr_nofail(j->inotify_fd); + 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)); @@ -1836,6 +1856,7 @@ _public_ void sd_journal_close(sd_journal *j) { } free(j->path); + free(j->prefix); free(j->unique_field); set_free(j->errors); free(j); @@ -1962,6 +1983,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** uint64_t p, l; le64_t le_hash; size_t t; + int compression; p = le64toh(o->entry.items[i].object_offset); le_hash = o->entry.items[i].hash; @@ -1974,19 +1996,22 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** l = le64toh(o->object.size) - offsetof(Object, data.payload); - if (o->object.flags & OBJECT_COMPRESSED) { - -#ifdef HAVE_XZ - if (uncompress_startswith(o->data.payload, l, + compression = o->object.flags & OBJECT_COMPRESSION_MASK; + if (compression) { +#if defined(HAVE_XZ) || defined(HAVE_LZ4) + if (decompress_startswith(compression, + o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, field, field_length, '=')) { - uint64_t rsize; + size_t rsize; - if (!uncompress_blob(o->data.payload, l, - &f->compress_buffer, &f->compress_buffer_size, &rsize, - j->data_threshold)) - return -EBADMSG; + r = decompress_blob(compression, + o->data.payload, l, + &f->compress_buffer, &f->compress_buffer_size, &rsize, + j->data_threshold); + if (r < 0) + return r; *data = f->compress_buffer; *size = (size_t) rsize; @@ -1996,7 +2021,6 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** #else return -EPROTONOSUPPORT; #endif - } else if (l >= field_length+1 && memcmp(o->data.payload, field, field_length) == 0 && o->data.payload[field_length] == '=') { @@ -2023,6 +2047,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) { size_t t; uint64_t l; + int compression; l = le64toh(o->object.size) - offsetof(Object, data.payload); t = (size_t) l; @@ -2031,12 +2056,17 @@ static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **da if ((uint64_t) t != l) return -E2BIG; - if (o->object.flags & OBJECT_COMPRESSED) { -#ifdef HAVE_XZ - uint64_t rsize; + compression = o->object.flags & OBJECT_COMPRESSION_MASK; + if (compression) { +#if defined(HAVE_XZ) || defined(HAVE_LZ4) + size_t rsize; + int r; - if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold)) - return -EBADMSG; + r = decompress_blob(compression, + o->data.payload, l, &f->compress_buffer, + &f->compress_buffer_size, &rsize, j->data_threshold); + if (r < 0) + return r; *data = f->compress_buffer; *size = (size_t) rsize; @@ -2121,9 +2151,9 @@ _public_ int sd_journal_get_fd(sd_journal *j) { if (j->no_new_files) r = add_current_paths(j); else if (j->path) - r = add_root_directory(j, j->path, NULL); + r = add_root_directory(j, j->path); else - r = add_search_paths(j, NULL); + r = add_search_paths(j); if (r < 0) return r; @@ -2277,8 +2307,6 @@ _public_ int sd_journal_process(sd_journal *j) { l -= step; } } - - return determine_change(j); } _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { @@ -2331,6 +2359,7 @@ _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, Iterator i; JournalFile *f; bool first = true; + uint64_t fmin = 0, tmax = 0; int r; assert_return(j, -EINVAL); @@ -2350,26 +2379,27 @@ _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, continue; if (first) { - if (from) - *from = fr; - if (to) - *to = t; + fmin = fr; + tmax = t; first = false; } else { - if (from) - *from = MIN(fr, *from); - if (to) - *to = MAX(t, *to); + fmin = MIN(fr, fmin); + tmax = MAX(t, tmax); } } + if (from) + *from = fmin; + if (to) + *to = tmax; + 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 first = true; + bool found = false; int r; assert_return(j, -EINVAL); @@ -2388,21 +2418,21 @@ _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot if (r == 0) continue; - if (first) { + if (found) { if (from) - *from = fr; + *from = MIN(fr, *from); if (to) - *to = t; - first = false; + *to = MAX(t, *to); } else { if (from) - *from = MIN(fr, *from); + *from = fr; if (to) - *to = MAX(t, *to); + *to = t; + found = true; } } - return first ? 0 : 1; + return found; } void journal_print_header(sd_journal *j) { @@ -2465,9 +2495,7 @@ _public_ int sd_journal_query_unique(sd_journal *j, const char *field) { } _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) { - Object *o; size_t k; - int r; assert_return(j, -EINVAL); assert_return(!journal_pid_changed(j), -ECHILD); @@ -2487,9 +2515,11 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ for (;;) { JournalFile *of; Iterator i; + Object *o; const void *odata; size_t ol; bool found; + int r; /* Proceed to next data object in the field's linked list */ if (j->unique_offset == 0) { @@ -2526,8 +2556,16 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ return r; /* Let's do the type check by hand, since we used 0 context above. */ - if (o->object.type != OBJECT_DATA) + if (o->object.type != OBJECT_DATA) { + log_error("%s:offset " OFSfmt ": object has type %d, expected %d", + j->unique_file->path, j->unique_offset, + o->object.type, OBJECT_DATA); return -EBADMSG; + } + + r = journal_file_object_keep(j->unique_file, o, j->unique_offset); + if (r < 0) + return r; r = return_data(j, j->unique_file, o, &odata, &ol); if (r < 0) @@ -2561,6 +2599,10 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ if (found) continue; + r = journal_file_object_release(j->unique_file, o, j->unique_offset); + if (r < 0) + return r; + r = return_data(j, j->unique_file, o, data, l); if (r < 0) return r;