diff options
| author | Lennart Poettering <lennart@poettering.net> | 2017-02-16 11:24:03 +0100 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-02-16 11:24:03 +0100 | 
| commit | 2fe917fe916cae66194d12cafdb24333e808f1d7 (patch) | |
| tree | b8521991a6045ac4ddedd68d06af50f8c8869a89 | |
| parent | 0cbc024d591e1b1095d90494e0337dabd9ef2e19 (diff) | |
| parent | 561eede4d126610ee5023098fc2787bd8864f144 (diff) | |
Merge pull request #4526 from keszybz/coredump-python
Collect interpreter backtraces in systemd-coredump
44 files changed, 1175 insertions, 877 deletions
| diff --git a/.gitignore b/.gitignore index fe7859c265..924b995bb3 100644 --- a/.gitignore +++ b/.gitignore @@ -220,6 +220,7 @@  /test-journal  /test-journal-enum  /test-journal-flush +/test-journal-importer  /test-journal-init  /test-journal-interleaving  /test-journal-match @@ -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 diff --git a/Makefile-man.am b/Makefile-man.am index 6f59658445..e20187d0df 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -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) diff --git a/Makefile.am b/Makefile.am index c45755f36e..10839e922a 100644 --- a/Makefile.am +++ b/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 diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml index 77b4dac51c..5f61e05f40 100644 --- a/man/coredump.conf.xml +++ b/man/coredump.conf.xml @@ -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 diff --git a/man/sd-id128.xml b/man/sd-id128.xml index 5f24feff8e..2e29cf91cb 100644 --- a/man/sd-id128.xml +++ b/man/sd-id128.xml @@ -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 diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml index 4a1bc8b296..7243467dc2 100644 --- a/man/systemd-coredump.xml +++ b/man/systemd-coredump.xml @@ -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 diff --git a/src/basic/journal-importer.c b/src/basic/journal-importer.c new file mode 100644 index 0000000000..4c13e46a49 --- /dev/null +++ b/src/basic/journal-importer.c @@ -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; +} diff --git a/src/basic/journal-importer.h b/src/basic/journal-importer.h new file mode 100644 index 0000000000..b3e308dd6d --- /dev/null +++ b/src/basic/journal-importer.h @@ -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; +} diff --git a/src/basic/log.c b/src/basic/log.c index 1362b1c086..e6d2d61d72 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -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), diff --git a/src/basic/log.h b/src/basic/log.h index 2afee20bb5..9cacbb6b70 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -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); diff --git a/src/core/execute.c b/src/core/execute.c index 4c2968f971..f455afa962 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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), diff --git a/src/core/job.c b/src/core/job.c index 07f4b74c5c..e2349830a8 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -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), diff --git a/src/core/manager.c b/src/core/manager.c index 5646889a8e..b509adfc64 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -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)), diff --git a/src/core/unit.c b/src/core/unit.c index 0b680e9544..bb05d2abfb 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -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, diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 1f6fb5de1e..1bb1dbbe8d 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -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; + +        x = strappend(field, value); +        if (x) +                IOVEC_SET_STRING(iovec[(*n_iovec)++], x); +        return 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; +static char* set_iovec_field_free(struct iovec iovec[27], size_t *n_iovec, const char *field, char *value) { +        char *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; +        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 (compose_open_fds(pid, &t) >= 0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_OPEN_FDS=", t); -        if (get_process_cmdline(pid, 0, false, &t) >= 0) { -                core_cmdline = strjoina("COREDUMP_CMDLINE=", t); -                free(t); +        p = procfs_file_alloca(pid, "status"); +        if (read_full_file(p, &t, NULL) >= 0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_STATUS=", t); -                IOVEC_SET_STRING(iovec[n_iovec++], core_cmdline); -        } +        p = procfs_file_alloca(pid, "maps"); +        if (read_full_file(p, &t, NULL) >= 0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MAPS=", t); -        if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { -                core_cgroup = strjoina("COREDUMP_CGROUP=", t); -                free(t); +        p = procfs_file_alloca(pid, "limits"); +        if (read_full_file(p, &t, NULL) >= 0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_LIMITS=", t); -                IOVEC_SET_STRING(iovec[n_iovec++], core_cgroup); -        } +        p = procfs_file_alloca(pid, "cgroup"); +        if (read_full_file(p, &t, NULL) >=0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_CGROUP=", t); -        if (compose_open_fds(pid, &t) >= 0) { -                core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); -                free(t); +        p = procfs_file_alloca(pid, "mountinfo"); +        if (read_full_file(p, &t, NULL) >=0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t); -                if (core_open_fds) -                        IOVEC_SET_STRING(iovec[n_iovec++], core_open_fds); -        } +        if (get_process_cwd(pid, &t) >= 0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", 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 (get_process_root(pid, &t) >= 0) { +                bool proc_self_root_is_slash; -                if (core_proc_status) -                        IOVEC_SET_STRING(iovec[n_iovec++], core_proc_status); -        } +                proc_self_root_is_slash = strcmp(t, "/") == 0; -        p = procfs_file_alloca(pid, "maps"); -        if (read_full_file(p, &t, NULL) >= 0) { -                core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); -                free(t); +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_ROOT=", t); -                if (core_proc_maps) -                        IOVEC_SET_STRING(iovec[n_iovec++], core_proc_maps); +                /* If the process' root is "/", then there is a chance it has +                 * mounted own root and hence being containerized. */ +                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);          } -        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 (get_process_environ(pid, &t) >= 0) +                set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t); -                if (core_proc_limits) -                        IOVEC_SET_STRING(iovec[n_iovec++], core_proc_limits); +        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;          } -        p = procfs_file_alloca(pid, "cgroup"); -        if (read_full_file(p, &t, NULL) >=0) { -                core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); -                free(t); +        return 0; +} -                if (core_proc_cgroup) -                        IOVEC_SET_STRING(iovec[n_iovec++], core_proc_cgroup); -        } +static int process_kernel(int argc, char* argv[]) { -        p = procfs_file_alloca(pid, "mountinfo"); -        if (read_full_file(p, &t, NULL) >=0) { -                core_proc_mountinfo = strappend("COREDUMP_PROC_MOUNTINFO=", t); -                free(t); +        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 (core_proc_mountinfo) -                        IOVEC_SET_STRING(iovec[n_iovec++], core_proc_mountinfo); +        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;          } -        if (get_process_cwd(pid, &t) >= 0) { -                core_cwd = strjoina("COREDUMP_CWD=", t); -                free(t); +        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]; -                IOVEC_SET_STRING(iovec[n_iovec++], core_cwd); -        } +        r = gather_pid_metadata(context, argv + CONTEXT_COMM + 1, NULL, iovec, &n_to_free); +        if (r < 0) +                goto finish; +        n_iovec = n_to_free; -        if (get_process_root(pid, &t) >= 0) { -                core_root = strjoina("COREDUMP_ROOT=", t); +        IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR); -                IOVEC_SET_STRING(iovec[n_iovec++], core_root); +        assert_cc(2 == LOG_CRIT); +        IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2"); -                /* 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); +        assert(n_iovec <= ELEMENTSOF(iovec)); -                        if (core_container_cmdline) -                                IOVEC_SET_STRING(iovec[n_iovec++], core_container_cmdline); -                } +        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;          } -        if (get_process_environ(pid, &t) >= 0) { -                core_environ = strappend("COREDUMP_ENVIRON=", t); -                free(t); +        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(); -                if (core_environ) -                        IOVEC_SET_STRING(iovec[n_iovec++], core_environ); +        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;          } -        core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000"); -        IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp); +        if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + importer.iovw.count + 2)) +                return log_oom(); -        IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); +        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 <= ELEMENTSOF(iovec)); +        assert(n_iovec <= n_allocated); + +        r = sd_journal_sendv(iovec, n_iovec); +        if (r < 0) +                log_error_errno(r, "Failed to log backtrace: %m"); -        return send_iovec(iovec, n_iovec, STDIN_FILENO); + 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."); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index fcb741b353..6abd99430b 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -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; -        log_debug("Adding pattern: %s", pattern); -        r = set_consume(set, pattern); +        r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0);          if (r < 0) -                goto fail; +                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; +        }          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; diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c index 9ba9ee3fc0..79afe6604c 100644 --- a/src/journal-remote/journal-remote-parse.c +++ b/src/journal-remote/journal-remote-parse.c @@ -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;  } diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 1740a21f92..e3632528cf 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -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); diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index 8729372aa3..734cad333f 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -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) { diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h index 53ba45fc04..e04af54e55 100644 --- a/src/journal-remote/journal-remote-write.h +++ b/src/journal-remote/journal-remote-write.h @@ -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; diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index d0d8d936e3..202a5a3f97 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -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, diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index 18c8644507..8afaec0ced 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -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); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 0a1ce205c2..3c03b83754 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -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" diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h index c13b80aa4f..1ab415ac85 100644 --- a/src/journal/journald-native.h +++ b/src/journal/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); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 8b92ea3def..451f16483f 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -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), diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 716e758b7c..75ac114d24 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -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); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index 896303fb85..474369039a 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -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); diff --git a/src/journal/journald.c b/src/journal/journald.c index 54fd1f999d..1aaef387b4 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -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); diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 90fb93bbaf..d739af8ea2 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -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; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index ad44ca290e..c6be596af3 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -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); diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index bfbd07309d..e4836fcaab 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -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); diff --git a/src/login/logind-session.c b/src/login/logind-session.c index fd7fcf7f2c..4a168906d6 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -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, diff --git a/src/machine/machine.c b/src/machine/machine.c index eb4b35d52a..067a7e2866 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -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), diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 10562d03ec..072cbfca1a 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -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), diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 69e1d58ccf..9687409663 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -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, diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c index 9917b9e984..d8529f8317 100644 --- a/src/resolve/resolved-dns-trust-anchor.c +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -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); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index c8f0742183..ea96615222 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -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); diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index 6cc8e4ac0e..9b38969b77 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -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;  } diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index db1a21be05..f466d9b062 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -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_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_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_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_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_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_SHUTDOWN         SD_ID128_MAKE(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_SPAWN_FAILED     SD_ID128_MAKE(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_OVERMOUNTING     SD_ID128_MAKE(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_INVALID_CONFIGURATION SD_ID128_MAKE(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_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_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_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_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_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_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_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_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_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_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_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_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_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_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; diff --git a/src/test/test-journal-importer.c b/src/test/test-journal-importer.c new file mode 100644 index 0000000000..1f0684863e --- /dev/null +++ b/src/test/test-journal-importer.c @@ -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; +} diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 490929e93b..1061b094d3 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -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); diff --git a/test/journal-data/journal-1.txt b/test/journal-data/journal-1.txtBinary files differ new file mode 100644 index 0000000000..92a9199a93 --- /dev/null +++ b/test/journal-data/journal-1.txt diff --git a/test/journal-data/journal-2.txt b/test/journal-data/journal-2.txtBinary files differ new file mode 100644 index 0000000000..4f582a0e88 --- /dev/null +++ b/test/journal-data/journal-2.txt | 
