X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fsd-journal.c;h=23aad740dd14da29e63c7eefb858e2627a0c1f87;hb=fbcedaaea4705a0548d50d9702ece04f73847344;hp=b9ec90230d74d0c9b7413594920ef328cfed7bb9;hpb=fa1c4b518ec7d8ec2d647213ee651cde4d6c9d7e;p=elogind.git diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index b9ec90230..23aad740d 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -70,7 +70,7 @@ static int set_put_error(sd_journal *j, int r) { if (r >= 0) return r; - k = set_ensure_allocated(&j->errors, trivial_hash_func, trivial_compare_func); + k = set_ensure_allocated(&j->errors, NULL); if (k < 0) return k; @@ -86,7 +86,7 @@ static void detach_location(sd_journal *j) { j->current_file = NULL; j->current_field = 0; - HASHMAP_FOREACH(f, j->files, i) + ORDERED_HASHMAP_FOREACH(f, j->files, i) f->current_offset = 0; } @@ -497,6 +497,47 @@ static int compare_entry_order(JournalFile *af, Object *_ao, return 0; } +static bool whole_file_precedes_location(JournalFile *f, Location *l, direction_t direction) { + assert(f); + assert(l); + + if (l->type != LOCATION_DISCRETE && l->type != LOCATION_SEEK) + return false; + + if (l->seqnum_set && sd_id128_equal(l->seqnum_id, f->header->seqnum_id)) + return direction == DIRECTION_DOWN ? + l->seqnum > le64toh(f->header->tail_entry_seqnum) : + l->seqnum < le64toh(f->header->head_entry_seqnum); + + if (l->realtime_set) + return direction == DIRECTION_DOWN ? + l->realtime > le64toh(f->header->tail_entry_realtime) : + l->realtime < le64toh(f->header->head_entry_realtime); + + return false; +} + +static bool file_may_have_preceding_entry(JournalFile *f, JournalFile *of, uint64_t op, direction_t direction) { + Object *o; + int r; + + assert(f); + assert(of); + + r = journal_file_move_to_object(of, OBJECT_ENTRY, op, &o); + if (r < 0) + return true; + + if (sd_id128_equal(f->header->seqnum_id, of->header->seqnum_id)) + return direction == DIRECTION_DOWN ? + le64toh(o->entry.seqnum) >= le64toh(f->header->head_entry_seqnum) : + le64toh(o->entry.seqnum) <= le64toh(f->header->tail_entry_seqnum); + + return direction == DIRECTION_DOWN ? + le64toh(o->entry.realtime) >= le64toh(f->header->head_entry_realtime) : + le64toh(o->entry.realtime) <= le64toh(f->header->tail_entry_realtime); +} + _pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) { uint64_t a; @@ -849,10 +890,8 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc int k; k = compare_with_location(f, c, &j->current_location); - if (direction == DIRECTION_DOWN) - found = k > 0; - else - found = k < 0; + + found = direction == DIRECTION_DOWN ? k > 0 : k < 0; } else found = true; @@ -881,12 +920,18 @@ static int real_journal_next(sd_journal *j, direction_t direction) { assert_return(j, -EINVAL); assert_return(!journal_pid_changed(j), -ECHILD); - HASHMAP_FOREACH(f, j->files, i) { + ORDERED_HASHMAP_FOREACH(f, j->files, i) { bool found; + if (whole_file_precedes_location(f, &j->current_location, direction)) + continue; + + if (new_file && !file_may_have_preceding_entry(f, new_file, new_offset, direction)) + continue; + 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)); + log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path); remove_file_real(j, f); continue; } else if (r == 0) @@ -1290,10 +1335,10 @@ static int add_any_file(sd_journal *j, const char *path) { assert(j); assert(path); - if (hashmap_get(j->files, path)) + if (ordered_hashmap_get(j->files, path)) return 0; - if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) { + if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { log_warning("Too many open journal files, not adding %s.", path); return set_put_error(j, -ETOOMANYREFS); } @@ -1304,7 +1349,7 @@ static int add_any_file(sd_journal *j, const char *path) { /* journal_file_dump(f); */ - r = hashmap_put(j->files, f->path, f); + r = ordered_hashmap_put(j->files, f->path, f); if (r < 0) { journal_file_close(f); return r; @@ -1353,7 +1398,7 @@ static int remove_file(sd_journal *j, const char *prefix, const char *filename) if (!path) return -ENOMEM; - f = hashmap_get(j->files, path); + f = ordered_hashmap_get(j->files, path); if (!f) return 0; @@ -1365,7 +1410,7 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { assert(j); assert(f); - hashmap_remove(j->files, f->path); + ordered_hashmap_remove(j->files, f->path); log_debug("File %s removed.", f->path); @@ -1375,8 +1420,11 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { } if (j->unique_file == f) { - j->unique_file = NULL; + /* Jump to the next unique_file or NULL if that one was last */ + j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path); j->unique_offset = 0; + if (!j->unique_file) + j->unique_file_lost = true; } journal_file_close(f); @@ -1409,7 +1457,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) d = opendir(path); if (!d) { - log_debug("Failed to open %s: %m", path); + log_debug_errno(errno, "Failed to open %s: %m", path); if (errno == ENOENT) return 0; return -errno; @@ -1455,7 +1503,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) de = readdir(d); if (!de && errno != 0) { r = -errno; - log_debug("Failed to read directory %s: %m", m->path); + log_debug_errno(errno, "Failed to read directory %s: %m", m->path); return r; } if (!de) @@ -1465,8 +1513,8 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) dirent_is_file_with_suffix(de, ".journal~")) { r = add_file(j, m->path, de->d_name); if (r < 0) { - log_debug("Failed to add file %s/%s: %s", - m->path, de->d_name, strerror(-r)); + log_debug_errno(r, "Failed to add file %s/%s: %m", + m->path, de->d_name); r = set_put_error(j, r); if (r < 0) return r; @@ -1545,7 +1593,7 @@ static int add_root_directory(sd_journal *j, const char *p) { de = readdir(d); if (!de && errno != 0) { r = -errno; - log_debug("Failed to read directory %s: %m", m->path); + log_debug_errno(errno, "Failed to read directory %s: %m", m->path); return r; } if (!de) @@ -1555,8 +1603,8 @@ static int add_root_directory(sd_journal *j, const char *p) { dirent_is_file_with_suffix(de, ".journal~")) { r = add_file(j, m->path, de->d_name); if (r < 0) { - log_debug("Failed to add file %s/%s: %s", - m->path, de->d_name, strerror(-r)); + log_debug_errno(r, "Failed to add file %s/%s: %m", + m->path, de->d_name); r = set_put_error(j, r); if (r < 0) return r; @@ -1566,7 +1614,7 @@ static int add_root_directory(sd_journal *j, const char *p) { r = add_directory(j, m->path, de->d_name); if (r < 0) - log_debug("Failed to add directory %s/%s: %s", m->path, de->d_name, strerror(-r)); + log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name); } } @@ -1633,7 +1681,7 @@ static int add_current_paths(sd_journal *j) { * "root" directories. We don't expect errors here, so we * treat them as fatal. */ - HASHMAP_FOREACH(f, j->files, i) { + ORDERED_HASHMAP_FOREACH(f, j->files, i) { _cleanup_free_ char *dir; int r; @@ -1662,7 +1710,7 @@ static int allocate_inotify(sd_journal *j) { } if (!j->directories_by_wd) { - j->directories_by_wd = hashmap_new(trivial_hash_func, trivial_compare_func); + j->directories_by_wd = hashmap_new(NULL); if (!j->directories_by_wd) return -ENOMEM; } @@ -1688,8 +1736,8 @@ static sd_journal *journal_new(int flags, const char *path) { goto fail; } - j->files = hashmap_new(string_hash_func, string_compare_func); - j->directories_by_path = hashmap_new(string_hash_func, string_compare_func); + j->files = ordered_hashmap_new(&string_hash_ops); + j->directories_by_path = hashmap_new(&string_hash_ops); j->mmap = mmap_cache_new(); if (!j->files || !j->directories_by_path || !j->mmap) goto fail; @@ -1734,7 +1782,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in assert_return(machine, -EINVAL); assert_return(ret, -EINVAL); assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL); - assert_return(filename_is_safe(machine), -EINVAL); + assert_return(machine_name_is_valid(machine), -EINVAL); p = strappenda("/run/systemd/machines/", machine); r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL); @@ -1809,7 +1857,7 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla STRV_FOREACH(path, paths) { r = add_any_file(j, *path); if (r < 0) { - log_error("Failed to open %s: %s", *path, strerror(-r)); + log_error_errno(r, "Failed to open %s: %m", *path); goto fail; } } @@ -1834,10 +1882,10 @@ _public_ void sd_journal_close(sd_journal *j) { sd_journal_flush_matches(j); - while ((f = hashmap_steal_first(j->files))) + while ((f = ordered_hashmap_steal_first(j->files))) journal_file_close(f); - hashmap_free(j->files); + ordered_hashmap_free(j->files); while ((d = hashmap_first(j->directories_by_path))) remove_directory(j, d); @@ -2217,8 +2265,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { r = add_file(j, d->path, e->name); if (r < 0) { - log_debug("Failed to add file %s/%s: %s", - d->path, e->name, strerror(-r)); + log_debug_errno(r, "Failed to add file %s/%s: %m", + d->path, e->name); set_put_error(j, r); } @@ -2226,7 +2274,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { r = remove_file(j, d->path, e->name); if (r < 0) - log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r)); + log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name); } } else if (!d->is_root && e->len == 0) { @@ -2236,7 +2284,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) { r = remove_directory(j, d); if (r < 0) - log_debug("Failed to remove directory %s: %s", d->path, strerror(-r)); + log_debug_errno(r, "Failed to remove directory %s: %m", d->path); } @@ -2247,7 +2295,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { r = add_directory(j, d->path, e->name); if (r < 0) - log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r)); + log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name); } } @@ -2272,7 +2320,6 @@ static int determine_change(sd_journal *j) { } _public_ int sd_journal_process(sd_journal *j) { - uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event); bool got_something = false; assert_return(j, -EINVAL); @@ -2281,6 +2328,7 @@ _public_ int sd_journal_process(sd_journal *j) { j->last_process_usec = now(CLOCK_MONOTONIC); for (;;) { + uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event); struct inotify_event *e; ssize_t l; @@ -2294,18 +2342,8 @@ _public_ int sd_journal_process(sd_journal *j) { got_something = true; - e = (struct inotify_event*) buffer; - while (l > 0) { - size_t step; - + FOREACH_INOTIFY_EVENT(e, buffer, l) process_inotify_event(j, e); - - step = sizeof(struct inotify_event) + e->len; - assert(step <= (size_t) l); - - e = (struct inotify_event*) ((uint8_t*) e + step); - l -= step; - } } } @@ -2367,7 +2405,7 @@ _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, assert_return(from || to, -EINVAL); assert_return(from != to, -EINVAL); - HASHMAP_FOREACH(f, j->files, i) { + ORDERED_HASHMAP_FOREACH(f, j->files, i) { usec_t fr, t; r = journal_file_get_cutoff_realtime_usec(f, &fr, &t); @@ -2407,7 +2445,7 @@ _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot assert_return(from || to, -EINVAL); assert_return(from != to, -EINVAL); - HASHMAP_FOREACH(f, j->files, i) { + ORDERED_HASHMAP_FOREACH(f, j->files, i) { usec_t fr, t; r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t); @@ -2442,7 +2480,7 @@ void journal_print_header(sd_journal *j) { assert(j); - HASHMAP_FOREACH(f, j->files, i) { + ORDERED_HASHMAP_FOREACH(f, j->files, i) { if (newline) putchar('\n'); else @@ -2461,7 +2499,7 @@ _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) { assert_return(!journal_pid_changed(j), -ECHILD); assert_return(bytes, -EINVAL); - HASHMAP_FOREACH(f, j->files, i) { + ORDERED_HASHMAP_FOREACH(f, j->files, i) { struct stat st; if (fstat(f->fd, &st) < 0) @@ -2490,6 +2528,7 @@ _public_ int sd_journal_query_unique(sd_journal *j, const char *field) { j->unique_field = f; j->unique_file = NULL; j->unique_offset = 0; + j->unique_file_lost = false; return 0; } @@ -2506,9 +2545,13 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ k = strlen(j->unique_field); if (!j->unique_file) { - j->unique_file = hashmap_first(j->files); + if (j->unique_file_lost) + return 0; + + j->unique_file = ordered_hashmap_first(j->files); if (!j->unique_file) return 0; + j->unique_offset = 0; } @@ -2520,6 +2563,7 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ size_t ol; bool found; int r; + void *release_cookie; /* Proceed to next data object in the field's linked list */ if (j->unique_offset == 0) { @@ -2538,13 +2582,10 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ /* 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) + j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path); + if (!j->unique_file) return 0; - j->unique_file = n; continue; } @@ -2557,13 +2598,13 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ /* Let's do the type check by hand, since we used 0 context above. */ if (o->object.type != OBJECT_DATA) { - log_error("%s:offset " OFSfmt ": object has type %d, expected %d", + log_debug("%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); + r = journal_file_object_keep(j->unique_file, o, j->unique_offset, &release_cookie); if (r < 0) return r; @@ -2571,11 +2612,26 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ if (r < 0) return r; + /* Check if we have at least the field name and "=". */ + if (ol <= k) { + log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu", + j->unique_file->path, j->unique_offset, + ol, k + 1); + return -EBADMSG; + } + + if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') { + log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"", + j->unique_file->path, j->unique_offset, + 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; - HASHMAP_FOREACH(of, j->files, i) { + ORDERED_HASHMAP_FOREACH(of, j->files, i) { Object *oo; uint64_t op; @@ -2596,13 +2652,13 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ found = true; } - if (found) - continue; - - r = journal_file_object_release(j->unique_file, o, j->unique_offset); + r = journal_file_object_release(j->unique_file, release_cookie); if (r < 0) return r; + if (found) + continue; + r = return_data(j, j->unique_file, o, data, l); if (r < 0) return r; @@ -2617,6 +2673,7 @@ _public_ void sd_journal_restart_unique(sd_journal *j) { j->unique_file = NULL; j->unique_offset = 0; + j->unique_file_lost = false; } _public_ int sd_journal_reliable_fd(sd_journal *j) {