<refnamediv>
<refname>sd_journal_get_fd</refname>
+ <refname>sd_journal_get_events</refname>
+ <refname>sd_journal_get_timeout</refname>
<refname>sd_journal_process</refname>
<refname>sd_journal_wait</refname>
+ <refname>sd_journal_reliable_fd</refname>
<refname>SD_JOURNAL_NOP</refname>
<refname>SD_JOURNAL_APPEND</refname>
<refname>SD_JOURNAL_INVALIDATE</refname>
<funcprototype>
<funcdef>int <function>sd_journal_get_fd</function></funcdef>
- <paramdef>sd_journal* <parameter>j</parameter></paramdef>
+ <paramdef>sd_journal *<parameter>j</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_journal_get_events</function></funcdef>
+ <paramdef>sd_journal *<parameter>j</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_journal_get_timeout</function></funcdef>
+ <paramdef>sd_journal *<parameter>j</parameter></paramdef>
+ <paramdef>uint64_t *<parameter>timeout_usec</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_journal_process</function></funcdef>
- <paramdef>sd_journal* <parameter>j</parameter></paramdef>
+ <paramdef>sd_journal *<parameter>j</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_journal_wait</function></funcdef>
- <paramdef>sd_journal* <parameter>j</parameter></paramdef>
+ <paramdef>sd_journal *<parameter>j</parameter></paramdef>
<paramdef>uint64_t <parameter>timeout_usec</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>int <function>sd_journal_reliable_fd</function></funcdef>
+ <paramdef>sd_journal *<parameter>j</parameter></paramdef>
+ </funcprototype>
+
</funcsynopsis>
</refsynopsisdiv>
<para><function>sd_journal_get_fd()</function> returns
a file descriptor that may be asynchronously polled in
- an external event loop and is signaled readable as
- soon as the journal changes, for example because new
- entries were added. The file descriptor is suitable
+ an external event loop and is signaled as soon as the
+ journal changes, because new entries or files were
+ added, rotation took place, or files have been
+ deleted, and similar. The file descriptor is suitable
for usage in
- <citerefentry><refentrytitle>poll</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- where it will yield POLLIN on all changes. The call
- takes one argument: the journal context object.</para>
+ <citerefentry><refentrytitle>poll</refentrytitle><manvolnum>2</manvolnum></citerefentry>. Use
+ <function>sd_journal_get_events()</function> for an
+ events mask to watch for. The call takes one argument:
+ the journal context object. Note that not all file
+ systems are capable of generating the necessary events
+ for wakeups from this file descriptor for changes to
+ be noticed immediately. In particular network files
+ systems do not generate suitable file change events in
+ all cases. Cases like this can be detected with
+ <function>sd_journal_reliable_fd()</function>,
+ below. <function>sd_journal_get_timeout()</function>
+ will ensure in these cases that wake-ups happen
+ frequently enough for changes to be noticed, although
+ with a certain latency.</para>
+
+ <para><function>sd_journal_get_events()</function>
+ will return the <function>poll()</function> mask to
+ wait for. This function will return a combination of
+ <constant>POLLIN</constant> and
+ <constant>POLLOUT</constant> and similar to fill into
+ the <literal>.events</literal> field of
+ <varname>struct pollfd</varname>.</para>
+
+ <para><function>sd_journal_get_timeout()</function>
+ will return a timeout value for usage in
+ <function>poll()</function>. This returns a value in
+ microseconds since the epoch of
+ <constant>CLOCK_MONOTONIC</constant> for timing out
+ <function>poll()</function> in
+ <varname>timeout_usec</varname>. See
+ <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ for details about
+ <constant>CLOCK_MONOTONIC</constant>. If there is no
+ timeout to wait for, this will fill in
+ <constant>(uint64_t) -1</constant> instead. Note that
+ <function>poll()</function> takes a relative timeout
+ in milliseconds rather than an absolute timeout in
+ microseconds. To convert the absolute 'us' timeout
+ into relative 'ms', use code like the
+ following:</para>
- <para>After each POLLIN wake-up
+ <programlisting>uint64_t t;
+int msec;
+sd_journal_get_timeout(m, &t);
+if (t == (uint64_t) -1)
+ msec = -1;
+else {
+ struct timespec ts;
+ uint64_t n;
+ clock_getttime(CLOCK_MONOTONIC, &ts);
+ n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+ msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
+}</programlisting>
+
+ <para>The code above does not do any error checking
+ for brevity's sake. The calculated <varname>msec</varname>
+ integer can be passed directly as
+ <function>poll()</function>'s timeout
+ parameter.</para>
+
+ <para>After each <function>poll()</function> wake-up
<function>sd_journal_process()</function> needs to be
- called to process events and reset the readable state
- of the file descriptor. This call will also indicate
+ called to process events. This call will also indicate
what kind of change has been detected (see below; note
that spurious wake-ups are possible).</para>
<para>A synchronous alternative for using
- <function>sd_journal_get_fd()</function> and
+ <function>sd_journal_get_fd()</function>,
+ <function>sd_journal_get_events()</function>,
+ <function>sd_journal_get_timeout()</function> and
<function>sd_journal_process()</function> is
<function>sd_journal_wait()</function>. It will
- synchronously wait until the journal gets changed up
- to a certain time-out as specified in its second
- argument. Pass <literal>(uint64_t) -1</literal> to
+ synchronously wait until the journal gets changed. The
+ maximum time this call sleeps may be controlled with
+ the <parameter>timeout_usec</parameter>
+ parameter. Pass <constant>(uint64_t) -1</constant> to
wait indefinitely. Internally this call simply
combines <function>sd_journal_get_fd()</function>,
+ <function>sd_journal_get_events()</function>,
+ <function>sd_journal_get_timeout()</function>,
<function>poll()</function> and
<function>sd_journal_process()</function> into
one.</para>
+ <para><function>sd_journal_reliable_fd()</function>
+ may be used to check whether the wakeup events from
+ the file descriptor returned by
+ <function>sd_journal_get_fd()</function> are known to
+ be immediately triggered. On certain file systems
+ where file change events from the OS are not available
+ (such as NFS) changes need to be polled for
+ repeatedly, and hence are detected only with a certain
+ latency. This call will return a positive value if the
+ journal changes are detected immediately and zero when
+ they need to be polled for and hence might be noticed
+ only with a certain latency. Note that there's usually
+ no need to invoke this function directly as
+ <function>sd_journal_get_timeout()</function> on these
+ file systems will ask for timeouts explicitly
+ anyway.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
- <para><function>sd_journal_get_fd()</function> returns a valid file descriptor on success or a negative errno-style error
- code.</para>
+ <para><function>sd_journal_get_fd()</function> returns
+ a valid file descriptor on success or a negative
+ errno-style error code.</para>
+
+ <para><function>sd_journal_get_events()</function>
+ returns a combination of <constant>POLLIN</constant>,
+ <constant>POLLOUT</constant> and suchlike on success or
+ a negative errno-style error code.</para>
+
+ <para><function>sd_journal_reliable_fd()</function>
+ returns a positive integer if the file descriptor
+ returned by <function>sd_journal_get_fd()</function>
+ will generate wake-ups immediately for all journal
+ changes. Returns 0 if there might be a latency
+ involved.</para>
<para><function>sd_journal_process()</function> and
<function>sd_journal_wait()</function> return one of
- <literal>SD_JOURNAL_NOP</literal>,
- <literal>SD_JOURNAL_APPEND</literal> or
- <literal>SD_JOURNAL_INVALIDATE</literal> on success or
+ <constant>SD_JOURNAL_NOP</constant>,
+ <constant>SD_JOURNAL_APPEND</constant> or
+ <constant>SD_JOURNAL_INVALIDATE</constant> on success or
a negative errno-style error code. If
- <literal>SD_JOURNAL_NOP</literal> is returned the
- journal didn't change since the last invocation. If
- <literal>SD_JOURNAL_APPEND</literal> is returned new
+ <constant>SD_JOURNAL_NOP</constant> is returned, the
+ journal did not change since the last invocation. If
+ <constant>SD_JOURNAL_APPEND</constant> is returned, new
entries have been appended to the end of the
- journal. If <literal>SD_JOURNAL_INVALIDATE</literal>
+ journal. If <constant>SD_JOURNAL_INVALIDATE</constant>,
journal files were added or removed (possibly due to
- rotation). In the latter event live-view UIs should
- probably refresh their entire display while in the
- case of <literal>SD_JOURNAL_APPEND</literal> it is
+ rotation). In the latter event, live-view UIs should
+ probably refresh their entire display, while in the
+ case of <constant>SD_JOURNAL_APPEND</constant>, it is
sufficient to simply continue reading at the previous
end of the journal.</para>
</refsect1>
<title>Notes</title>
<para>The <function>sd_journal_get_fd()</function>,
+ <function>sd_journal_get_events()</function>,
+ <function>sd_journal_reliable_fd()</function>,
<function>sd_journal_process()</function> and
<function>sd_journal_wait()</function> interfaces are
- available as shared library, which can be compiled and
+ available as a shared library, which can be compiled and
linked to with the
- <literal>libsystemd-journal</literal>
- <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <constant>libsystemd</constant> <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
file.</para>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <para>Iterating through the journal, in a live view tracking all changes:</para>
+
+ <programlisting>#include <stdio.h>
+#include <string.h>
+#include <systemd/sd-journal.h>
+
+int main(int argc, char *argv[]) {
+ int r;
+ sd_journal *j;
+ r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
+ if (r < 0) {
+ fprintf(stderr, "Failed to open journal: %s\n", strerror(-r));
+ return 1;
+ }
+ for (;;) {
+ const void *d;
+ size_t l;
+ r = sd_journal_next(j);
+ if (r < 0) {
+ fprintf(stderr, "Failed to iterate to next entry: %s\n", strerror(-r));
+ break;
+ }
+ if (r == 0) {
+ /* Reached the end, let's wait for changes, and try again */
+ r = sd_journal_wait(j, (uint64_t) -1);
+ if (r < 0) {
+ fprintf(stderr, "Failed to wait for changes: %s\n", strerror(-r));
+ break;
+ }
+ continue;
+ }
+ r = sd_journal_get_data(j, "MESSAGE", &d, &l);
+ if (r < 0) {
+ fprintf(stderr, "Failed to read message field: %s\n", strerror(-r));
+ continue;
+ }
+ printf("%.*s\n", (int) l, (const char*) d);
+ }
+ sd_journal_close(j);
+ return 0;
+}</programlisting>
+
+ <para>Waiting with <function>poll()</function> (this
+ example lacks all error checking for the sake of
+ simplicity):</para>
+
+ <programlisting>#include <sys/poll.h>
+#include <systemd/sd-journal.h>
+
+int wait_for_changes(sd_journal *j) {
+ struct pollfd pollfd;
+ int msec;
+
+ sd_journal_get_timeout(m, &t);
+ if (t == (uint64_t) -1)
+ msec = -1;
+ else {
+ struct timespec ts;
+ uint64_t n;
+ clock_getttime(CLOCK_MONOTONIC, &ts);
+ n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+ msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
+ }
+
+ pollfd.fd = sd_journal_get_fd(j);
+ pollfd.events = sd_journal_get_events(j);
+ poll(&pollfd, 1, msec);
+ return sd_journal_process(j);
+}</programlisting>
+ </refsect1>
+
<refsect1>
<title>See Also</title>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</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_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>poll</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>
</para>
</refsect1>