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=bc9e41e0471518a37ef5603896659cb06ef6a029;hp=ef4b9b2242a422c64867eb776feadc987eee566d;hb=aea275c43194b6ac519ef907b62c5c995050fde0;hpb=8cb17a6dc88cecfcee3189765031e9e8a1f4106b diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index ef4b9b224..bc9e41e04 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -49,6 +49,21 @@ #define DEFAULT_DATA_THRESHOLD (64*1024) +/* 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; + + k = set_ensure_allocated(&j->errors, trivial_hash_func, trivial_compare_func); + if (k < 0) + return k; + + return set_put(j->errors, INT_TO_PTR(r)); +} + static void detach_location(sd_journal *j) { Iterator i; JournalFile *f; @@ -188,7 +203,7 @@ static void match_free_if_empty(Match *m) { } _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) { - Match *l2, *l3, *add_here = NULL, *m; + Match *l3, *l4, *add_here = NULL, *m; le64_t le_hash; if (!j) @@ -203,44 +218,52 @@ _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) if (!match_is_valid(data, size)) return -EINVAL; - /* level 0: OR term - * level 1: AND terms - * level 2: OR terms - * level 3: concrete matches */ + /* level 0: AND term + * level 1: OR terms + * level 2: AND terms + * level 3: OR terms + * level 4: concrete matches */ if (!j->level0) { - j->level0 = match_new(NULL, MATCH_OR_TERM); + j->level0 = match_new(NULL, MATCH_AND_TERM); if (!j->level0) return -ENOMEM; } if (!j->level1) { - j->level1 = match_new(j->level0, MATCH_AND_TERM); + j->level1 = match_new(j->level0, MATCH_OR_TERM); if (!j->level1) return -ENOMEM; } - assert(j->level0->type == MATCH_OR_TERM); - assert(j->level1->type == MATCH_AND_TERM); + if (!j->level2) { + j->level2 = match_new(j->level1, MATCH_AND_TERM); + if (!j->level2) + return -ENOMEM; + } + + assert(j->level0->type == MATCH_AND_TERM); + assert(j->level1->type == MATCH_OR_TERM); + assert(j->level2->type == MATCH_AND_TERM); le_hash = htole64(hash64(data, size)); - LIST_FOREACH(matches, l2, j->level1->matches) { - assert(l2->type == MATCH_OR_TERM); + LIST_FOREACH(matches, l3, j->level2->matches) { + assert(l3->type == MATCH_OR_TERM); - LIST_FOREACH(matches, l3, l2->matches) { - assert(l3->type == MATCH_DISCRETE); + LIST_FOREACH(matches, l4, l3->matches) { + assert(l4->type == MATCH_DISCRETE); /* Exactly the same match already? Then ignore * this addition */ - if (l3->le_hash == le_hash && - l3->size == size && - memcmp(l3->data, data, size) == 0) + if (l4->le_hash == le_hash && + l4->size == size && + memcmp(l4->data, data, size) == 0) return 0; /* Same field? Then let's add this to this OR term */ - if (same_field(data, size, l3->data, l3->size)) { - add_here = l2; + if (same_field(data, size, l4->data, l4->size)) { + add_here = l3; break; } } @@ -250,7 +273,7 @@ _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) } if (!add_here) { - add_here = match_new(j->level1, MATCH_OR_TERM); + add_here = match_new(j->level2, MATCH_OR_TERM); if (!add_here) goto fail; } @@ -273,6 +296,9 @@ fail: if (add_here) match_free_if_empty(add_here); + if (j->level2) + match_free_if_empty(j->level2); + if (j->level1) match_free_if_empty(j->level1); @@ -282,9 +308,7 @@ fail: return -ENOMEM; } -_public_ int sd_journal_add_disjunction(sd_journal *j) { - Match *m; - +_public_ int sd_journal_add_conjunction(sd_journal *j) { assert(j); if (!j->level0) @@ -296,11 +320,28 @@ _public_ int sd_journal_add_disjunction(sd_journal *j) { if (!j->level1->matches) return 0; - m = match_new(j->level0, MATCH_AND_TERM); - if (!m) - return -ENOMEM; + j->level1 = NULL; + j->level2 = NULL; - j->level1 = m; + return 0; +} + +_public_ int sd_journal_add_disjunction(sd_journal *j) { + assert(j); + + if (!j->level0) + return 0; + + if (!j->level1) + return 0; + + if (!j->level2) + return 0; + + if (!j->level2->matches) + return 0; + + j->level2 = NULL; return 0; } @@ -365,7 +406,7 @@ _public_ void sd_journal_flush_matches(sd_journal *j) { if (j->level0) match_free(j->level0); - j->level0 = j->level1 = NULL; + j->level0 = j->level1 = j->level2 = NULL; detach_location(j); } @@ -587,7 +628,7 @@ static int next_for_match( return r; if ((direction == DIRECTION_DOWN ? cp >= after_offset : cp <= after_offset) && - (np == 0 || (direction == DIRECTION_DOWN ? cp > np : np < cp))) { + (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))) { np = cp; continue_looking = true; } @@ -1207,11 +1248,11 @@ static void check_network(sd_journal *j, int fd) { 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; + F_TYPE_CMP(sfs.f_type, CIFS_MAGIC_NUMBER) || + F_TYPE_CMP(sfs.f_type, CODA_SUPER_MAGIC) || + F_TYPE_CMP(sfs.f_type, NCP_SUPER_MAGIC) || + F_TYPE_CMP(sfs.f_type, NFS_SUPER_MAGIC) || + F_TYPE_CMP(sfs.f_type, SMB_SUPER_MAGIC); } static int add_file(sd_journal *j, const char *prefix, const char *filename) { @@ -1239,7 +1280,7 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) { log_debug("Too many open journal files, not adding %s, ignoring.", path); - return 0; + return set_put_error(j, -ETOOMANYREFS); } r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); @@ -1380,8 +1421,13 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) if (dirent_is_file_with_suffix(de, ".journal") || 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)); + if (r < 0) { + log_debug("Failed to add file %s/%s: %s", + m->path, de->d_name, strerror(-r)); + r = set_put_error(j, r); + if (r < 0) + return r; + } } } @@ -1454,9 +1500,13 @@ static int add_root_directory(sd_journal *j, const char *p) { if (dirent_is_file_with_suffix(de, ".journal") || 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)); - + if (r < 0) { + log_debug("Failed to add file %s/%s: %s", + m->path, de->d_name, strerror(-r)); + r = set_put_error(j, r); + if (r < 0) + return r; + } } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) && sd_id128_from_string(de->d_name, &id) >= 0) { @@ -1495,7 +1545,7 @@ static int remove_directory(sd_journal *j, Directory *d) { } static int add_search_paths(sd_journal *j) { - + int r; const char search_paths[] = "/run/log/journal\0" "/var/log/journal\0"; @@ -1506,8 +1556,14 @@ static int add_search_paths(sd_journal *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) - add_root_directory(j, p); + 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; } @@ -1607,8 +1663,10 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f return -ENOMEM; r = add_root_directory(j, path); - if (r < 0) + if (r < 0) { + set_put_error(j, r); goto fail; + } *ret = j; return 0; @@ -1626,6 +1684,8 @@ _public_ void sd_journal_close(sd_journal *j) { if (!j) return; + sd_journal_flush_matches(j); + while ((f = hashmap_steal_first(j->files))) journal_file_close(f); @@ -1643,13 +1703,12 @@ _public_ void sd_journal_close(sd_journal *j) { if (j->inotify_fd >= 0) close_nointr_nofail(j->inotify_fd); - sd_journal_flush_matches(j); - if (j->mmap) mmap_cache_unref(j->mmap); free(j->path); free(j->unique_field); + set_free(j->errors); free(j); } @@ -1948,6 +2007,43 @@ _public_ int sd_journal_get_fd(sd_journal *j) { return j->inotify_fd; } +_public_ int sd_journal_get_events(sd_journal *j) { + int fd; + + if (!j) + return -EINVAL; + + fd = sd_journal_get_fd(j); + if (fd < 0) + return fd; + + return POLLIN; +} + +_public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { + int fd; + + if (!j) + return -EINVAL; + if (!timeout_usec) + return -EINVAL; + + fd = sd_journal_get_fd(j); + if (fd < 0) + return fd; + + if (!j->on_network) { + *timeout_usec = (uint64_t) -1; + return 0; + } + + /* If we are on the network we need to regularly check for + * changes manually */ + + *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC; + return 1; +} + static void process_inotify_event(sd_journal *j, struct inotify_event *e) { Directory *d; int r; @@ -1968,8 +2064,11 @@ 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)); + if (r < 0) { + log_debug("Failed to add file %s/%s: %s", + d->path, e->name, strerror(-r)); + set_put_error(j, r); + } } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) { @@ -2027,6 +2126,8 @@ _public_ int sd_journal_process(sd_journal *j) { if (!j) return -EINVAL; + j->last_process_usec = now(CLOCK_MONOTONIC); + for (;;) { struct inotify_event *e; ssize_t l; @@ -2060,6 +2161,7 @@ _public_ int sd_journal_process(sd_journal *j) { _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { int r; + uint64_t t; assert(j); @@ -2078,12 +2180,18 @@ _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 */ + 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; - if (timeout_usec == (uint64_t) -1 || timeout_usec > JOURNAL_FILES_RECHECK_USEC) - timeout_usec = JOURNAL_FILES_RECHECK_USEC; + if (timeout_usec == (uint64_t) -1 || timeout_usec > t) + timeout_usec = t; } do { @@ -2403,7 +2511,7 @@ _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) { if (r < 0) return r; - r = catalog_get(id, &text); + r = catalog_get(CATALOG_DATABASE, id, &text); if (r < 0) return r; @@ -2419,7 +2527,7 @@ _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) { if (!ret) return -EINVAL; - return catalog_get(id, ret); + return catalog_get(CATALOG_DATABASE, id, ret); } _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {