sd-journal: add an API to enumerate known field names of the journal
authorLennart Poettering <lennart@poettering.net>
Wed, 27 Jan 2016 17:59:29 +0000 (18:59 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 1 Feb 2016 21:42:33 +0000 (22:42 +0100)
This adds two new calls to get the list of all journal fields names currently in use.

This is the low-level support to implement the feature requested in #2176 in a more optimized way.

Makefile-man.am
man/sd-journal.xml
man/sd_journal_enumerate_fields.xml [new file with mode: 0644]
man/sd_journal_query_unique.xml
src/journal/journal-internal.h
src/journal/sd-journal.c
src/libsystemd/libsystemd.sym
src/systemd/sd-journal.h

index 12900da..28b5fb6 100644 (file)
@@ -72,6 +72,7 @@ MANPAGES += \
        man/sd_id128_to_string.3 \
        man/sd_is_fifo.3 \
        man/sd_journal_add_match.3 \
+       man/sd_journal_enumerate_fields.3 \
        man/sd_journal_get_catalog.3 \
        man/sd_journal_get_cursor.3 \
        man/sd_journal_get_cutoff_realtime_usec.3 \
@@ -237,6 +238,7 @@ MANPAGES_ALIAS += \
        man/SD_JOURNAL_FOREACH.3 \
        man/SD_JOURNAL_FOREACH_BACKWARDS.3 \
        man/SD_JOURNAL_FOREACH_DATA.3 \
+       man/SD_JOURNAL_FOREACH_FIELD.3 \
        man/SD_JOURNAL_FOREACH_UNIQUE.3 \
        man/SD_JOURNAL_INVALIDATE.3 \
        man/SD_JOURNAL_LOCAL_ONLY.3 \
@@ -397,6 +399,7 @@ MANPAGES_ALIAS += \
        man/sd_journal_process.3 \
        man/sd_journal_reliable_fd.3 \
        man/sd_journal_restart_data.3 \
+       man/sd_journal_restart_fields.3 \
        man/sd_journal_restart_unique.3 \
        man/sd_journal_seek_cursor.3 \
        man/sd_journal_seek_monotonic_usec.3 \
@@ -565,6 +568,7 @@ man/SD_JOURNAL_CURRENT_USER.3: man/sd_journal_open.3
 man/SD_JOURNAL_FOREACH.3: man/sd_journal_next.3
 man/SD_JOURNAL_FOREACH_BACKWARDS.3: man/sd_journal_next.3
 man/SD_JOURNAL_FOREACH_DATA.3: man/sd_journal_get_data.3
+man/SD_JOURNAL_FOREACH_FIELD.3: man/sd_journal_enumerate_fields.3
 man/SD_JOURNAL_FOREACH_UNIQUE.3: man/sd_journal_query_unique.3
 man/SD_JOURNAL_INVALIDATE.3: man/sd_journal_get_fd.3
 man/SD_JOURNAL_LOCAL_ONLY.3: man/sd_journal_open.3
@@ -725,6 +729,7 @@ man/sd_journal_printv.3: man/sd_journal_print.3
 man/sd_journal_process.3: man/sd_journal_get_fd.3
 man/sd_journal_reliable_fd.3: man/sd_journal_get_fd.3
 man/sd_journal_restart_data.3: man/sd_journal_get_data.3
+man/sd_journal_restart_fields.3: man/sd_journal_enumerate_fields.3
 man/sd_journal_restart_unique.3: man/sd_journal_query_unique.3
 man/sd_journal_seek_cursor.3: man/sd_journal_seek_head.3
 man/sd_journal_seek_monotonic_usec.3: man/sd_journal_seek_head.3
@@ -1017,6 +1022,9 @@ man/SD_JOURNAL_FOREACH_BACKWARDS.html: man/sd_journal_next.html
 man/SD_JOURNAL_FOREACH_DATA.html: man/sd_journal_get_data.html
        $(html-alias)
 
+man/SD_JOURNAL_FOREACH_FIELD.html: man/sd_journal_enumerate_fields.html
+       $(html-alias)
+
 man/SD_JOURNAL_FOREACH_UNIQUE.html: man/sd_journal_query_unique.html
        $(html-alias)
 
@@ -1497,6 +1505,9 @@ man/sd_journal_reliable_fd.html: man/sd_journal_get_fd.html
 man/sd_journal_restart_data.html: man/sd_journal_get_data.html
        $(html-alias)
 
+man/sd_journal_restart_fields.html: man/sd_journal_enumerate_fields.html
+       $(html-alias)
+
 man/sd_journal_restart_unique.html: man/sd_journal_query_unique.html
        $(html-alias)
 
@@ -2534,6 +2545,7 @@ EXTRA_DIST += \
        man/sd_id128_to_string.xml \
        man/sd_is_fifo.xml \
        man/sd_journal_add_match.xml \
+       man/sd_journal_enumerate_fields.xml \
        man/sd_journal_get_catalog.xml \
        man/sd_journal_get_cursor.xml \
        man/sd_journal_get_cutoff_realtime_usec.xml \
index a1185d3..09747a4 100644 (file)
@@ -77,6 +77,8 @@
     <citerefentry><refentrytitle>sd_journal_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_journal_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_journal_seek_head</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>sd_journal_query_enumerate</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>sd_journal_enumerate_fields</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_journal_get_cutoff_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_journal_get_cutoff_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_seek_head</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_query_enumerate</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_enumerate_fields</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_get_cutoff_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_get_cutoff_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
diff --git a/man/sd_journal_enumerate_fields.xml b/man/sd_journal_enumerate_fields.xml
new file mode 100644 (file)
index 0000000..fa58841
--- /dev/null
@@ -0,0 +1,161 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_journal_enumerate_fields">
+
+  <refentryinfo>
+    <title>sd_journal_enumerate_fields</title>
+    <productname>systemd</productname>
+
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>Lennart</firstname>
+        <surname>Poettering</surname>
+        <email>lennart@poettering.net</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_journal_enumerate_fields</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_journal_enumerate_fields</refname>
+    <refname>sd_journal_restart_fields</refname>
+    <refname>SD_JOURNAL_FOREACH_FIELD</refname>
+    <refpurpose>Read used field names from the journal</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-journal.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_journal_enumerate_fields</function></funcdef>
+        <paramdef>sd_journal *<parameter>j</parameter></paramdef>
+        <paramdef>const char **<parameter>field</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>void <function>sd_journal_restart_fields</function></funcdef>
+        <paramdef>sd_journal *<parameter>j</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef><function>SD_JOURNAL_FOREACH_FIELD</function></funcdef>
+        <paramdef>sd_journal *<parameter>j</parameter></paramdef>
+        <paramdef>const char *<parameter>field</parameter></paramdef>
+      </funcprototype>
+
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_journal_enumerate_fields()</function> may be used to iterate through all field names used in the
+    opened journal files. On each invocation the next field name is returned. The order of the returned field names is
+    not defined. It takes two arguments: the journal context object, plus a pointer to a constant string pointer where
+    the field name is stored in. The returned data is in a read-only memory map and is only valid until the next
+    invocation of <function>sd_journal_enumerate_fields()</function>. Note that this call is subject to the data field
+    size threshold as controlled by <function>sd_journal_set_data_threshold()</function>.</para>
+
+    <para><function>sd_journal_restart_fields()</function> resets the field name enumeration index to the beginning of
+    the list. The next invocation of <function>sd_journal_enumerate_fields()</function> will return the first field
+    name again.</para>
+
+    <para>The <function>SD_JOURNAL_FOREACH_FIELD()</function> macro may be used as a handy wrapper around
+    <function>sd_journal_restart_fields()</function> and <function>sd_journal_enumerate_fields()</function>.</para>
+
+    <para>These functions currently are not influenced by matches set with <function>sd_journal_add_match()</function>
+    but this might change in a later version of this software.</para>
+
+    <para>To retrieve the possible values a specific field can take use
+    <citerefentry><refentrytitle>sd_journal_query_unique</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>sd_journal_enumerate_fields()</function> returns a
+    positive integer if the next field name has been read, 0 when no
+    more field names are known, or a negative errno-style error code.
+    <function>sd_journal_restart_fields()</function> returns
+    nothing.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Notes</title>
+
+    <para>The <function>sd_journal_enumerate_fields()</function> and <function>sd_journal_restart_fields()</function>
+    interfaces are available as a shared library, which can be compiled and linked to with the
+    <constant>libsystemd</constant> <citerefentry
+    project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Examples</title>
+
+    <para>Use the <function>SD_JOURNAL_FOREACH_FIELD</function> macro to iterate through all field names in use in the
+    current journal.</para>
+
+    <programlisting>#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;systemd/sd-journal.h&gt;
+
+int main(int argc, char *argv[]) {
+        sd_journal *j;
+        const char *field;
+        int r;
+
+        r = sd_journal_open(&amp;j, SD_JOURNAL_LOCAL_ONLY);
+        if (r &lt; 0) {
+                fprintf(stderr, "Failed to open journal: %s\n", strerror(-r));
+                return 1;
+        }
+        SD_JOURNAL_FOREACH_FIELD(j, field)
+                printf("%s\n", field);
+        sd_journal_close(j);
+        return 0;
+}</programlisting>
+
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_open</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_query_unique</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
index ac0e5f6..dbff55c 100644 (file)
     <para>Note that these functions currently are not influenced by
     matches set with <function>sd_journal_add_match()</function> but
     this might change in a later version of this software.</para>
+
+    <para>To enumerate all field names currently in use (and thus all suitable field parameters for
+    <function>sd_journal_query_unique()</function>), use the
+    <citerefentry><refentrytitle>sd_journal_enumerate_fields</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    call.</para>
   </refsect1>
 
   <refsect1>
 #include &lt;systemd/sd-journal.h&gt;
 
 int main(int argc, char *argv[]) {
-  sd_journal *j;
-  const void *d;
-  size_t l;
-  int r;
-
-  r = sd_journal_open(&amp;j, SD_JOURNAL_LOCAL_ONLY);
-  if (r &lt; 0) {
-    fprintf(stderr, "Failed to open journal: %s\n", strerror(-r));
-    return 1;
-  }
-  r = sd_journal_query_unique(j, "_SYSTEMD_UNIT");
-  if (r &lt; 0) {
-    fprintf(stderr, "Failed to query journal: %s\n", strerror(-r));
-    return 1;
-  }
-  SD_JOURNAL_FOREACH_UNIQUE(j, d, l)
-    printf("%.*s\n", (int) l, (const char*) d);
-  sd_journal_close(j);
-  return 0;
+        sd_journal *j;
+        const void *d;
+        size_t l;
+        int r;
+
+        r = sd_journal_open(&amp;j, SD_JOURNAL_LOCAL_ONLY);
+        if (r &lt; 0) {
+                fprintf(stderr, "Failed to open journal: %s\n", strerror(-r));
+                return 1;
+        }
+        r = sd_journal_query_unique(j, "_SYSTEMD_UNIT");
+        if (r &lt; 0) {
+                fprintf(stderr, "Failed to query journal: %s\n", strerror(-r));
+                return 1;
+        }
+        SD_JOURNAL_FOREACH_UNIQUE(j, d, l)
+                printf("%.*s\n", (int) l, (const char*) d);
+        sd_journal_close(j);
+        return 0;
 }</programlisting>
 
   </refsect1>
@@ -198,6 +203,7 @@ int main(int argc, char *argv[]) {
       <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_open</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_journal_enumerate_fields</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     </para>
index fa5ca11..a55d1bc 100644 (file)
@@ -103,18 +103,27 @@ struct sd_journal {
         unsigned current_invalidate_counter, last_invalidate_counter;
         usec_t last_process_usec;
 
+        /* Iterating through unique fields and their data values */
         char *unique_field;
         JournalFile *unique_file;
         uint64_t unique_offset;
 
+        /* Iterating through known fields */
+        JournalFile *fields_file;
+        uint64_t fields_offset;
+        uint64_t fields_hash_table_index;
+        char *fields_buffer;
+        size_t fields_buffer_allocated;
+
         int flags;
 
-        bool on_network;
-        bool no_new_files;
-        bool unique_file_lost; /* File we were iterating over got
-                                  removed, and there were no more
-                                  files, so sd_j_enumerate_unique
-                                  will return a value equal to 0. */
+        bool on_network:1;
+        bool no_new_files:1;
+        bool unique_file_lost:1; /* File we were iterating over got
+                                    removed, and there were no more
+                                    files, so sd_j_enumerate_unique
+                                    will return a value equal to 0. */
+        bool fields_file_lost:1;
         bool has_runtime_files:1;
         bool has_persistent_files:1;
 
index 74a5e26..85d9bbe 100644 (file)
@@ -1338,6 +1338,13 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
                         j->unique_file_lost = true;
         }
 
+        if (j->fields_file == f) {
+                j->fields_file = ordered_hashmap_next(j->files, j->fields_file->path);
+                j->fields_offset = 0;
+                if (!j->fields_file)
+                        j->fields_file_lost = true;
+        }
+
         journal_file_close(f);
 
         j->current_invalidate_counter ++;
@@ -1806,6 +1813,7 @@ _public_ void sd_journal_close(sd_journal *j) {
         free(j->path);
         free(j->prefix);
         free(j->unique_field);
+        free(j->fields_buffer);
         free(j);
 }
 
@@ -2552,6 +2560,154 @@ _public_ void sd_journal_restart_unique(sd_journal *j) {
         j->unique_file_lost = false;
 }
 
+_public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) {
+        int r;
+
+        assert_return(j, -EINVAL);
+        assert_return(!journal_pid_changed(j), -ECHILD);
+        assert_return(field, -EINVAL);
+
+        if (!j->fields_file) {
+                if (j->fields_file_lost)
+                        return 0;
+
+                j->fields_file = ordered_hashmap_first(j->files);
+                if (!j->fields_file)
+                        return 0;
+
+                j->fields_hash_table_index = 0;
+                j->fields_offset = 0;
+        }
+
+        for (;;) {
+                JournalFile *f, *of;
+                Iterator i;
+                uint64_t m;
+                Object *o;
+                size_t sz;
+                bool found;
+
+                f = j->fields_file;
+
+                if (j->fields_offset == 0) {
+                        bool eof = false;
+
+                        /* We are not yet positioned at any field. Let's pick the first one */
+                        r = journal_file_map_field_hash_table(f);
+                        if (r < 0)
+                                return r;
+
+                        m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
+                        for (;;) {
+                                if (j->fields_hash_table_index >= m) {
+                                        /* Reached the end of the hash table, go to the next file. */
+                                        eof = true;
+                                        break;
+                                }
+
+                                j->fields_offset = le64toh(f->field_hash_table[j->fields_hash_table_index].head_hash_offset);
+
+                                if (j->fields_offset != 0)
+                                        break;
+
+                                /* Empty hash table bucket, go to next one */
+                                j->fields_hash_table_index++;
+                        }
+
+                        if (eof) {
+                                /* Proceed with next file */
+                                j->fields_file = ordered_hashmap_next(j->files, f->path);
+                                if (!j->fields_file) {
+                                        *field = NULL;
+                                        return 0;
+                                }
+
+                                j->fields_offset = 0;
+                                j->fields_hash_table_index = 0;
+                                continue;
+                        }
+
+                } else {
+                        /* We are already positioned at a field. If so, let's figure out the next field from it */
+
+                        r = journal_file_move_to_object(f, OBJECT_FIELD, j->fields_offset, &o);
+                        if (r < 0)
+                                return r;
+
+                        j->fields_offset = le64toh(o->field.next_hash_offset);
+                        if (j->fields_offset == 0) {
+                                /* Reached the end of the hash table chain */
+                                j->fields_hash_table_index++;
+                                continue;
+                        }
+                }
+
+                /* We use OBJECT_UNUSED here, so that the iteator below doesn't remove our mmap window */
+                r = journal_file_move_to_object(f, OBJECT_UNUSED, j->fields_offset, &o);
+                if (r < 0)
+                        return r;
+
+                /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
+                if (o->object.type != OBJECT_FIELD) {
+                        log_debug("%s:offset " OFSfmt ": object has type %i, expected %i", f->path, j->fields_offset, o->object.type, OBJECT_FIELD);
+                        return -EBADMSG;
+                }
+
+                sz = le64toh(o->object.size) - offsetof(Object, field.payload);
+
+                /* Let's see if we already returned this field name before. */
+                found = false;
+                ORDERED_HASHMAP_FOREACH(of, j->files, i) {
+                        if (of == f)
+                                break;
+
+                        /* Skip this file it didn't have any fields indexed */
+                        if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
+                                continue;
+
+                        r = journal_file_find_field_object_with_hash(of, o->field.payload, sz, le64toh(o->field.hash), NULL, NULL);
+                        if (r < 0)
+                                return r;
+                        if (r > 0) {
+                                found = true;
+                                break;
+                        }
+                }
+
+                if (found)
+                        continue;
+
+                /* Check if this is really a valid string containing no NUL byte */
+                if (memchr(o->field.payload, 0, sz))
+                        return -EBADMSG;
+
+                if (sz > j->data_threshold)
+                        sz = j->data_threshold;
+
+                if (!GREEDY_REALLOC(j->fields_buffer, j->fields_buffer_allocated, sz + 1))
+                        return -ENOMEM;
+
+                memcpy(j->fields_buffer, o->field.payload, sz);
+                j->fields_buffer[sz] = 0;
+
+                if (!field_is_valid(j->fields_buffer))
+                        return -EBADMSG;
+
+                *field = j->fields_buffer;
+                return 1;
+        }
+}
+
+_public_ void sd_journal_restart_fields(sd_journal *j) {
+        if (!j)
+                return;
+
+        j->fields_file = NULL;
+        j->fields_hash_table_index = 0;
+        j->fields_offset = 0;
+        j->fields_file_lost = false;
+}
+
 _public_ int sd_journal_reliable_fd(sd_journal *j) {
         assert_return(j, -EINVAL);
         assert_return(!journal_pid_changed(j), -ECHILD);
index 043ff13..d6928bf 100644 (file)
@@ -481,3 +481,9 @@ global:
         sd_bus_path_encode_many;
         sd_listen_fds_with_names;
 } LIBSYSTEMD_226;
+
+LIBSYSTEMD_229 {
+global:
+        sd_journal_enumerate_fields;
+        sd_journal_restart_fields;
+} LIBSYSTEMD_227;
index 7f16c69..caf322f 100644 (file)
@@ -129,6 +129,9 @@ int sd_journal_query_unique(sd_journal *j, const char *field);
 int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l);
 void sd_journal_restart_unique(sd_journal *j);
 
+int sd_journal_enumerate_fields(sd_journal *j, const char **field);
+void sd_journal_restart_fields(sd_journal *j);
+
 int sd_journal_get_fd(sd_journal *j);
 int sd_journal_get_events(sd_journal *j);
 int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec);
@@ -142,22 +145,28 @@ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **text);
 int sd_journal_has_runtime_files(sd_journal *j);
 int sd_journal_has_persistent_files(sd_journal *j);
 
-/* the inverse condition avoids ambiguity of danling 'else' after the macro */
+/* The inverse condition avoids ambiguity of dangling 'else' after the macro */
 #define SD_JOURNAL_FOREACH(j)                                           \
         if (sd_journal_seek_head(j) < 0) { }                            \
         else while (sd_journal_next(j) > 0)
 
-/* the inverse condition avoids ambiguity of danling 'else' after the macro */
+/* The inverse condition avoids ambiguity of dangling 'else' after the macro */
 #define SD_JOURNAL_FOREACH_BACKWARDS(j)                                 \
         if (sd_journal_seek_tail(j) < 0) { }                            \
         else while (sd_journal_previous(j) > 0)
 
+/* Iterate through the data fields of the current journal entry */
 #define SD_JOURNAL_FOREACH_DATA(j, data, l)                             \
         for (sd_journal_restart_data(j); sd_journal_enumerate_data((j), &(data), &(l)) > 0; )
 
+/* Iterate through the all known values of a specific field */
 #define SD_JOURNAL_FOREACH_UNIQUE(j, data, l)                           \
         for (sd_journal_restart_unique(j); sd_journal_enumerate_unique((j), &(data), &(l)) > 0; )
 
+/* Iterate through all known field names */
+#define SD_JOURNAL_FOREACH_FIELD(j, field) \
+        for (sd_journal_restart_fields(j); sd_journal_enumerate_fields((j), &(field)) > 0; )
+
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_journal, sd_journal_close);
 
 _SD_END_DECLARATIONS;