Merge pull request #4526 from keszybz/coredump-python

Collect interpreter backtraces in systemd-coredump
This commit is contained in:
Lennart Poettering 2017-02-16 11:24:03 +01:00 committed by GitHub
commit 2fe917fe91
44 changed files with 1170 additions and 872 deletions

1
.gitignore vendored
View file

@ -220,6 +220,7 @@
/test-journal
/test-journal-enum
/test-journal-flush
/test-journal-importer
/test-journal-init
/test-journal-interleaving
/test-journal-match

View file

@ -51,12 +51,14 @@ systemd's build dependencies:
Putting this all together, here's a series of commands for preparing a patch
for systemd (this example is for Fedora):
$ sudo dnf builddep systemd # install build dependencies
$ sudo dnf install mkosi # install tool to quickly build images
$ git clone https://github.com/systemd/systemd.git
$ cd systemd
$ vim src/core/main.c # or wherever you'd like to make your changes
$ dnf builddep systemd # install build dependencies
$ ./autogen.sh c # configure the source tree
$ make -j `nproc` # build it locally, see if everything compiles fine
$ make -j `nproc` check # run some simple regression tests
$ sudo mkosi # build a test image
$ sudo systemd-nspawn -bi image.raw # boot up the test image
$ git add -p # interactively put together your patch

View file

@ -240,6 +240,7 @@ MANPAGES_ALIAS += \
man/SD_ID128_FORMAT_STR.3 \
man/SD_ID128_FORMAT_VAL.3 \
man/SD_ID128_MAKE.3 \
man/SD_ID128_MAKE_STR.3 \
man/SD_ID128_NULL.3 \
man/SD_INFO.3 \
man/SD_JOURNAL_APPEND.3 \
@ -597,6 +598,7 @@ man/SD_ID128_CONST_STR.3: man/sd-id128.3
man/SD_ID128_FORMAT_STR.3: man/sd-id128.3
man/SD_ID128_FORMAT_VAL.3: man/sd-id128.3
man/SD_ID128_MAKE.3: man/sd-id128.3
man/SD_ID128_MAKE_STR.3: man/sd-id128.3
man/SD_ID128_NULL.3: man/sd-id128.3
man/SD_INFO.3: man/sd-daemon.3
man/SD_JOURNAL_APPEND.3: man/sd_journal_get_fd.3
@ -1066,6 +1068,9 @@ man/SD_ID128_FORMAT_VAL.html: man/sd-id128.html
man/SD_ID128_MAKE.html: man/sd-id128.html
$(html-alias)
man/SD_ID128_MAKE_STR.html: man/sd-id128.html
$(html-alias)
man/SD_ID128_NULL.html: man/sd-id128.html
$(html-alias)

View file

@ -960,7 +960,9 @@ libbasic_la_SOURCES = \
src/basic/format-util.h \
src/basic/nss-util.h \
src/basic/khash.h \
src/basic/khash.c
src/basic/khash.c \
src/basic/journal-importer.h \
src/basic/journal-importer.c
nodist_libbasic_la_SOURCES = \
src/basic/errno-from-name.h \
@ -1596,7 +1598,8 @@ tests += \
test-rlimit-util \
test-signal-util \
test-selinux \
test-sizeof
test-sizeof \
test-journal-importer
if HAVE_ACL
tests += \
@ -2460,6 +2463,16 @@ test_arphrd_list_SOURCES = \
test_arphrd_list_LDADD = \
libsystemd-shared.la
test_journal_importer_SOURCES = \
src/test/test-journal-importer.c
test_journal_importer_LDADD = \
libsystemd-shared.la
EXTRA_DIST += \
test/journal-data/journal-1.txt \
test/journal-data/journal-2.txt
# ------------------------------------------------------------------------------
## .PHONY so it always rebuilds it
.PHONY: coverage lcov-run lcov-report coverage-sync

View file

@ -85,7 +85,7 @@
<listitem><para>Controls where to store cores. One of <literal>none</literal>,
<literal>external</literal>, and <literal>journal</literal>. When
<literal>none</literal>, the core dumps will be logged (included the traceback if
<literal>none</literal>, the core dumps will be logged (including the backtrace if
possible), but not stored permanently. When <literal>external</literal> (the
default), cores will be stored in <filename>/var/lib/systemd/coredump/</filename>.
When <literal>journal</literal>, cores will be stored in the journal and rotated

View file

@ -47,6 +47,7 @@
<refname>sd-id128</refname>
<refname>sd_id128_t</refname>
<refname>SD_ID128_MAKE</refname>
<refname>SD_ID128_MAKE_STR</refname>
<refname>SD_ID128_NULL</refname>
<refname>SD_ID128_CONST_STR</refname>
<refname>SD_ID128_FORMAT_STR</refname>
@ -113,12 +114,24 @@
<para><function>SD_ID128_NULL</function> may be used to refer to the 128bit ID consisting of only NUL
bytes.</para>
<para><function>SD_ID128_MAKE_STR()</function> is similar to <function>SD_ID128_MAKE()</function>, but creates a
<type>const char*</type> expression that can be conveniently used in message formats and such:</para>
<programlisting>#include &lt;stdio.h&gt;
#define SD_MESSAGE_COREDUMP_STR SD_ID128_MAKE_STR(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
int main(int argc, char **argv) {
puts("Match for coredumps: MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
}
</programlisting>
<para><function>SD_ID128_CONST_STR()</function> may be used to
convert constant 128-bit IDs into constant strings for output. The
following example code will output the string
"fc2e22bc6ee647b6b90729ab34a250b1":</para>
<programlisting>int main(int argc, char *argv[]) {
puts(SD_ID128_CONST_STR(SD_MESSAGE_COREDUMP));
puts("Match for coredumps: %s", SD_ID128_CONST_STR(SD_MESSAGE_COREDUMP));
}</programlisting>
<para><function>SD_ID128_FORMAT_STR()</function> and

View file

@ -52,14 +52,26 @@
<refsynopsisdiv>
<para><filename>/usr/lib/systemd/systemd-coredump</filename></para>
<para><filename>/usr/lib/systemd/systemd-coredump</filename> <option>--backtrace</option></para>
<para><filename>systemd-coredump@.service</filename></para>
<para><filename>systemd-coredump.socket</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>systemd-coredump</command> is a system service that can acquire core dumps
from the kernel and handle them in various ways.</para>
<para><filename>systemd-coredump@.service</filename> is a system service that can acquire core
dumps from the kernel and handle them in various ways. The <command>systemd-coredump</command>
executable does the actual work. It is invoked twice: once as the handler by the kernel, and the
second time in the <filename>systemd-coredump@.service</filename> to actually write the data to
the journal.</para>
<para>When the kernel invokes <command>systemd-coredump</command> to handle a core dump, it runs
in privileged mode, and will connect to the socket created by the
<filename>systemd-coredump.socket</filename> unit, which in turn will spawn an unprivileged
<filename>systemd-coredump@.service</filename> instance to process the core dump. Hence
<filename>systemd-coredump.socket</filename> and <filename>systemd-coredump@.service</filename>
are helper units which do the actual processing of core dumps and are subject to normal service
management.</para>
<para>Core dumps can be written to the journal or saved as a file. Once saved they can be retrieved
for further processing, for example in
@ -70,18 +82,20 @@
if possible to the journal and store the core dump itself in an external file in
<filename>/var/lib/systemd/coredump</filename>.</para>
<para>When the kernel invokes <command>systemd-coredump</command> to handle a core dump,
it will connect to the socket created by the <filename>systemd-coredump.socket</filename>
unit, which in turn will spawn a <filename>systemd-coredump@.service</filename> instance
to process the core dump. Hence <filename>systemd-coredump.socket</filename>
and <filename>systemd-coredump@.service</filename> are helper units which do the actual
processing of core dumps and are subject to normal service management.</para>
<para>The behavior of a specific program upon reception of a signal is governed by a few
factors which are described in detail in
<citerefentry project='man-pages'><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
In particular, the core dump will only be processed when the related resource limits are sufficient.
</para>
<para>It is also possible to invoke <command>systemd-coredump</command> with
<option>--backtrace</option> option. In this case, <command>systemd-coredump</command> expects
a journal entry in the journal
<ulink url="http://www.freedesktop.org/wiki/Software/systemd/export">Journal Export Format</ulink>
on standard input. The entry should contain a <varname>MESSAGE=</varname> field and any additional
metadata fields the caller deems reasonable. <command>systemd-coredump</command> will append
additional metadata fields in the same way it does for core dumps received from the kernel. In
this mode, no core dump is stored in the journal.</para>
</refsect1>
<refsect1>
@ -91,7 +105,8 @@
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
<para>In order to be used <command>systemd-coredump</command> must be configured in
<para>In order to be used by the kernel to handle core dumps,
<command>systemd-coredump</command> must be configured in
<citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
parameter <varname>kernel.core_pattern</varname>. The syntax of this parameter is explained in
<citerefentry project='man-pages'><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
@ -99,14 +114,20 @@
<varname>kernel.core_pattern</varname> accordingly. This file may be masked or overridden to use a different
setting following normal
<citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
rules.
If the sysctl configuration is modified, it must be updated in the kernel before
it takes effect, see
rules. If the sysctl configuration is modified, it must be updated in the kernel before it
takes effect, see
<citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>systemd-sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
</para>
<para>In order to by used in the <option>--backtrace</option> mode, an appropriate backtrace
handler must be installed on the sender side. For example, in case of
<citerefentry><refentrytitle>python</refentrytitle><manvolnum>1</manvolnum></citerefentry>, this
means a <varname>sys.excepthook</varname> must installed, see
<ulink url="https://github.com/keszybz/systemd-coredump-python">systemd-coredump-python</ulink>.
</para>
<para>The behavior of <command>systemd-coredump</command> itself is configured through the configuration file
<filename>/etc/systemd/coredump.conf</filename> and corresponding snippets
<filename>/etc/systemd/coredump.conf.d/*.conf</filename>, see

View file

@ -0,0 +1,481 @@
/***
This file is part of systemd.
Copyright 2014 Zbigniew Jędrzejewski-Szmek
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/>.
***/
#include <unistd.h>
#include "alloc-util.h"
#include "journal-importer.h"
#include "fd-util.h"
#include "parse-util.h"
#include "string-util.h"
enum {
IMPORTER_STATE_LINE = 0, /* waiting to read, or reading line */
IMPORTER_STATE_DATA_START, /* reading binary data header */
IMPORTER_STATE_DATA, /* reading binary data */
IMPORTER_STATE_DATA_FINISH, /* expecting newline */
IMPORTER_STATE_EOF, /* done */
};
static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
return log_oom();
iovw->iovec[iovw->count++] = (struct iovec) {data, len};
return 0;
}
static void iovw_free_contents(struct iovec_wrapper *iovw) {
iovw->iovec = mfree(iovw->iovec);
iovw->size_bytes = iovw->count = 0;
}
static void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
size_t i;
for (i = 0; i < iovw->count; i++)
iovw->iovec[i].iov_base = (char*) iovw->iovec[i].iov_base - old + new;
}
size_t iovw_size(struct iovec_wrapper *iovw) {
size_t n = 0, i;
for (i = 0; i < iovw->count; i++)
n += iovw->iovec[i].iov_len;
return n;
}
void journal_importer_cleanup(JournalImporter *imp) {
if (imp->fd >= 0 && !imp->passive_fd) {
log_debug("Closing %s (fd=%d)", imp->name ?: "importer", imp->fd);
safe_close(imp->fd);
}
free(imp->buf);
iovw_free_contents(&imp->iovw);
}
static char* realloc_buffer(JournalImporter *imp, size_t size) {
char *b, *old = imp->buf;
b = GREEDY_REALLOC(imp->buf, imp->size, size);
if (!b)
return NULL;
iovw_rebase(&imp->iovw, old, imp->buf);
return b;
}
static int get_line(JournalImporter *imp, char **line, size_t *size) {
ssize_t n;
char *c = NULL;
assert(imp);
assert(imp->state == IMPORTER_STATE_LINE);
assert(imp->offset <= imp->filled);
assert(imp->filled <= imp->size);
assert(imp->buf == NULL || imp->size > 0);
assert(imp->fd >= 0);
for (;;) {
if (imp->buf) {
size_t start = MAX(imp->scanned, imp->offset);
c = memchr(imp->buf + start, '\n',
imp->filled - start);
if (c != NULL)
break;
}
imp->scanned = imp->filled;
if (imp->scanned >= DATA_SIZE_MAX) {
log_error("Entry is bigger than %u bytes.", DATA_SIZE_MAX);
return -E2BIG;
}
if (imp->passive_fd)
/* we have to wait for some data to come to us */
return -EAGAIN;
/* We know that imp->filled is at most DATA_SIZE_MAX, so if
we reallocate it, we'll increase the size at least a bit. */
assert_cc(DATA_SIZE_MAX < ENTRY_SIZE_MAX);
if (imp->size - imp->filled < LINE_CHUNK &&
!realloc_buffer(imp, MIN(imp->filled + LINE_CHUNK, ENTRY_SIZE_MAX)))
return log_oom();
assert(imp->buf);
assert(imp->size - imp->filled >= LINE_CHUNK ||
imp->size == ENTRY_SIZE_MAX);
n = read(imp->fd,
imp->buf + imp->filled,
imp->size - imp->filled);
if (n < 0) {
if (errno != EAGAIN)
log_error_errno(errno, "read(%d, ..., %zu): %m",
imp->fd,
imp->size - imp->filled);
return -errno;
} else if (n == 0)
return 0;
imp->filled += n;
}
*line = imp->buf + imp->offset;
*size = c + 1 - imp->buf - imp->offset;
imp->offset += *size;
return 1;
}
static int fill_fixed_size(JournalImporter *imp, void **data, size_t size) {
assert(imp);
assert(imp->state == IMPORTER_STATE_DATA_START ||
imp->state == IMPORTER_STATE_DATA ||
imp->state == IMPORTER_STATE_DATA_FINISH);
assert(size <= DATA_SIZE_MAX);
assert(imp->offset <= imp->filled);
assert(imp->filled <= imp->size);
assert(imp->buf != NULL || imp->size == 0);
assert(imp->buf == NULL || imp->size > 0);
assert(imp->fd >= 0);
assert(data);
while (imp->filled - imp->offset < size) {
int n;
if (imp->passive_fd)
/* we have to wait for some data to come to us */
return -EAGAIN;
if (!realloc_buffer(imp, imp->offset + size))
return log_oom();
n = read(imp->fd, imp->buf + imp->filled,
imp->size - imp->filled);
if (n < 0) {
if (errno != EAGAIN)
log_error_errno(errno, "read(%d, ..., %zu): %m", imp->fd,
imp->size - imp->filled);
return -errno;
} else if (n == 0)
return 0;
imp->filled += n;
}
*data = imp->buf + imp->offset;
imp->offset += size;
return 1;
}
static int get_data_size(JournalImporter *imp) {
int r;
void *data;
assert(imp);
assert(imp->state == IMPORTER_STATE_DATA_START);
assert(imp->data_size == 0);
r = fill_fixed_size(imp, &data, sizeof(uint64_t));
if (r <= 0)
return r;
imp->data_size = le64toh( *(uint64_t *) data );
if (imp->data_size > DATA_SIZE_MAX) {
log_error("Stream declares field with size %zu > DATA_SIZE_MAX = %u",
imp->data_size, DATA_SIZE_MAX);
return -EINVAL;
}
if (imp->data_size == 0)
log_warning("Binary field with zero length");
return 1;
}
static int get_data_data(JournalImporter *imp, void **data) {
int r;
assert(imp);
assert(data);
assert(imp->state == IMPORTER_STATE_DATA);
r = fill_fixed_size(imp, data, imp->data_size);
if (r <= 0)
return r;
return 1;
}
static int get_data_newline(JournalImporter *imp) {
int r;
char *data;
assert(imp);
assert(imp->state == IMPORTER_STATE_DATA_FINISH);
r = fill_fixed_size(imp, (void**) &data, 1);
if (r <= 0)
return r;
assert(data);
if (*data != '\n') {
log_error("expected newline, got '%c'", *data);
return -EINVAL;
}
return 1;
}
static int process_dunder(JournalImporter *imp, char *line, size_t n) {
const char *timestamp;
int r;
assert(line);
assert(n > 0);
assert(line[n-1] == '\n');
/* XXX: is it worth to support timestamps in extended format?
* We don't produce them, but who knows... */
timestamp = startswith(line, "__CURSOR=");
if (timestamp)
/* ignore __CURSOR */
return 1;
timestamp = startswith(line, "__REALTIME_TIMESTAMP=");
if (timestamp) {
long long unsigned x;
line[n-1] = '\0';
r = safe_atollu(timestamp, &x);
if (r < 0)
log_warning("Failed to parse __REALTIME_TIMESTAMP: '%s'", timestamp);
else
imp->ts.realtime = x;
return r < 0 ? r : 1;
}
timestamp = startswith(line, "__MONOTONIC_TIMESTAMP=");
if (timestamp) {
long long unsigned x;
line[n-1] = '\0';
r = safe_atollu(timestamp, &x);
if (r < 0)
log_warning("Failed to parse __MONOTONIC_TIMESTAMP: '%s'", timestamp);
else
imp->ts.monotonic = x;
return r < 0 ? r : 1;
}
timestamp = startswith(line, "__");
if (timestamp) {
log_notice("Unknown dunder line %s", line);
return 1;
}
/* no dunder */
return 0;
}
int journal_importer_process_data(JournalImporter *imp) {
int r;
switch(imp->state) {
case IMPORTER_STATE_LINE: {
char *line, *sep;
size_t n = 0;
assert(imp->data_size == 0);
r = get_line(imp, &line, &n);
if (r < 0)
return r;
if (r == 0) {
imp->state = IMPORTER_STATE_EOF;
return r;
}
assert(n > 0);
assert(line[n-1] == '\n');
if (n == 1) {
log_trace("Received empty line, event is ready");
return 1;
}
r = process_dunder(imp, line, n);
if (r != 0)
return r < 0 ? r : 0;
/* MESSAGE=xxx\n
or
COREDUMP\n
LLLLLLLL0011223344...\n
*/
sep = memchr(line, '=', n);
if (sep) {
/* chomp newline */
n--;
r = iovw_put(&imp->iovw, line, n);
if (r < 0)
return r;
} else {
/* replace \n with = */
line[n-1] = '=';
imp->field_len = n;
imp->state = IMPORTER_STATE_DATA_START;
/* we cannot put the field in iovec until we have all data */
}
log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary");
return 0; /* continue */
}
case IMPORTER_STATE_DATA_START:
assert(imp->data_size == 0);
r = get_data_size(imp);
// log_debug("get_data_size() -> %d", r);
if (r < 0)
return r;
if (r == 0) {
imp->state = IMPORTER_STATE_EOF;
return 0;
}
imp->state = imp->data_size > 0 ?
IMPORTER_STATE_DATA : IMPORTER_STATE_DATA_FINISH;
return 0; /* continue */
case IMPORTER_STATE_DATA: {
void *data;
char *field;
assert(imp->data_size > 0);
r = get_data_data(imp, &data);
// log_debug("get_data_data() -> %d", r);
if (r < 0)
return r;
if (r == 0) {
imp->state = IMPORTER_STATE_EOF;
return 0;
}
assert(data);
field = (char*) data - sizeof(uint64_t) - imp->field_len;
memmove(field + sizeof(uint64_t), field, imp->field_len);
r = iovw_put(&imp->iovw, field + sizeof(uint64_t), imp->field_len + imp->data_size);
if (r < 0)
return r;
imp->state = IMPORTER_STATE_DATA_FINISH;
return 0; /* continue */
}
case IMPORTER_STATE_DATA_FINISH:
r = get_data_newline(imp);
// log_debug("get_data_newline() -> %d", r);
if (r < 0)
return r;
if (r == 0) {
imp->state = IMPORTER_STATE_EOF;
return 0;
}
imp->data_size = 0;
imp->state = IMPORTER_STATE_LINE;
return 0; /* continue */
default:
assert_not_reached("wtf?");
}
}
int journal_importer_push_data(JournalImporter *imp, const char *data, size_t size) {
assert(imp);
assert(imp->state != IMPORTER_STATE_EOF);
if (!realloc_buffer(imp, imp->filled + size)) {
log_error("Failed to store received data of size %zu "
"(in addition to existing %zu bytes with %zu filled): %s",
size, imp->size, imp->filled, strerror(ENOMEM));
return -ENOMEM;
}
memcpy(imp->buf + imp->filled, data, size);
imp->filled += size;
return 0;
}
void journal_importer_drop_iovw(JournalImporter *imp) {
size_t remain, target;
/* This function drops processed data that along with the iovw that points at it */
iovw_free_contents(&imp->iovw);
/* possibly reset buffer position */
remain = imp->filled - imp->offset;
if (remain == 0) /* no brainer */
imp->offset = imp->scanned = imp->filled = 0;
else if (imp->offset > imp->size - imp->filled &&
imp->offset > remain) {
memcpy(imp->buf, imp->buf + imp->offset, remain);
imp->offset = imp->scanned = 0;
imp->filled = remain;
}
target = imp->size;
while (target > 16 * LINE_CHUNK && imp->filled < target / 2)
target /= 2;
if (target < imp->size) {
char *tmp;
tmp = realloc(imp->buf, target);
if (!tmp)
log_warning("Failed to reallocate buffer to (smaller) size %zu",
target);
else {
log_debug("Reallocated buffer from %zu to %zu bytes",
imp->size, target);
imp->buf = tmp;
imp->size = target;
}
}
}
bool journal_importer_eof(const JournalImporter *imp) {
return imp->state == IMPORTER_STATE_EOF;
}

View file

@ -0,0 +1,70 @@
/***
This file is part of systemd.
Copyright 2016 Zbigniew Jędrzejewski-Szmek
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/>.
***/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include <sys/uio.h>
#include "time-util.h"
/* Make sure not to make this smaller than the maximum coredump size.
* See COREDUMP_MAX in coredump.c */
#define ENTRY_SIZE_MAX (1024*1024*770u)
#define DATA_SIZE_MAX (1024*1024*768u)
#define LINE_CHUNK 8*1024u
struct iovec_wrapper {
struct iovec *iovec;
size_t size_bytes;
size_t count;
};
size_t iovw_size(struct iovec_wrapper *iovw);
typedef struct JournalImporter {
int fd;
bool passive_fd;
char *name;
char *buf;
size_t size; /* total size of the buffer */
size_t offset; /* offset to the beginning of live data in the buffer */
size_t scanned; /* number of bytes since the beginning of data without a newline */
size_t filled; /* total number of bytes in the buffer */
size_t field_len; /* used for binary fields: the field name length */
size_t data_size; /* and the size of the binary data chunk being processed */
struct iovec_wrapper iovw;
int state;
dual_timestamp ts;
} JournalImporter;
void journal_importer_cleanup(JournalImporter *);
int journal_importer_process_data(JournalImporter *);
int journal_importer_push_data(JournalImporter *, const char *data, size_t size);
void journal_importer_drop_iovw(JournalImporter *);
bool journal_importer_eof(const JournalImporter *);
static inline size_t journal_importer_bytes_remaining(const JournalImporter *imp) {
return imp->filled;
}

View file

@ -1164,7 +1164,7 @@ int log_syntax_internal(
return log_struct_internal(
level, error,
file, line, func,
LOG_MESSAGE_ID(SD_MESSAGE_INVALID_CONFIGURATION),
"MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
"CONFIG_FILE=%s", config_file,
"CONFIG_LINE=%u", config_line,
LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),

View file

@ -214,9 +214,8 @@ bool log_on_console(void) _pure_;
const char *log_target_to_string(LogTarget target) _const_;
LogTarget log_target_from_string(const char *s) _pure_;
/* Helpers to prepare various fields for structured logging */
/* Helper to prepare various field for structured logging */
#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x)
void log_received_signal(int level, const struct signalfd_siginfo *si);

View file

@ -2981,7 +2981,7 @@ int exec_spawn(Unit *unit,
log_open();
if (error_message)
log_struct_errno(LOG_ERR, r,
LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
LOG_UNIT_MESSAGE(unit, "%s: %m",
error_message),
@ -2989,7 +2989,7 @@ int exec_spawn(Unit *unit,
NULL);
else
log_struct_errno(LOG_ERR, r,
LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),

View file

@ -746,9 +746,8 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
}
static void job_log_status_message(Unit *u, JobType t, JobResult result) {
const char *format;
const char *format, *mid;
char buf[LINE_MAX];
sd_id128_t mid;
static const int job_result_log_level[_JOB_RESULT_MAX] = {
[JOB_DONE] = LOG_INFO,
[JOB_CANCELED] = LOG_INFO,
@ -784,16 +783,19 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
switch (t) {
case JOB_START:
mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
if (result == JOB_DONE)
mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR;
else
mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_FAILED_STR;
break;
case JOB_RELOAD:
mid = SD_MESSAGE_UNIT_RELOADED;
mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADED_STR;
break;
case JOB_STOP:
case JOB_RESTART:
mid = SD_MESSAGE_UNIT_STOPPED;
mid = "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPED_STR;
break;
default:
@ -806,7 +808,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
}
log_struct(job_result_log_level[result],
LOG_MESSAGE_ID(mid),
mid,
LOG_UNIT_ID(u),
LOG_MESSAGE("%s", buf),
"RESULT=%s", job_result_to_string(result),

View file

@ -2171,7 +2171,7 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint
assert(m->time_change_fd == fd);
log_struct(LOG_DEBUG,
LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
"MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
LOG_MESSAGE("Time has been changed"),
NULL);
@ -2930,7 +2930,7 @@ static void manager_notify_finished(Manager *m) {
initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
"KERNEL_USEC="USEC_FMT, kernel_usec,
"INITRD_USEC="USEC_FMT, initrd_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
@ -2945,7 +2945,7 @@ static void manager_notify_finished(Manager *m) {
initrd_usec = 0;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
"KERNEL_USEC="USEC_FMT, kernel_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s (kernel) + %s (userspace) = %s.",
@ -2959,7 +2959,7 @@ static void manager_notify_finished(Manager *m) {
total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_USER_STARTUP_FINISHED),
"MESSAGE_ID=" SD_MESSAGE_USER_STARTUP_FINISHED_STR,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),

View file

@ -1466,9 +1466,8 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) {
}
static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
const char *format;
const char *format, *mid;
char buf[LINE_MAX];
sd_id128_t mid;
assert(u);
@ -1486,9 +1485,9 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
snprintf(buf, sizeof buf, format, unit_description(u));
REENABLE_WARNING;
mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING :
t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING :
SD_MESSAGE_UNIT_RELOADING;
mid = t == JOB_START ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTING_STR :
t == JOB_STOP ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STOPPING_STR :
"MESSAGE_ID=" SD_MESSAGE_UNIT_RELOADING_STR;
/* Note that we deliberately use LOG_MESSAGE() instead of
* LOG_UNIT_MESSAGE() here, since this is supposed to mimic
@ -1497,7 +1496,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
* possible, which means we should avoid the low-level unit
* name. */
log_struct(LOG_INFO,
LOG_MESSAGE_ID(mid),
mid,
LOG_UNIT_ID(u),
LOG_MESSAGE("%s", buf),
NULL);
@ -4069,7 +4068,7 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
}
log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
"MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
LOG_UNIT_ID(u),
LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where),
"WHERE=%s", where,
@ -4091,7 +4090,7 @@ int unit_fail_if_symlink(Unit *u, const char* where) {
return 0;
log_struct(LOG_ERR,
LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
"MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
LOG_UNIT_ID(u),
LOG_UNIT_MESSAGE(u, "Mount on symlink %s not allowed.", where),
"WHERE=%s", where,

View file

@ -47,7 +47,7 @@
#include "fileio.h"
#include "fs-util.h"
#include "io-util.h"
#include "journald-native.h"
#include "journal-importer.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
@ -360,7 +360,7 @@ static int save_external_coredump(
log_struct(LOG_INFO,
LOG_MESSAGE("Core file was truncated to %zu bytes.", max_size),
"SIZE_LIMIT=%zu", max_size,
LOG_MESSAGE_ID(SD_MESSAGE_TRUNCATED_CORE),
"MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR,
NULL);
if (fstat(fd, &st) < 0) {
@ -820,7 +820,7 @@ static void map_context_fields(const struct iovec *iovec, const char *context[])
static int process_socket(int fd) {
_cleanup_close_ int coredump_fd = -1;
struct iovec *iovec = NULL;
size_t n_iovec = 0, n_iovec_allocated = 0, i;
size_t n_iovec = 0, n_allocated = 0, i;
const char *context[_CONTEXT_MAX] = {};
int r;
@ -830,6 +830,8 @@ static int process_socket(int fd) {
log_parse_environment();
log_open();
log_debug("Processing coredump received on stdin...");
for (;;) {
union {
struct cmsghdr cmsghdr;
@ -843,7 +845,7 @@ static int process_socket(int fd) {
ssize_t n;
ssize_t l;
if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) {
if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + 3)) {
r = log_oom();
goto finish;
}
@ -907,7 +909,7 @@ static int process_socket(int fd) {
n_iovec++;
}
if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) {
if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + 3)) {
r = log_oom();
goto finish;
}
@ -922,7 +924,7 @@ static int process_socket(int fd) {
assert(context[CONTEXT_COMM]);
assert(coredump_fd >= 0);
r = submit_coredump(context, iovec, n_iovec_allocated, n_iovec, coredump_fd);
r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd);
finish:
for (i = 0; i < n_iovec; i++)
@ -1025,45 +1027,47 @@ static int process_special_crash(const char *context[], int input_fd) {
return 0;
}
static int process_kernel(int argc, char* argv[]) {
static char* set_iovec_field(struct iovec iovec[27], size_t *n_iovec, const char *field, const char *value) {
char *x;
/* The small core field we allocate on the stack, to keep things simple */
char
*core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
*core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL,
*core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL,
*core_user_unit = NULL, *core_slice = NULL, *core_timestamp = NULL, *core_rlimit = NULL;
x = strappend(field, value);
if (x)
IOVEC_SET_STRING(iovec[(*n_iovec)++], x);
return x;
}
/* The larger ones we allocate on the heap */
_cleanup_free_ char
*core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL,
*core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL,
*core_proc_mountinfo = NULL, *core_container_cmdline = NULL;
static char* set_iovec_field_free(struct iovec iovec[27], size_t *n_iovec, const char *field, char *value) {
char *x;
x = set_iovec_field(iovec, n_iovec, field, value);
free(value);
return x;
}
static int gather_pid_metadata(
const char *context[_CONTEXT_MAX],
char **comm_fallback,
char **comm_ret,
struct iovec *iovec, size_t *n_iovec) {
/* We need 25 empty slots in iovec!
* Note that if we fail on oom later on, we do not roll-back changes to the iovec
* structure. (It remains valid, with the first n_iovec fields initialized.) */
_cleanup_free_ char *exe = NULL, *comm = NULL;
const char *context[_CONTEXT_MAX];
bool proc_self_root_is_slash;
struct iovec iovec[27];
size_t n_iovec = 0;
uid_t owner_uid;
const char *p;
pid_t pid;
char *t;
const char *p;
int r;
if (argc < CONTEXT_COMM + 1) {
log_error("Not enough arguments passed from kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
return -EINVAL;
}
r = parse_pid(argv[CONTEXT_PID + 1], &pid);
r = parse_pid(context[CONTEXT_PID], &pid);
if (r < 0)
return log_error_errno(r, "Failed to parse PID.");
return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]);
r = get_process_comm(pid, &comm);
if (r < 0) {
log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m");
comm = strv_join(argv + CONTEXT_COMM + 1, " ");
comm = strv_join(comm_fallback, " ");
if (!comm)
return log_oom();
}
@ -1072,15 +1076,6 @@ static int process_kernel(int argc, char* argv[]) {
if (r < 0)
log_warning_errno(r, "Failed to get EXE, ignoring: %m");
context[CONTEXT_PID] = argv[CONTEXT_PID + 1];
context[CONTEXT_UID] = argv[CONTEXT_UID + 1];
context[CONTEXT_GID] = argv[CONTEXT_GID + 1];
context[CONTEXT_SIGNAL] = argv[CONTEXT_SIGNAL + 1];
context[CONTEXT_TIMESTAMP] = argv[CONTEXT_TIMESTAMP + 1];
context[CONTEXT_RLIMIT] = argv[CONTEXT_RLIMIT + 1];
context[CONTEXT_COMM] = comm;
context[CONTEXT_EXE] = exe;
if (cg_pid_get_unit(pid, &t) >= 0) {
/* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */
@ -1096,186 +1091,238 @@ static int process_kernel(int argc, char* argv[]) {
return process_special_crash(context, STDIN_FILENO);
}
core_unit = strjoina("COREDUMP_UNIT=", t);
free(t);
IOVEC_SET_STRING(iovec[n_iovec++], core_unit);
set_iovec_field_free(iovec, n_iovec, "COREDUMP_UNIT=", t);
}
/* OK, now we know it's not the journal, hence we can make use of it now. */
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_open();
if (cg_pid_get_user_unit(pid, &t) >= 0) {
core_user_unit = strjoina("COREDUMP_USER_UNIT=", t);
free(t);
if (cg_pid_get_user_unit(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t);
IOVEC_SET_STRING(iovec[n_iovec++], core_user_unit);
}
/* The next few are mandatory */
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
return log_oom();
core_pid = strjoina("COREDUMP_PID=", context[CONTEXT_PID]);
IOVEC_SET_STRING(iovec[n_iovec++], core_pid);
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
return log_oom();
core_uid = strjoina("COREDUMP_UID=", context[CONTEXT_UID]);
IOVEC_SET_STRING(iovec[n_iovec++], core_uid);
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
return log_oom();
core_gid = strjoina("COREDUMP_GID=", context[CONTEXT_GID]);
IOVEC_SET_STRING(iovec[n_iovec++], core_gid);
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
return log_oom();
core_signal = strjoina("COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]);
IOVEC_SET_STRING(iovec[n_iovec++], core_signal);
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
return log_oom();
core_rlimit = strjoina("COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]);
IOVEC_SET_STRING(iovec[n_iovec++], core_rlimit);
if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", comm))
return log_oom();
if (sd_pid_get_session(pid, &t) >= 0) {
core_session = strjoina("COREDUMP_SESSION=", t);
free(t);
if (exe &&
!set_iovec_field(iovec, n_iovec, "COREDUMP_EXE=", exe))
return log_oom();
IOVEC_SET_STRING(iovec[n_iovec++], core_session);
}
if (sd_pid_get_session(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_SESSION=", t);
if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
r = asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
r = asprintf(&t, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
if (r > 0)
IOVEC_SET_STRING(iovec[n_iovec++], core_owner_uid);
IOVEC_SET_STRING(iovec[(*n_iovec)++], t);
}
if (sd_pid_get_slice(pid, &t) >= 0) {
core_slice = strjoina("COREDUMP_SLICE=", t);
free(t);
if (sd_pid_get_slice(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_SLICE=", t);
IOVEC_SET_STRING(iovec[n_iovec++], core_slice);
}
if (get_process_cmdline(pid, 0, false, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CMDLINE=", t);
if (comm) {
core_comm = strjoina("COREDUMP_COMM=", comm);
IOVEC_SET_STRING(iovec[n_iovec++], core_comm);
}
if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CGROUP=", t);
if (exe) {
core_exe = strjoina("COREDUMP_EXE=", exe);
IOVEC_SET_STRING(iovec[n_iovec++], core_exe);
}
if (get_process_cmdline(pid, 0, false, &t) >= 0) {
core_cmdline = strjoina("COREDUMP_CMDLINE=", t);
free(t);
IOVEC_SET_STRING(iovec[n_iovec++], core_cmdline);
}
if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
core_cgroup = strjoina("COREDUMP_CGROUP=", t);
free(t);
IOVEC_SET_STRING(iovec[n_iovec++], core_cgroup);
}
if (compose_open_fds(pid, &t) >= 0) {
core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
free(t);
if (core_open_fds)
IOVEC_SET_STRING(iovec[n_iovec++], core_open_fds);
}
if (compose_open_fds(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_OPEN_FDS=", t);
p = procfs_file_alloca(pid, "status");
if (read_full_file(p, &t, NULL) >= 0) {
core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
free(t);
if (core_proc_status)
IOVEC_SET_STRING(iovec[n_iovec++], core_proc_status);
}
if (read_full_file(p, &t, NULL) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_STATUS=", t);
p = procfs_file_alloca(pid, "maps");
if (read_full_file(p, &t, NULL) >= 0) {
core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
free(t);
if (core_proc_maps)
IOVEC_SET_STRING(iovec[n_iovec++], core_proc_maps);
}
if (read_full_file(p, &t, NULL) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MAPS=", t);
p = procfs_file_alloca(pid, "limits");
if (read_full_file(p, &t, NULL) >= 0) {
core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
free(t);
if (core_proc_limits)
IOVEC_SET_STRING(iovec[n_iovec++], core_proc_limits);
}
if (read_full_file(p, &t, NULL) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_LIMITS=", t);
p = procfs_file_alloca(pid, "cgroup");
if (read_full_file(p, &t, NULL) >=0) {
core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
free(t);
if (core_proc_cgroup)
IOVEC_SET_STRING(iovec[n_iovec++], core_proc_cgroup);
}
if (read_full_file(p, &t, NULL) >=0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_CGROUP=", t);
p = procfs_file_alloca(pid, "mountinfo");
if (read_full_file(p, &t, NULL) >=0) {
core_proc_mountinfo = strappend("COREDUMP_PROC_MOUNTINFO=", t);
free(t);
if (read_full_file(p, &t, NULL) >=0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t);
if (core_proc_mountinfo)
IOVEC_SET_STRING(iovec[n_iovec++], core_proc_mountinfo);
}
if (get_process_cwd(pid, &t) >= 0) {
core_cwd = strjoina("COREDUMP_CWD=", t);
free(t);
IOVEC_SET_STRING(iovec[n_iovec++], core_cwd);
}
if (get_process_cwd(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t);
if (get_process_root(pid, &t) >= 0) {
core_root = strjoina("COREDUMP_ROOT=", t);
bool proc_self_root_is_slash;
IOVEC_SET_STRING(iovec[n_iovec++], core_root);
proc_self_root_is_slash = strcmp(t, "/") == 0;
set_iovec_field_free(iovec, n_iovec, "COREDUMP_ROOT=", t);
/* If the process' root is "/", then there is a chance it has
* mounted own root and hence being containerized. */
proc_self_root_is_slash = strcmp(t, "/") == 0;
free(t);
if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0) {
core_container_cmdline = strappend("COREDUMP_CONTAINER_CMDLINE=", t);
free(t);
if (core_container_cmdline)
IOVEC_SET_STRING(iovec[n_iovec++], core_container_cmdline);
}
if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CONTAINER_CMDLINE=", t);
}
if (get_process_environ(pid, &t) >= 0) {
core_environ = strappend("COREDUMP_ENVIRON=", t);
free(t);
if (get_process_environ(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t);
if (core_environ)
IOVEC_SET_STRING(iovec[n_iovec++], core_environ);
t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL);
if (t)
IOVEC_SET_STRING(iovec[(*n_iovec)++], t);
if (comm_ret) {
*comm_ret = comm;
comm = NULL;
}
core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp);
return 0;
}
IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
static int process_kernel(int argc, char* argv[]) {
const char *context[_CONTEXT_MAX];
struct iovec iovec[27];
size_t i, n_iovec, n_to_free = 0;
int r;
log_debug("Processing coredump received from the kernel...");
if (argc < CONTEXT_COMM + 1) {
log_error("Not enough arguments passed by the kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
return -EINVAL;
}
context[CONTEXT_PID] = argv[CONTEXT_PID + 1];
context[CONTEXT_UID] = argv[CONTEXT_UID + 1];
context[CONTEXT_GID] = argv[CONTEXT_GID + 1];
context[CONTEXT_SIGNAL] = argv[CONTEXT_SIGNAL + 1];
context[CONTEXT_TIMESTAMP] = argv[CONTEXT_TIMESTAMP + 1];
context[CONTEXT_RLIMIT] = argv[CONTEXT_RLIMIT + 1];
r = gather_pid_metadata(context, argv + CONTEXT_COMM + 1, NULL, iovec, &n_to_free);
if (r < 0)
goto finish;
n_iovec = n_to_free;
IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
assert_cc(2 == LOG_CRIT);
IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2");
assert(n_iovec <= ELEMENTSOF(iovec));
return send_iovec(iovec, n_iovec, STDIN_FILENO);
r = send_iovec(iovec, n_iovec, STDIN_FILENO);
finish:
for (i = 0; i < n_to_free; i++)
free(iovec[i].iov_base);
return r;
}
static int process_backtrace(int argc, char *argv[]) {
const char *context[_CONTEXT_MAX];
_cleanup_free_ char *comm = NULL, *message = NULL;
_cleanup_free_ struct iovec *iovec = NULL;
size_t n_iovec, n_allocated, n_to_free = 0, i;
int r;
JournalImporter importer = {
.fd = STDIN_FILENO,
};
log_debug("Processing backtrace on stdin...");
if (argc < CONTEXT_COMM + 1) {
log_error("Not enough arguments passed (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
return -EINVAL;
}
context[CONTEXT_PID] = argv[CONTEXT_PID + 2];
context[CONTEXT_UID] = argv[CONTEXT_UID + 2];
context[CONTEXT_GID] = argv[CONTEXT_GID + 2];
context[CONTEXT_SIGNAL] = argv[CONTEXT_SIGNAL + 2];
context[CONTEXT_TIMESTAMP] = argv[CONTEXT_TIMESTAMP + 2];
context[CONTEXT_RLIMIT] = argv[CONTEXT_RLIMIT + 2];
n_allocated = 32; /* 25 metadata, 2 static, +unknown input, rounded up */
iovec = new(struct iovec, n_allocated);
if (!iovec)
return log_oom();
r = gather_pid_metadata(context, argv + CONTEXT_COMM + 2, &comm, iovec, &n_to_free);
if (r < 0)
goto finish;
n_iovec = n_to_free;
while (true) {
r = journal_importer_process_data(&importer);
if (r < 0) {
log_error_errno(r, "Failed to parse journal entry on stdin: %m");
goto finish;
}
if (r == 1)
break;
}
if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + importer.iovw.count + 2))
return log_oom();
if (journal_importer_eof(&importer)) {
log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter");
message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], " (", comm, ")"
" of user ", context[CONTEXT_UID],
" failed with ", context[CONTEXT_SIGNAL]);
if (!message) {
r = log_oom();
goto finish;
}
IOVEC_SET_STRING(iovec[n_iovec++], message);
} else {
for (i = 0; i < importer.iovw.count; i++)
iovec[n_iovec++] = importer.iovw.iovec[i];
}
IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
assert_cc(2 == LOG_CRIT);
IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2");
assert(n_iovec <= n_allocated);
r = sd_journal_sendv(iovec, n_iovec);
if (r < 0)
log_error_errno(r, "Failed to log backtrace: %m");
finish:
for (i = 0; i < n_to_free; i++)
free(iovec[i].iov_base);
return r;
}
int main(int argc, char *argv[]) {
int r;
/* First, log to a safe place, since we don't know what crashed and it might be journald which we'd rather not
* log to then. */
/* First, log to a safe place, since we don't know what crashed and it might
* be journald which we'd rather not log to then. */
log_set_target(LOG_TARGET_KMSG);
log_open();
@ -1295,11 +1342,14 @@ int main(int argc, char *argv[]) {
goto finish;
}
/* If we got an fd passed, we are running in coredumpd mode. Otherwise we are invoked from the kernel as
* coredump handler */
if (r == 0)
r = process_kernel(argc, argv);
else if (r == 1)
/* If we got an fd passed, we are running in coredumpd mode. Otherwise we
* are invoked from the kernel as coredump handler. */
if (r == 0) {
if (streq_ptr(argv[1], "--backtrace"))
r = process_backtrace(argc, argv);
else
r = process_kernel(argc, argv);
} else if (r == 1)
r = process_socket(SD_LISTEN_FDS_START);
else {
log_error("Received unexpected number of file descriptors.");

View file

@ -25,6 +25,7 @@
#include <unistd.h>
#include "sd-journal.h"
#include "sd-messages.h"
#include "alloc-util.h"
#include "compress.h"
@ -38,10 +39,10 @@
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "set.h"
#include "sigbus.h"
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "user-util.h"
#include "util.h"
@ -60,36 +61,9 @@ static int arg_no_legend = false;
static int arg_one = false;
static FILE* arg_output = NULL;
static bool arg_reverse = false;
static char** arg_matches = NULL;
static Set *new_matches(void) {
Set *set;
char *tmp;
int r;
set = set_new(NULL);
if (!set) {
log_oom();
return NULL;
}
tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
if (!tmp) {
log_oom();
set_free(set);
return NULL;
}
r = set_consume(set, tmp);
if (r < 0) {
log_error_errno(r, "failed to add to set: %m");
set_free(set);
return NULL;
}
return set;
}
static int add_match(Set *set, const char *match) {
static int add_match(sd_journal *j, const char *match) {
_cleanup_free_ char *p = NULL;
char *pattern = NULL;
const char* prefix;
@ -101,7 +75,8 @@ static int add_match(Set *set, const char *match) {
else if (strchr(match, '/')) {
r = path_make_absolute_cwd(match, &p);
if (r < 0)
goto fail;
return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match);
match = p;
prefix = "COREDUMP_EXE=";
} else if (parse_pid(match, &pid) >= 0)
@ -110,19 +85,35 @@ static int add_match(Set *set, const char *match) {
prefix = "COREDUMP_COMM=";
pattern = strjoin(prefix, match);
if (!pattern) {
r = -ENOMEM;
goto fail;
if (!pattern)
return log_oom();
log_debug("Adding match: %s", pattern);
r = sd_journal_add_match(j, pattern, 0);
if (r < 0)
return log_error_errno(r, "Failed to add match \"%s\": %m", match);
return 0;
}
static int add_matches(sd_journal *j) {
char **match;
int r;
r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0);
if (r < 0)
return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR, 0);
if (r < 0)
return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
STRV_FOREACH(match, arg_matches) {
r = add_match(j, *match);
if (r < 0)
return r;
}
log_debug("Adding pattern: %s", pattern);
r = set_consume(set, pattern);
if (r < 0)
goto fail;
return 0;
fail:
return log_error_errno(r, "Failed to add match: %m");
}
static void help(void) {
@ -147,14 +138,14 @@ static void help(void) {
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[], Set *matches) {
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
};
int r, c;
int c;
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
@ -251,12 +242,8 @@ static int parse_argv(int argc, char *argv[], Set *matches) {
return -EINVAL;
}
while (optind < argc) {
r = add_match(matches, argv[optind]);
if (r != 0)
return r;
optind++;
}
if (optind < argc)
arg_matches = argv + optind;
return 0;
}
@ -329,7 +316,7 @@ static int print_field(FILE* file, sd_journal *j) {
static int print_list(FILE* file, sd_journal *j, int had_legend) {
_cleanup_free_ char
*pid = NULL, *uid = NULL, *gid = NULL,
*mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
*sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
*filename = NULL, *coredump = NULL;
const void *d;
@ -338,11 +325,13 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) {
char buf[FORMAT_TIMESTAMP_MAX];
int r;
const char *present;
bool normal_coredump;
assert(file);
assert(j);
SD_JOURNAL_FOREACH_DATA(j, d, l) {
RETRIEVE(d, l, "MESSAGE_ID", mid);
RETRIEVE(d, l, "COREDUMP_PID", pid);
RETRIEVE(d, l, "COREDUMP_UID", uid);
RETRIEVE(d, l, "COREDUMP_GID", gid);
@ -375,6 +364,8 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) {
8, "COREFILE",
"EXE");
normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
if (filename)
if (access(filename, R_OK) == 0)
present = "present";
@ -384,15 +375,17 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) {
present = "error";
else if (coredump)
present = "journal";
else
else if (normal_coredump)
present = "none";
else
present = "-";
fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n",
FORMAT_TIMESTAMP_WIDTH, buf,
6, strna(pid),
5, strna(uid),
5, strna(gid),
3, strna(sgnl),
3, normal_coredump ? strna(sgnl) : "-",
8, present,
strna(exe ?: (comm ?: cmdline)));
@ -401,7 +394,7 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) {
static int print_info(FILE *file, sd_journal *j, bool need_space) {
_cleanup_free_ char
*pid = NULL, *uid = NULL, *gid = NULL,
*mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
*sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
*unit = NULL, *user_unit = NULL, *session = NULL,
*boot_id = NULL, *machine_id = NULL, *hostname = NULL,
@ -410,12 +403,14 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
*coredump = NULL;
const void *d;
size_t l;
bool normal_coredump;
int r;
assert(file);
assert(j);
SD_JOURNAL_FOREACH_DATA(j, d, l) {
RETRIEVE(d, l, "MESSAGE_ID", mid);
RETRIEVE(d, l, "COREDUMP_PID", pid);
RETRIEVE(d, l, "COREDUMP_UID", uid);
RETRIEVE(d, l, "COREDUMP_GID", gid);
@ -441,6 +436,8 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
if (need_space)
fputs("\n", file);
normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
if (comm)
fprintf(file,
" PID: %s%s%s (%s)\n",
@ -486,11 +483,12 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
if (sgnl) {
int sig;
const char *name = normal_coredump ? "Signal" : "Reason";
if (safe_atoi(sgnl, &sig) >= 0)
fprintf(file, " Signal: %s (%s)\n", sgnl, signal_to_string(sig));
if (normal_coredump && safe_atoi(sgnl, &sig) >= 0)
fprintf(file, " %s: %s (%s)\n", name, sgnl, signal_to_string(sig));
else
fprintf(file, " Signal: %s\n", sgnl);
fprintf(file, " %s: %s\n", name, sgnl);
}
if (timestamp) {
@ -875,22 +873,13 @@ finish:
int main(int argc, char *argv[]) {
_cleanup_(sd_journal_closep) sd_journal*j = NULL;
const char* match;
Iterator it;
int r = 0;
_cleanup_set_free_free_ Set *matches = NULL;
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
matches = new_matches();
if (!matches) {
r = -ENOMEM;
goto end;
}
r = parse_argv(argc, argv, matches);
r = parse_argv(argc, argv);
if (r < 0)
goto end;
@ -913,14 +902,9 @@ int main(int argc, char *argv[]) {
}
}
SET_FOREACH(match, matches, it) {
r = sd_journal_add_match(j, match, strlen(match));
if (r != 0) {
log_error_errno(r, "Failed to add match '%s': %m",
match);
goto end;
}
}
r = add_matches(j);
if (r < 0)
goto end;
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
_cleanup_free_ char *filter;

View file

@ -24,20 +24,11 @@
#include "parse-util.h"
#include "string-util.h"
#define LINE_CHUNK 8*1024u
void source_free(RemoteSource *source) {
if (!source)
return;
if (source->fd >= 0 && !source->passive_fd) {
log_debug("Closing fd:%d (%s)", source->fd, source->name);
safe_close(source->fd);
}
free(source->name);
free(source->buf);
iovw_free_contents(&source->iovw);
journal_importer_cleanup(&source->importer);
log_debug("Writer ref count %i", source->writer->n_ref);
writer_unref(source->writer);
@ -65,442 +56,44 @@ RemoteSource* source_new(int fd, bool passive_fd, char *name, Writer *writer) {
if (!source)
return NULL;
source->fd = fd;
source->passive_fd = passive_fd;
source->name = name;
source->importer.fd = fd;
source->importer.passive_fd = passive_fd;
source->importer.name = name;
source->writer = writer;
return source;
}
static char* realloc_buffer(RemoteSource *source, size_t size) {
char *b, *old = source->buf;
b = GREEDY_REALLOC(source->buf, source->size, size);
if (!b)
return NULL;
iovw_rebase(&source->iovw, old, source->buf);
return b;
}
static int get_line(RemoteSource *source, char **line, size_t *size) {
ssize_t n;
char *c = NULL;
assert(source);
assert(source->state == STATE_LINE);
assert(source->offset <= source->filled);
assert(source->filled <= source->size);
assert(source->buf == NULL || source->size > 0);
assert(source->fd >= 0);
for (;;) {
if (source->buf) {
size_t start = MAX(source->scanned, source->offset);
c = memchr(source->buf + start, '\n',
source->filled - start);
if (c != NULL)
break;
}
source->scanned = source->filled;
if (source->scanned >= DATA_SIZE_MAX) {
log_error("Entry is bigger than %u bytes.", DATA_SIZE_MAX);
return -E2BIG;
}
if (source->passive_fd)
/* we have to wait for some data to come to us */
return -EAGAIN;
/* We know that source->filled is at most DATA_SIZE_MAX, so if
we reallocate it, we'll increase the size at least a bit. */
assert_cc(DATA_SIZE_MAX < ENTRY_SIZE_MAX);
if (source->size - source->filled < LINE_CHUNK &&
!realloc_buffer(source, MIN(source->filled + LINE_CHUNK, ENTRY_SIZE_MAX)))
return log_oom();
assert(source->buf);
assert(source->size - source->filled >= LINE_CHUNK ||
source->size == ENTRY_SIZE_MAX);
n = read(source->fd,
source->buf + source->filled,
source->size - source->filled);
if (n < 0) {
if (errno != EAGAIN)
log_error_errno(errno, "read(%d, ..., %zu): %m",
source->fd,
source->size - source->filled);
return -errno;
} else if (n == 0)
return 0;
source->filled += n;
}
*line = source->buf + source->offset;
*size = c + 1 - source->buf - source->offset;
source->offset += *size;
return 1;
}
int push_data(RemoteSource *source, const char *data, size_t size) {
assert(source);
assert(source->state != STATE_EOF);
if (!realloc_buffer(source, source->filled + size)) {
log_error("Failed to store received data of size %zu "
"(in addition to existing %zu bytes with %zu filled): %s",
size, source->size, source->filled, strerror(ENOMEM));
return -ENOMEM;
}
memcpy(source->buf + source->filled, data, size);
source->filled += size;
return 0;
}
static int fill_fixed_size(RemoteSource *source, void **data, size_t size) {
assert(source);
assert(source->state == STATE_DATA_START ||
source->state == STATE_DATA ||
source->state == STATE_DATA_FINISH);
assert(size <= DATA_SIZE_MAX);
assert(source->offset <= source->filled);
assert(source->filled <= source->size);
assert(source->buf != NULL || source->size == 0);
assert(source->buf == NULL || source->size > 0);
assert(source->fd >= 0);
assert(data);
while (source->filled - source->offset < size) {
int n;
if (source->passive_fd)
/* we have to wait for some data to come to us */
return -EAGAIN;
if (!realloc_buffer(source, source->offset + size))
return log_oom();
n = read(source->fd, source->buf + source->filled,
source->size - source->filled);
if (n < 0) {
if (errno != EAGAIN)
log_error_errno(errno, "read(%d, ..., %zu): %m", source->fd,
source->size - source->filled);
return -errno;
} else if (n == 0)
return 0;
source->filled += n;
}
*data = source->buf + source->offset;
source->offset += size;
return 1;
}
static int get_data_size(RemoteSource *source) {
int r;
void *data;
assert(source);
assert(source->state == STATE_DATA_START);
assert(source->data_size == 0);
r = fill_fixed_size(source, &data, sizeof(uint64_t));
if (r <= 0)
return r;
source->data_size = le64toh( *(uint64_t *) data );
if (source->data_size > DATA_SIZE_MAX) {
log_error("Stream declares field with size %zu > DATA_SIZE_MAX = %u",
source->data_size, DATA_SIZE_MAX);
return -EINVAL;
}
if (source->data_size == 0)
log_warning("Binary field with zero length");
return 1;
}
static int get_data_data(RemoteSource *source, void **data) {
int r;
assert(source);
assert(data);
assert(source->state == STATE_DATA);
r = fill_fixed_size(source, data, source->data_size);
if (r <= 0)
return r;
return 1;
}
static int get_data_newline(RemoteSource *source) {
int r;
char *data;
assert(source);
assert(source->state == STATE_DATA_FINISH);
r = fill_fixed_size(source, (void**) &data, 1);
if (r <= 0)
return r;
assert(data);
if (*data != '\n') {
log_error("expected newline, got '%c'", *data);
return -EINVAL;
}
return 1;
}
static int process_dunder(RemoteSource *source, char *line, size_t n) {
const char *timestamp;
int r;
assert(line);
assert(n > 0);
assert(line[n-1] == '\n');
/* XXX: is it worth to support timestamps in extended format?
* We don't produce them, but who knows... */
timestamp = startswith(line, "__CURSOR=");
if (timestamp)
/* ignore __CURSOR */
return 1;
timestamp = startswith(line, "__REALTIME_TIMESTAMP=");
if (timestamp) {
long long unsigned x;
line[n-1] = '\0';
r = safe_atollu(timestamp, &x);
if (r < 0)
log_warning("Failed to parse __REALTIME_TIMESTAMP: '%s'", timestamp);
else
source->ts.realtime = x;
return r < 0 ? r : 1;
}
timestamp = startswith(line, "__MONOTONIC_TIMESTAMP=");
if (timestamp) {
long long unsigned x;
line[n-1] = '\0';
r = safe_atollu(timestamp, &x);
if (r < 0)
log_warning("Failed to parse __MONOTONIC_TIMESTAMP: '%s'", timestamp);
else
source->ts.monotonic = x;
return r < 0 ? r : 1;
}
timestamp = startswith(line, "__");
if (timestamp) {
log_notice("Unknown dunder line %s", line);
return 1;
}
/* no dunder */
return 0;
}
static int process_data(RemoteSource *source) {
int r;
switch(source->state) {
case STATE_LINE: {
char *line, *sep;
size_t n = 0;
assert(source->data_size == 0);
r = get_line(source, &line, &n);
if (r < 0)
return r;
if (r == 0) {
source->state = STATE_EOF;
return r;
}
assert(n > 0);
assert(line[n-1] == '\n');
if (n == 1) {
log_trace("Received empty line, event is ready");
return 1;
}
r = process_dunder(source, line, n);
if (r != 0)
return r < 0 ? r : 0;
/* MESSAGE=xxx\n
or
COREDUMP\n
LLLLLLLL0011223344...\n
*/
sep = memchr(line, '=', n);
if (sep) {
/* chomp newline */
n--;
r = iovw_put(&source->iovw, line, n);
if (r < 0)
return r;
} else {
/* replace \n with = */
line[n-1] = '=';
source->field_len = n;
source->state = STATE_DATA_START;
/* we cannot put the field in iovec until we have all data */
}
log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary");
return 0; /* continue */
}
case STATE_DATA_START:
assert(source->data_size == 0);
r = get_data_size(source);
// log_debug("get_data_size() -> %d", r);
if (r < 0)
return r;
if (r == 0) {
source->state = STATE_EOF;
return 0;
}
source->state = source->data_size > 0 ?
STATE_DATA : STATE_DATA_FINISH;
return 0; /* continue */
case STATE_DATA: {
void *data;
char *field;
assert(source->data_size > 0);
r = get_data_data(source, &data);
// log_debug("get_data_data() -> %d", r);
if (r < 0)
return r;
if (r == 0) {
source->state = STATE_EOF;
return 0;
}
assert(data);
field = (char*) data - sizeof(uint64_t) - source->field_len;
memmove(field + sizeof(uint64_t), field, source->field_len);
r = iovw_put(&source->iovw, field + sizeof(uint64_t), source->field_len + source->data_size);
if (r < 0)
return r;
source->state = STATE_DATA_FINISH;
return 0; /* continue */
}
case STATE_DATA_FINISH:
r = get_data_newline(source);
// log_debug("get_data_newline() -> %d", r);
if (r < 0)
return r;
if (r == 0) {
source->state = STATE_EOF;
return 0;
}
source->data_size = 0;
source->state = STATE_LINE;
return 0; /* continue */
default:
assert_not_reached("wtf?");
}
}
int process_source(RemoteSource *source, bool compress, bool seal) {
size_t remain, target;
int r;
assert(source);
assert(source->writer);
r = process_data(source);
r = journal_importer_process_data(&source->importer);
if (r <= 0)
return r;
/* We have a full event */
log_trace("Received full event from source@%p fd:%d (%s)",
source, source->fd, source->name);
source, source->importer.fd, source->importer.name);
if (!source->iovw.count) {
if (source->importer.iovw.count == 0) {
log_warning("Entry with no payload, skipping");
goto freeing;
}
assert(source->iovw.iovec);
assert(source->iovw.count);
assert(source->importer.iovw.iovec);
r = writer_write(source->writer, &source->iovw, &source->ts, compress, seal);
r = writer_write(source->writer, &source->importer.iovw, &source->importer.ts, compress, seal);
if (r < 0)
log_error_errno(r, "Failed to write entry of %zu bytes: %m",
iovw_size(&source->iovw));
iovw_size(&source->importer.iovw));
else
r = 1;
freeing:
iovw_free_contents(&source->iovw);
/* possibly reset buffer position */
remain = source->filled - source->offset;
if (remain == 0) /* no brainer */
source->offset = source->scanned = source->filled = 0;
else if (source->offset > source->size - source->filled &&
source->offset > remain) {
memcpy(source->buf, source->buf + source->offset, remain);
source->offset = source->scanned = 0;
source->filled = remain;
}
target = source->size;
while (target > 16 * LINE_CHUNK && source->filled < target / 2)
target /= 2;
if (target < source->size) {
char *tmp;
tmp = realloc(source->buf, target);
if (!tmp)
log_warning("Failed to reallocate buffer to (smaller) size %zu",
target);
else {
log_debug("Reallocated buffer from %zu to %zu bytes",
source->size, target);
source->buf = tmp;
source->size = target;
}
}
journal_importer_drop_iovw(&source->importer);
return r;
}

View file

@ -21,34 +21,11 @@
#include "sd-event.h"
#include "journal-importer.h"
#include "journal-remote-write.h"
typedef enum {
STATE_LINE = 0, /* waiting to read, or reading line */
STATE_DATA_START, /* reading binary data header */
STATE_DATA, /* reading binary data */
STATE_DATA_FINISH, /* expecting newline */
STATE_EOF, /* done */
} source_state;
typedef struct RemoteSource {
char *name;
int fd;
bool passive_fd;
char *buf;
size_t size; /* total size of the buffer */
size_t offset; /* offset to the beginning of live data in the buffer */
size_t scanned; /* number of bytes since the beginning of data without a newline */
size_t filled; /* total number of bytes in the buffer */
size_t field_len; /* used for binary fields: the field name length */
size_t data_size; /* and the size of the binary data chunk being processed */
struct iovec_wrapper iovw;
source_state state;
dual_timestamp ts;
JournalImporter importer;
Writer *writer;
@ -57,13 +34,5 @@ typedef struct RemoteSource {
} RemoteSource;
RemoteSource* source_new(int fd, bool passive_fd, char *name, Writer *writer);
static inline size_t source_non_empty(RemoteSource *source) {
assert(source);
return source->filled;
}
void source_free(RemoteSource *source);
int push_data(RemoteSource *source, const char *data, size_t size);
int process_source(RemoteSource *source, bool compress, bool seal);

View file

@ -20,39 +20,6 @@
#include "alloc-util.h"
#include "journal-remote.h"
int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
return log_oom();
iovw->iovec[iovw->count++] = (struct iovec) {data, len};
return 0;
}
void iovw_free_contents(struct iovec_wrapper *iovw) {
iovw->iovec = mfree(iovw->iovec);
iovw->size_bytes = iovw->count = 0;
}
size_t iovw_size(struct iovec_wrapper *iovw) {
size_t n = 0, i;
for (i = 0; i < iovw->count; i++)
n += iovw->iovec[i].iov_len;
return n;
}
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
size_t i;
for (i = 0; i < iovw->count; i++)
iovw->iovec[i].iov_base = (char*) iovw->iovec[i].iov_base - old + new;
}
/**********************************************************************
**********************************************************************
**********************************************************************/
static int do_rotate(JournalFile **f, bool compress, bool seal) {
int r = journal_file_rotate(f, compress, seal, NULL);
if (r < 0) {

View file

@ -20,20 +20,10 @@
***/
#include "journal-file.h"
#include "journal-importer.h"
typedef struct RemoteServer RemoteServer;
struct iovec_wrapper {
struct iovec *iovec;
size_t size_bytes;
size_t count;
};
int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len);
void iovw_free_contents(struct iovec_wrapper *iovw);
size_t iovw_size(struct iovec_wrapper *iovw);
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
typedef struct Writer {
JournalFile *journal;
JournalMetrics metrics;

View file

@ -512,7 +512,8 @@ static int process_http_upload(
if (*upload_data_size) {
log_trace("Received %zu bytes", *upload_data_size);
r = push_data(source, upload_data, *upload_data_size);
r = journal_importer_push_data(&source->importer,
upload_data, *upload_data_size);
if (r < 0)
return mhd_respond_oom(connection);
@ -542,7 +543,7 @@ static int process_http_upload(
/* The upload is finished */
remaining = source_non_empty(source);
remaining = journal_importer_bytes_remaining(&source->importer);
if (remaining > 0) {
log_warning("Premature EOF byte. %zu bytes lost.", remaining);
return mhd_respondf(connection,
@ -1036,19 +1037,19 @@ static int handle_raw_source(sd_event_source *event,
assert(fd >= 0 && fd < (ssize_t) s->sources_size);
source = s->sources[fd];
assert(source->fd == fd);
assert(source->importer.fd == fd);
r = process_source(source, arg_compress, arg_seal);
if (source->state == STATE_EOF) {
if (journal_importer_eof(&source->importer)) {
size_t remaining;
log_debug("EOF reached with source fd:%d (%s)",
source->fd, source->name);
log_debug("EOF reached with source %s (fd=%d)",
source->importer.name, source->importer.fd);
remaining = source_non_empty(source);
remaining = journal_importer_bytes_remaining(&source->importer);
if (remaining > 0)
log_notice("Premature EOF. %zu bytes lost.", remaining);
remove_source(s, source->fd);
remove_source(s, source->importer.fd);
log_debug("%zu active sources remaining", s->active);
return 0;
} else if (r == -E2BIG) {
@ -1072,7 +1073,7 @@ static int dispatch_raw_source_until_block(sd_event_source *event,
/* Make sure event stays around even if source is destroyed */
sd_event_source_ref(event);
r = handle_raw_source(event, source->fd, EPOLLIN, server);
r = handle_raw_source(event, source->importer.fd, EPOLLIN, server);
if (r != 1)
/* No more data for now */
sd_event_source_set_enabled(event, SD_EVENT_OFF);
@ -1105,7 +1106,7 @@ static int dispatch_blocking_source_event(sd_event_source *event,
void *userdata) {
RemoteSource *source = userdata;
return handle_raw_source(event, source->fd, EPOLLIN, server);
return handle_raw_source(event, source->importer.fd, EPOLLIN, server);
}
static int accept_connection(const char* type, int fd,

View file

@ -156,7 +156,8 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
/* Did we lose any? */
if (serial > *s->kernel_seqnum)
server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED,
server_driver_message(s,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_MISSED_STR,
LOG_MESSAGE("Missed %"PRIu64" kernel messages",
serial - *s->kernel_seqnum),
NULL);

View file

@ -27,6 +27,7 @@
#include "fd-util.h"
#include "fs-util.h"
#include "io-util.h"
#include "journal-importer.h"
#include "journald-console.h"
#include "journald-kmsg.h"
#include "journald-native.h"

View file

@ -21,11 +21,6 @@
#include "journald-server.h"
/* Make sure not to make this smaller than the maximum coredump
* size. See COREDUMP_MAX in coredump.c */
#define ENTRY_SIZE_MAX (1024*1024*770u)
#define DATA_SIZE_MAX (1024*1024*768u)
bool valid_user_field(const char *p, size_t l, bool allow_protected);
void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);

View file

@ -214,7 +214,7 @@ void server_space_usage_message(Server *s, JournalStorage *storage) {
format_bytes(fb5, sizeof(fb5), storage->space.limit);
format_bytes(fb6, sizeof(fb6), storage->space.available);
server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
server_driver_message(s, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_USAGE_STR,
LOG_MESSAGE("%s (%s) is %s, max %s, %s free.",
storage->name, storage->path, fb1, fb5, fb6),
"JOURNAL_NAME=%s", storage->name,
@ -1061,8 +1061,7 @@ static void dispatch_message_real(
write_to_journal(s, journal_uid, iovec, n, priority);
}
void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
char mid[11 + 32 + 1];
void server_driver_message(Server *s, const char *message_id, const char *format, ...) {
struct iovec iovec[N_IOVEC_META_FIELDS + 5 + N_IOVEC_PAYLOAD_FIELDS];
unsigned n = 0, m;
int r;
@ -1080,11 +1079,8 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
assert_cc(6 == LOG_INFO);
IOVEC_SET_STRING(iovec[n++], "PRIORITY=6");
if (!sd_id128_is_null(message_id)) {
snprintf(mid, sizeof(mid), LOG_MESSAGE_ID(message_id));
IOVEC_SET_STRING(iovec[n++], mid);
}
if (message_id)
IOVEC_SET_STRING(iovec[n++], message_id);
m = n;
va_start(ap, format);
@ -1174,7 +1170,7 @@ void server_dispatch_message(
/* Write a suppression message if we suppressed something */
if (rl > 1)
server_driver_message(s, SD_MESSAGE_JOURNAL_DROPPED,
server_driver_message(s, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_DROPPED_STR,
LOG_MESSAGE("Suppressed %u messages from %s", rl - 1, path),
NULL);
@ -1273,7 +1269,7 @@ finish:
sd_journal_close(j);
server_driver_message(s, SD_ID128_NULL,
server_driver_message(s, NULL,
LOG_MESSAGE("Time spent on flushing to /var is %s for %u entries.",
format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0),
n),

View file

@ -176,7 +176,7 @@ struct Server {
#define N_IOVEC_PAYLOAD_FIELDS 15
void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,0) _sentinel_;
void server_driver_message(Server *s, const char *message_id, const char *format, ...) _printf_(3,0) _sentinel_;
/* gperf lookup function */
const struct ConfigPerfItem* journald_gperf_lookup(const char *key, GPERF_LEN_TYPE length);

View file

@ -444,7 +444,8 @@ void server_maybe_warn_forward_syslog_missed(Server *s) {
if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n)
return;
server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED,
server_driver_message(s,
"MESSAGE_ID=" SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR,
LOG_MESSAGE("Forwarding to syslog missed %u messages.",
s->n_forward_syslog_missed),
NULL);

View file

@ -56,7 +56,8 @@ int main(int argc, char *argv[]) {
server_flush_dev_kmsg(&server);
log_debug("systemd-journald running as pid "PID_FMT, getpid());
server_driver_message(&server, SD_MESSAGE_JOURNAL_START,
server_driver_message(&server,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_START_STR,
LOG_MESSAGE("Journal started"),
NULL);
@ -114,7 +115,8 @@ int main(int argc, char *argv[]) {
}
log_debug("systemd-journald stopped as pid "PID_FMT, getpid());
server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP,
server_driver_message(&server,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_STOP_STR,
LOG_MESSAGE("Journal stopped"),
NULL);

View file

@ -155,7 +155,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
case KEY_POWER2:
log_struct(LOG_INFO,
LOG_MESSAGE("Power key pressed."),
LOG_MESSAGE_ID(SD_MESSAGE_POWER_KEY),
"MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR,
NULL);
manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
@ -170,7 +170,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
case KEY_SLEEP:
log_struct(LOG_INFO,
LOG_MESSAGE("Suspend key pressed."),
LOG_MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
"MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR,
NULL);
manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
@ -179,7 +179,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
case KEY_SUSPEND:
log_struct(LOG_INFO,
LOG_MESSAGE("Hibernate key pressed."),
LOG_MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
"MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR,
NULL);
manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
@ -191,7 +191,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
if (ev.code == SW_LID) {
log_struct(LOG_INFO,
LOG_MESSAGE("Lid closed."),
LOG_MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
"MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR,
NULL);
b->lid_closed = true;
@ -201,7 +201,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
} else if (ev.code == SW_DOCK) {
log_struct(LOG_INFO,
LOG_MESSAGE("System docked."),
LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED),
"MESSAGE_ID=" SD_MESSAGE_SYSTEM_DOCKED_STR,
NULL);
b->docked = true;
@ -212,7 +212,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
if (ev.code == SW_LID) {
log_struct(LOG_INFO,
LOG_MESSAGE("Lid opened."),
LOG_MESSAGE_ID(SD_MESSAGE_LID_OPENED),
"MESSAGE_ID=" SD_MESSAGE_LID_OPENED_STR,
NULL);
b->lid_closed = false;
@ -221,7 +221,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
} else if (ev.code == SW_DOCK) {
log_struct(LOG_INFO,
LOG_MESSAGE("System undocked."),
LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED),
"MESSAGE_ID=" SD_MESSAGE_SYSTEM_UNDOCKED_STR,
NULL);
b->docked = false;

View file

@ -1430,7 +1430,7 @@ static int bus_manager_log_shutdown(
p = strjoina(p, " (", m->wall_message, ").");
return log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
p,
q,
NULL);

View file

@ -416,7 +416,7 @@ int seat_start(Seat *s) {
return 0;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SEAT_START),
"MESSAGE_ID=" SD_MESSAGE_SEAT_START_STR,
"SEAT_ID=%s", s->id,
LOG_MESSAGE("New seat %s.", s->id),
NULL);
@ -444,7 +444,7 @@ int seat_stop(Seat *s, bool force) {
if (s->started)
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SEAT_STOP),
"MESSAGE_ID=" SD_MESSAGE_SEAT_STOP_STR,
"SEAT_ID=%s", s->id,
LOG_MESSAGE("Removed seat %s.", s->id),
NULL);

View file

@ -561,7 +561,7 @@ int session_start(Session *s) {
return r;
log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
"MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
"SESSION_ID=%s", s->id,
"USER_ID=%s", s->user->name,
"LEADER="PID_FMT, s->leader,
@ -666,7 +666,7 @@ int session_finalize(Session *s) {
if (s->started)
log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
"MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
"SESSION_ID=%s", s->id,
"USER_ID=%s", s->user->name,
"LEADER="PID_FMT, s->leader,

View file

@ -401,7 +401,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return r;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
"MESSAGE_ID=" SD_MESSAGE_MACHINE_START_STR,
"NAME=%s", m->name,
"LEADER="PID_FMT, m->leader,
LOG_MESSAGE("New machine %s.", m->name),
@ -464,7 +464,7 @@ int machine_finalize(Machine *m) {
if (m->started)
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
"MESSAGE_ID=" SD_MESSAGE_MACHINE_STOP_STR,
"NAME=%s", m->name,
"LEADER="PID_FMT, m->leader,
LOG_MESSAGE("Machine %s terminated.", m->name),

View file

@ -570,7 +570,7 @@ void dns_server_warn_downgrade(DnsServer *server) {
return;
log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_DOWNGRADE),
"MESSAGE_ID=" SD_MESSAGE_DNSSEC_DOWNGRADE_STR,
LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", dns_server_string(server)),
"DNS_SERVER=%s", dns_server_string(server),
"DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(server->possible_feature_level),

View file

@ -318,7 +318,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
dns_resource_key_to_string(t->key, key_str, sizeof key_str);
log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_FAILURE),
"MESSAGE_ID=" SD_MESSAGE_DNSSEC_FAILURE_STR,
LOG_MESSAGE("DNSSEC validation failed for question %s: %s", key_str, dnssec_result_to_string(t->answer_dnssec_result)),
"DNS_TRANSACTION=%" PRIu16, t->id,
"DNS_QUESTION=%s", key_str,

View file

@ -594,7 +594,7 @@ static int dns_trust_anchor_remove_revoked(DnsTrustAnchor *d, DnsResourceRecord
/* We found the key! Warn the user */
log_struct(LOG_WARNING,
LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED),
"MESSAGE_ID=" SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR,
LOG_MESSAGE("DNSSEC Trust anchor %s has been revoked. Please update the trust anchor, or upgrade your operating system."), strna(dns_resource_record_to_string(rr)),
"TRUST_ANCHOR=%s", dns_resource_record_to_string(rr),
NULL);

View file

@ -109,7 +109,7 @@ static int execute(char **modes, char **states) {
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
"MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
LOG_MESSAGE("Suspending system..."),
"SLEEP=%s", arg_verb,
NULL);
@ -119,7 +119,7 @@ static int execute(char **modes, char **states) {
return r;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
"MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
LOG_MESSAGE("System resumed."),
"SLEEP=%s", arg_verb,
NULL);

View file

@ -100,6 +100,9 @@ int sd_id128_get_invocation(sd_id128_t *ret);
((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \
0 })
#define SD_ID128_MAKE_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
#a #b #c #d #e #f #g #h #i #j #k #l #m #n #o #p
_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
return memcmp(&a, &b, 16) == 0;
}

View file

@ -33,60 +33,109 @@ _SD_BEGIN_DECLARATIONS;
* with journalctl --new-id128. Do not use any other IDs, and do not
* count them up manually. */
#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
#define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
#define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
#define SD_MESSAGE_JOURNAL_MISSED SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
#define SD_MESSAGE_JOURNAL_USAGE SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
#define SD_MESSAGE_JOURNAL_START_STR SD_ID128_MAKE_STR(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
#define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
#define SD_MESSAGE_JOURNAL_STOP_STR SD_ID128_MAKE_STR(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
#define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
#define SD_MESSAGE_JOURNAL_DROPPED_STR SD_ID128_MAKE_STR(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
#define SD_MESSAGE_JOURNAL_MISSED SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
#define SD_MESSAGE_JOURNAL_MISSED_STR SD_ID128_MAKE_STR(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
#define SD_MESSAGE_JOURNAL_USAGE SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
#define SD_MESSAGE_JOURNAL_USAGE_STR SD_ID128_MAKE_STR(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
#define SD_MESSAGE_TRUNCATED_CORE SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
#define SD_MESSAGE_COREDUMP_STR SD_ID128_MAKE_STR(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
#define SD_MESSAGE_TRUNCATED_CORE SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
#define SD_MESSAGE_TRUNCATED_CORE_STR SD_ID128_MAKE_STR(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
#define SD_MESSAGE_BACKTRACE SD_ID128_MAKE(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
#define SD_MESSAGE_BACKTRACE_STR SD_ID128_MAKE_STR(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
#define SD_MESSAGE_SESSION_START SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
#define SD_MESSAGE_SESSION_STOP SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
#define SD_MESSAGE_SEAT_START SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
#define SD_MESSAGE_SEAT_STOP SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
#define SD_MESSAGE_MACHINE_START SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
#define SD_MESSAGE_MACHINE_STOP SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
#define SD_MESSAGE_SESSION_START SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
#define SD_MESSAGE_SESSION_START_STR SD_ID128_MAKE_STR(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
#define SD_MESSAGE_SESSION_STOP SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
#define SD_MESSAGE_SESSION_STOP_STR SD_ID128_MAKE_STR(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
#define SD_MESSAGE_SEAT_START SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
#define SD_MESSAGE_SEAT_START_STR SD_ID128_MAKE_STR(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
#define SD_MESSAGE_SEAT_STOP SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
#define SD_MESSAGE_SEAT_STOP_STR SD_ID128_MAKE_STR(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
#define SD_MESSAGE_MACHINE_START SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
#define SD_MESSAGE_MACHINE_START_STR SD_ID128_MAKE_STR(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
#define SD_MESSAGE_MACHINE_STOP SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
#define SD_MESSAGE_MACHINE_STOP_STR SD_ID128_MAKE_STR(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
#define SD_MESSAGE_TIME_CHANGE SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
#define SD_MESSAGE_TIMEZONE_CHANGE SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
#define SD_MESSAGE_TIME_CHANGE SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
#define SD_MESSAGE_TIME_CHANGE_STR SD_ID128_MAKE_STR(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
#define SD_MESSAGE_TIMEZONE_CHANGE SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
#define SD_MESSAGE_TIMEZONE_CHANGE_STR SD_ID128_MAKE_STR(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
#define SD_MESSAGE_STARTUP_FINISHED SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
#define SD_MESSAGE_USER_STARTUP_FINISHED SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
#define SD_MESSAGE_STARTUP_FINISHED SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
#define SD_MESSAGE_STARTUP_FINISHED_STR SD_ID128_MAKE_STR(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
#define SD_MESSAGE_USER_STARTUP_FINISHED \
SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
#define SD_MESSAGE_USER_STARTUP_FINISHED_STR \
SD_ID128_MAKE_STR(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
#define SD_MESSAGE_SLEEP_START SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
#define SD_MESSAGE_SLEEP_STOP SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
#define SD_MESSAGE_SLEEP_START SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
#define SD_MESSAGE_SLEEP_START_STR SD_ID128_MAKE_STR(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
#define SD_MESSAGE_SLEEP_STOP SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
#define SD_MESSAGE_SLEEP_STOP_STR SD_ID128_MAKE_STR(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
#define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
#define SD_MESSAGE_UNIT_STARTING SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
#define SD_MESSAGE_UNIT_STARTED SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
#define SD_MESSAGE_UNIT_STOPPING SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
#define SD_MESSAGE_UNIT_STOPPED SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
#define SD_MESSAGE_UNIT_FAILED SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
#define SD_MESSAGE_UNIT_RELOADING SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
#define SD_MESSAGE_UNIT_STARTING SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
#define SD_MESSAGE_UNIT_STARTING_STR SD_ID128_MAKE_STR(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
#define SD_MESSAGE_UNIT_STARTED SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
#define SD_MESSAGE_UNIT_STARTED_STR SD_ID128_MAKE_STR(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
#define SD_MESSAGE_UNIT_STOPPING SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
#define SD_MESSAGE_UNIT_STOPPING_STR SD_ID128_MAKE_STR(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
#define SD_MESSAGE_UNIT_STOPPED SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
#define SD_MESSAGE_UNIT_STOPPED_STR SD_ID128_MAKE_STR(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
#define SD_MESSAGE_UNIT_FAILED SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
#define SD_MESSAGE_UNIT_FAILED_STR SD_ID128_MAKE_STR(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
#define SD_MESSAGE_UNIT_RELOADING SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
#define SD_MESSAGE_UNIT_RELOADING_STR SD_ID128_MAKE_STR(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
#define SD_MESSAGE_UNIT_RELOADED_STR SD_ID128_MAKE_STR(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
#define SD_MESSAGE_SPAWN_FAILED_STR SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
#define SD_MESSAGE_FORWARD_SYSLOG_MISSED SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
#define SD_MESSAGE_FORWARD_SYSLOG_MISSED SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
#define SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR \
SD_ID128_MAKE_STR(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
#define SD_MESSAGE_OVERMOUNTING_STR SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
#define SD_MESSAGE_LID_OPENED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
#define SD_MESSAGE_LID_CLOSED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
#define SD_MESSAGE_SYSTEM_DOCKED SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
#define SD_MESSAGE_SYSTEM_UNDOCKED SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
#define SD_MESSAGE_POWER_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
#define SD_MESSAGE_LID_OPENED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
#define SD_MESSAGE_LID_OPENED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
#define SD_MESSAGE_LID_CLOSED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
#define SD_MESSAGE_LID_CLOSED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
#define SD_MESSAGE_SYSTEM_DOCKED SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
#define SD_MESSAGE_SYSTEM_DOCKED_STR SD_ID128_MAKE_STR(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
#define SD_MESSAGE_SYSTEM_UNDOCKED SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
#define SD_MESSAGE_SYSTEM_UNDOCKED_STR SD_ID128_MAKE_STR(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
#define SD_MESSAGE_POWER_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
#define SD_MESSAGE_POWER_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
#define SD_MESSAGE_SUSPEND_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
#define SD_MESSAGE_HIBERNATE_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
#define SD_MESSAGE_INVALID_CONFIGURATION_STR \
SD_ID128_MAKE_STR(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
#define SD_MESSAGE_DNSSEC_FAILURE_STR SD_ID128_MAKE_STR(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED \
SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR \
SD_ID128_MAKE_STR(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
_SD_END_DECLARATIONS;

View file

@ -0,0 +1,90 @@
/***
This file is part of systemd.
Copyright 2016 Zbigniew Jędrzejewski-Szmek
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/>.
***/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log.h"
#include "journal-importer.h"
#include "string-util.h"
#include "test-helper.h"
static void assert_iovec_entry(const struct iovec *iovec, const char* content) {
assert_se(strlen(content) == iovec->iov_len);
assert_se(memcmp(content, iovec->iov_base, iovec->iov_len) == 0);
}
#define COREDUMP_PROC_GROUP \
"COREDUMP_PROC_CGROUP=1:name=systemd:/\n" \
"0::/user.slice/user-1002.slice/user@1002.service/gnome-terminal-server.service\n"
static void test_basic_parsing(void) {
_cleanup_(journal_importer_cleanup) JournalImporter imp = {};
int r;
imp.fd = open(TEST_DATA_DIR("/journal-data/journal-1.txt"), O_RDONLY|O_CLOEXEC);
assert_se(imp.fd >= 0);
do
r = journal_importer_process_data(&imp);
while (r == 0 && !journal_importer_eof(&imp));
assert_se(r == 1);
/* We read one entry, so we should get EOF on next read, but not yet */
assert_se(!journal_importer_eof(&imp));
assert_se(imp.iovw.count == 6);
assert_iovec_entry(&imp.iovw.iovec[0], "_BOOT_ID=1531fd22ec84429e85ae888b12fadb91");
assert_iovec_entry(&imp.iovw.iovec[1], "_TRANSPORT=journal");
assert_iovec_entry(&imp.iovw.iovec[2], COREDUMP_PROC_GROUP);
assert_iovec_entry(&imp.iovw.iovec[3], "COREDUMP_RLIMIT=-1");
assert_iovec_entry(&imp.iovw.iovec[4], COREDUMP_PROC_GROUP);
assert_iovec_entry(&imp.iovw.iovec[5], "_SOURCE_REALTIME_TIMESTAMP=1478389147837945");
/* Let's check if we get EOF now */
r = journal_importer_process_data(&imp);
assert_se(r == 0);
assert_se(journal_importer_eof(&imp));
}
static void test_bad_input(void) {
_cleanup_(journal_importer_cleanup) JournalImporter imp = {};
int r;
imp.fd = open(TEST_DATA_DIR("/journal-data/journal-2.txt"), O_RDONLY|O_CLOEXEC);
assert_se(imp.fd >= 0);
do
r = journal_importer_process_data(&imp);
while (!journal_importer_eof(&imp));
assert_se(r == 0); /* If we don't have enough input, 0 is returned */
assert_se(journal_importer_eof(&imp));
}
int main(int argc, char **argv) {
log_set_max_level(LOG_DEBUG);
log_parse_environment();
test_basic_parsing();
test_bad_input();
return 0;
}

View file

@ -413,7 +413,7 @@ static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error *
}
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE),
"MESSAGE_ID=" SD_MESSAGE_TIMEZONE_CHANGE_STR,
"TIMEZONE=%s", c->zone,
LOG_MESSAGE("Changed time zone to '%s'.", c->zone),
NULL);
@ -591,7 +591,7 @@ static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *erro
clock_set_hwclock(tm);
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
"MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
"REALTIME="USEC_FMT, timespec_load(&ts),
LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)),
NULL);

Binary file not shown.

Binary file not shown.