chiark / gitweb /
sd-journal: fix sd_journal_enumerate_unique skipping values
[elogind.git] / src / journal / sd-journal.c
index b9ec90230d74d0c9b7413594920ef328cfed7bb9..479444c8dff94b8a4c22234a120d347cb5f3842f 100644 (file)
@@ -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;
 
@@ -1375,8 +1375,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 = 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);
@@ -1662,7 +1665,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 +1691,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 = 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;
@@ -2490,6 +2493,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 +2510,13 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_
         k = strlen(j->unique_field);
 
         if (!j->unique_file) {
+                if (j->unique_file_lost)
+                        return 0;
+
                 j->unique_file = hashmap_first(j->files);
                 if (!j->unique_file)
                         return 0;
+
                 j->unique_offset = 0;
         }
 
@@ -2520,6 +2528,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 +2547,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 = hashmap_next(j->files, j->unique_file->path);
+                        if (!j->unique_file)
                                 return 0;
 
-                        j->unique_file = n;
                         continue;
                 }
 
@@ -2557,13 +2563,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,6 +2577,21 @@ _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. */
@@ -2596,13 +2617,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 +2638,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) {