diff options
Diffstat (limited to 'src')
35 files changed, 1102 insertions, 859 deletions
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); |