mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-24 02:03:54 +03:00
Merge pull request #4526 from keszybz/coredump-python
Collect interpreter backtraces in systemd-coredump
This commit is contained in:
commit
2fe917fe91
1
.gitignore
vendored
1
.gitignore
vendored
@ -220,6 +220,7 @@
|
||||
/test-journal
|
||||
/test-journal-enum
|
||||
/test-journal-flush
|
||||
/test-journal-importer
|
||||
/test-journal-init
|
||||
/test-journal-interleaving
|
||||
/test-journal-match
|
||||
|
4
HACKING
4
HACKING
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
17
Makefile.am
17
Makefile.am
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 <stdio.h>
|
||||
#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
|
||||
|
@ -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
|
||||
|
481
src/basic/journal-importer.c
Normal file
481
src/basic/journal-importer.c
Normal 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;
|
||||
}
|
70
src/basic/journal-importer.h
Normal file
70
src/basic/journal-importer.h
Normal 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;
|
||||
}
|
@ -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),
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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)),
|
||||
|
@ -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,
|
||||
|
@ -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.");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
90
src/test/test-journal-importer.c
Normal file
90
src/test/test-journal-importer.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
|
BIN
test/journal-data/journal-1.txt
Normal file
BIN
test/journal-data/journal-1.txt
Normal file
Binary file not shown.
BIN
test/journal-data/journal-2.txt
Normal file
BIN
test/journal-data/journal-2.txt
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user