chiark / gitweb /
bus: introduce new SD_BUS_VTABLE_HIDDEN flag for vtable members
[elogind.git] / src / journal / sd-journal.c
index 3aa9ed4b3275df6e9e2a82442f3e1125f6931a0e..2ba7ca4559988a9573f8358bf23b7e2217a7b49b 100644 (file)
 
 #define DEFAULT_DATA_THRESHOLD (64*1024)
 
+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) {
@@ -102,7 +111,8 @@ static void init_location(Location *l, LocationType type, JournalFile *f, Object
         l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
 }
 
-static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o, uint64_t offset) {
+static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o,
+                         direction_t direction, uint64_t offset) {
         assert(j);
         assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
         assert(f);
@@ -110,12 +120,10 @@ static void set_location(sd_journal *j, LocationType type, JournalFile *f, Objec
 
         init_location(&j->current_location, type, f, o);
 
-        if (j->current_file)
-                j->current_file->current_offset = 0;
-
         j->current_file = f;
         j->current_field = 0;
 
+        f->last_direction = direction;
         f->current_offset = offset;
 }
 
@@ -164,7 +172,7 @@ static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
                         return true;
         }
 
-        return true;
+        assert_not_reached("\"=\" not found");
 }
 
 static Match *match_new(Match *p, MatchType t) {
@@ -178,7 +186,7 @@ static Match *match_new(Match *p, MatchType t) {
 
         if (p) {
                 m->parent = p;
-                LIST_PREPEND(Match, matches, p->matches, m);
+                LIST_PREPEND(matches, p->matches, m);
         }
 
         return m;
@@ -191,7 +199,7 @@ static void match_free(Match *m) {
                 match_free(m->matches);
 
         if (m->parent)
-                LIST_REMOVE(Match, matches, m->parent->matches, m);
+                LIST_REMOVE(matches, m->parent->matches, m);
 
         free(m->data);
         free(m);
@@ -208,17 +216,14 @@ _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size)
         Match *l3, *l4, *add_here = NULL, *m;
         le64_t le_hash;
 
-        if (!j)
-                return -EINVAL;
-
-        if (!data)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(data, -EINVAL);
 
         if (size == 0)
                 size = strlen(data);
 
-        if (!match_is_valid(data, size))
-                return -EINVAL;
+        assert_return(match_is_valid(data, size), -EINVAL);
 
         /* level 0: AND term
          * level 1: OR terms
@@ -304,7 +309,8 @@ fail:
 }
 
 _public_ int sd_journal_add_conjunction(sd_journal *j) {
-        assert(j);
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         if (!j->level0)
                 return 0;
@@ -322,7 +328,8 @@ _public_ int sd_journal_add_conjunction(sd_journal *j) {
 }
 
 _public_ int sd_journal_add_disjunction(sd_journal *j) {
-        assert(j);
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         if (!j->level0)
                 return 0;
@@ -346,7 +353,7 @@ static char *match_make_string(Match *m) {
         bool enclose = false;
 
         if (!m)
-                return strdup("");
+                return strdup("none");
 
         if (m->type == MATCH_DISCRETE)
                 return strndup(m->data, m->size);
@@ -372,10 +379,8 @@ static char *match_make_string(Match *m) {
                         p = k;
 
                         enclose = true;
-                } else {
-                        free(p);
+                } else
                         p = t;
-                }
         }
 
         if (enclose) {
@@ -394,7 +399,6 @@ char *journal_make_match_string(sd_journal *j) {
 }
 
 _public_ void sd_journal_flush_matches(sd_journal *j) {
-
         if (!j)
                 return;
 
@@ -588,11 +592,14 @@ static int next_for_match(
                         if (r < 0)
                                 return r;
                         else if (r > 0) {
-                                if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
+                                if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
                                         np = cp;
                         }
                 }
 
+                if (np == 0)
+                        return 0;
+
         } else if (m->type == MATCH_AND_TERM) {
                 Match *i, *last_moved;
 
@@ -625,8 +632,7 @@ static int next_for_match(
                 }
         }
 
-        if (np == 0)
-                return 0;
+        assert(np > 0);
 
         r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
         if (r < 0)
@@ -731,7 +737,7 @@ static int find_location_for_match(
                         if (r <= 0)
                                 return r;
 
-                        if (np == 0 || (direction == DIRECTION_DOWN ? np < cp : np > cp))
+                        if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
                                 np = cp;
                 }
 
@@ -811,7 +817,7 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
         assert(j);
         assert(f);
 
-        if (f->current_offset > 0) {
+        if (f->last_direction == direction && f->current_offset > 0) {
                 cp = f->current_offset;
 
                 r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c);
@@ -827,7 +833,7 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
                         return r;
         }
 
-        /* OK, we found the spot, now let's advance until to an entry
+        /* 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
@@ -869,8 +875,8 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
         Iterator i;
         int r;
 
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         HASHMAP_FOREACH(f, j->files, i) {
                 bool found;
@@ -889,10 +895,7 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
 
                         k = compare_entry_order(f, o, new_file, new_offset);
 
-                        if (direction == DIRECTION_DOWN)
-                                found = k < 0;
-                        else
-                                found = k > 0;
+                        found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
                 }
 
                 if (found) {
@@ -908,7 +911,7 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
         if (r < 0)
                 return r;
 
-        set_location(j, LOCATION_DISCRETE, new_file, o, new_offset);
+        set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset);
 
         return 1;
 }
@@ -924,8 +927,8 @@ _public_ int sd_journal_previous(sd_journal *j) {
 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
         int c = 0, r;
 
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         if (skip == 0) {
                 /* If this is not a discrete skip, then at least
@@ -964,10 +967,9 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
         int r;
         char bid[33], sid[33];
 
-        if (!j)
-                return -EINVAL;
-        if (!cursor)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(cursor, -EINVAL);
 
         if (!j->current_file || j->current_file->current_offset <= 0)
                 return -EADDRNOTAVAIL;
@@ -1003,10 +1005,9 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
                 xor_hash_set = false;
         sd_id128_t seqnum_id, boot_id;
 
-        if (!j)
-                return -EINVAL;
-        if (isempty(cursor))
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(!isempty(cursor), -EINVAL);
 
         FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
                 char *item;
@@ -1102,10 +1103,9 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
         size_t l;
         Object *o;
 
-        if (!j)
-                return -EINVAL;
-        if (isempty(cursor))
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(!isempty(cursor), -EINVAL);
 
         if (!j->current_file || j->current_file->current_offset <= 0)
                 return -EADDRNOTAVAIL;
@@ -1180,8 +1180,8 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
 
 
 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         reset_location(j);
         j->current_location.type = LOCATION_SEEK;
@@ -1193,8 +1193,8 @@ _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, u
 }
 
 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         reset_location(j);
         j->current_location.type = LOCATION_SEEK;
@@ -1205,8 +1205,8 @@ _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
 }
 
 _public_ int sd_journal_seek_head(sd_journal *j) {
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         reset_location(j);
         j->current_location.type = LOCATION_HEAD;
@@ -1215,8 +1215,8 @@ _public_ int sd_journal_seek_head(sd_journal *j) {
 }
 
 _public_ int sd_journal_seek_tail(sd_journal *j) {
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         reset_location(j);
         j->current_location.type = LOCATION_TAIL;
@@ -1236,17 +1236,17 @@ static void check_network(sd_journal *j, int fd) {
                 return;
 
         j->on_network =
-                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);
+                F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
+                F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
+                F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
+                F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
+                F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
 }
 
 static bool file_has_type_prefix(const char *prefix, const char *filename) {
         const char *full, *tilded, *atted;
 
-        full = strappend(prefix, ".journal");
+        full = strappenda(prefix, ".journal");
         tilded = strappenda(full, "~");
         atted = strappenda(prefix, "@");
 
@@ -1655,6 +1655,7 @@ static sd_journal *journal_new(int flags, const char *path) {
         if (!j)
                 return NULL;
 
+        j->original_pid = getpid();
         j->inotify_fd = -1;
         j->flags = flags;
         j->data_threshold = DEFAULT_DATA_THRESHOLD;
@@ -1682,8 +1683,7 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) {
         sd_journal *j;
         int r;
 
-        if (!ret)
-                return -EINVAL;
+        assert_return(ret, -EINVAL);
 
         if (flags & ~(SD_JOURNAL_LOCAL_ONLY|
                       SD_JOURNAL_RUNTIME_ONLY|
@@ -1712,14 +1712,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
         sd_journal *j;
         int r;
 
-        if (!ret)
-                return -EINVAL;
-
-        if (!path)
-                return -EINVAL;
-
-        if (flags != 0)
-                return -EINVAL;
+        assert_return(ret, -EINVAL);
+        assert_return(path, -EINVAL);
+        assert_return(flags == 0, -EINVAL);
 
         j = journal_new(flags, path);
         if (!j)
@@ -1745,11 +1740,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
         const char **path;
         int r;
 
-        if (!ret)
-                return -EINVAL;
-
-        if (flags != 0)
-                return -EINVAL;
+        assert_return(ret, -EINVAL);
+        assert_return(flags == 0, -EINVAL);
 
         j = journal_new(flags, NULL);
         if (!j)
@@ -1800,8 +1792,10 @@ _public_ void sd_journal_close(sd_journal *j) {
         if (j->inotify_fd >= 0)
                 close_nointr_nofail(j->inotify_fd);
 
-        if (j->mmap)
+        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->path);
         free(j->unique_field);
@@ -1814,10 +1808,9 @@ _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
         JournalFile *f;
         int r;
 
-        if (!j)
-                return -EINVAL;
-        if (!ret)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(ret, -EINVAL);
 
         f = j->current_file;
         if (!f)
@@ -1840,8 +1833,8 @@ _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id12
         int r;
         sd_id128_t id;
 
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         f = j->current_file;
         if (!f)
@@ -1906,17 +1899,12 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
         int r;
         Object *o;
 
-        if (!j)
-                return -EINVAL;
-        if (!field)
-                return -EINVAL;
-        if (!data)
-                return -EINVAL;
-        if (!size)
-                return -EINVAL;
-
-        if (!field_is_valid(field))
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(field, -EINVAL);
+        assert_return(data, -EINVAL);
+        assert_return(size, -EINVAL);
+        assert_return(field_is_valid(field), -EINVAL);
 
         f = j->current_file;
         if (!f)
@@ -2032,12 +2020,10 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t
         int r;
         Object *o;
 
-        if (!j)
-                return -EINVAL;
-        if (!data)
-                return -EINVAL;
-        if (!size)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(data, -EINVAL);
+        assert_return(size, -EINVAL);
 
         f = j->current_file;
         if (!f)
@@ -2082,8 +2068,8 @@ _public_ void sd_journal_restart_data(sd_journal *j) {
 _public_ int sd_journal_get_fd(sd_journal *j) {
         int r;
 
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         if (j->inotify_fd >= 0)
                 return j->inotify_fd;
@@ -2109,8 +2095,8 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
 _public_ int sd_journal_get_events(sd_journal *j) {
         int fd;
 
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         fd = sd_journal_get_fd(j);
         if (fd < 0)
@@ -2122,10 +2108,9 @@ _public_ int sd_journal_get_events(sd_journal *j) {
 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
         int fd;
 
-        if (!j)
-                return -EINVAL;
-        if (!timeout_usec)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(timeout_usec, -EINVAL);
 
         fd = sd_journal_get_fd(j);
         if (fd < 0)
@@ -2222,8 +2207,8 @@ _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;
 
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         j->last_process_usec = now(CLOCK_MONOTONIC);
 
@@ -2262,7 +2247,8 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
         int r;
         uint64_t t;
 
-        assert(j);
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         if (j->inotify_fd < 0) {
 
@@ -2309,12 +2295,10 @@ _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from,
         bool first = true;
         int r;
 
-        if (!j)
-                return -EINVAL;
-        if (!from && !to)
-                return -EINVAL;
-        if (from == to)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(from || to, -EINVAL);
+        assert_return(from != to, -EINVAL);
 
         HASHMAP_FOREACH(f, j->files, i) {
                 usec_t fr, t;
@@ -2350,12 +2334,10 @@ _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot
         bool first = true;
         int r;
 
-        if (!j)
-                return -EINVAL;
-        if (!from && !to)
-                return -EINVAL;
-        if (from == to)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(from || to, -EINVAL);
+        assert_return(from != to, -EINVAL);
 
         HASHMAP_FOREACH(f, j->files, i) {
                 usec_t fr, t;
@@ -2407,10 +2389,9 @@ _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
         JournalFile *f;
         uint64_t sum = 0;
 
-        if (!j)
-                return -EINVAL;
-        if (!bytes)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(bytes, -EINVAL);
 
         HASHMAP_FOREACH(f, j->files, i) {
                 struct stat st;
@@ -2428,12 +2409,10 @@ _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
         char *f;
 
-        if (!j)
-                return -EINVAL;
-        if (isempty(field))
-                return -EINVAL;
-        if (!field_is_valid(field))
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(!isempty(field), -EINVAL);
+        assert_return(field_is_valid(field), -EINVAL);
 
         f = strdup(field);
         if (!f)
@@ -2452,14 +2431,11 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
         size_t k;
         int r;
 
-        if (!j)
-                return -EINVAL;
-        if (!data)
-                return -EINVAL;
-        if (!l)
-                return -EINVAL;
-        if (!j->unique_field)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(data, -EINVAL);
+        assert_return(l, -EINVAL);
+        assert_return(j->unique_field, -EINVAL);
 
         k = strlen(j->unique_field);
 
@@ -2564,8 +2540,8 @@ _public_ void sd_journal_restart_unique(sd_journal *j) {
 }
 
 _public_ int sd_journal_reliable_fd(sd_journal *j) {
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         return !j->on_network;
 }
@@ -2597,10 +2573,9 @@ _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
         char *t;
         int r;
 
-        if (!j)
-                return -EINVAL;
-        if (!ret)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(ret, -EINVAL);
 
         r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
         if (r < 0)
@@ -2627,25 +2602,23 @@ _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
 }
 
 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
-        if (!ret)
-                return -EINVAL;
+        assert_return(ret, -EINVAL);
 
         return catalog_get(CATALOG_DATABASE, id, ret);
 }
 
 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
-        if (!j)
-                return -EINVAL;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
 
         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;
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(sz, -EINVAL);
 
         *sz = j->data_threshold;
         return 0;