diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/coredump/coredump.c | 32 | ||||
-rw-r--r-- | src/libsystemd/sd-journal/journal-send.c | 12 | ||||
-rw-r--r-- | src/libsystemd/sd-journal/journal-send.h | 4 | ||||
-rw-r--r-- | src/sysusers/sysusers.c | 47 |
4 files changed, 75 insertions, 20 deletions
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 10a96ab568..3ec41a32c3 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -29,6 +29,7 @@ #include "fs-util.h" #include "io-util.h" #include "journal-importer.h" +#include "journal-send.h" #include "log.h" #include "macro.h" #include "main-func.h" @@ -842,12 +843,10 @@ log: core_message = strjoina(core_message, stacktrace ? "\n\n" : NULL, stacktrace); - if (context->is_journald) { - /* We cannot log to the journal, so just print the message. - * The target was set previously to something safe. */ + if (context->is_journald) + /* We might not be able to log to the journal, so let's always print the message to another + * log target. The target was set previously to something safe. */ log_dispatch(LOG_ERR, 0, core_message); - return 0; - } (void) iovw_put_string_field(iovw, "MESSAGE=", core_message); @@ -903,8 +902,29 @@ log: coredump_size, arg_journal_size_max); } + /* If journald is coredumping, we have to be careful that we don't deadlock when trying to write the + * coredump to the journal, so we put the journal socket in nonblocking mode before trying to write + * the coredump to the socket. */ + + if (context->is_journald) { + r = journal_fd_nonblock(true); + if (r < 0) + return log_error_errno(r, "Failed to make journal socket non-blocking: %m"); + } + r = sd_journal_sendv(iovw->iovec, iovw->count); - if (r < 0) + + if (context->is_journald) { + int k; + + k = journal_fd_nonblock(false); + if (k < 0) + return log_error_errno(k, "Failed to make journal socket blocking: %m"); + } + + if (r == -EAGAIN && context->is_journald) + log_warning_errno(r, "Failed to log journal coredump, ignoring: %m"); + else if (r < 0) return log_error_errno(r, "Failed to log coredump: %m"); return 0; diff --git a/src/libsystemd/sd-journal/journal-send.c b/src/libsystemd/sd-journal/journal-send.c index e1c40702d3..81e3c81a0b 100644 --- a/src/libsystemd/sd-journal/journal-send.c +++ b/src/libsystemd/sd-journal/journal-send.c @@ -66,6 +66,16 @@ retry: return fd; } +int journal_fd_nonblock(bool nonblock) { + int r; + + r = journal_fd(); + if (r < 0) + return r; + + return fd_nonblock(r, nonblock); +} + #if VALGRIND void close_journal_fd(void) { /* Be nice to valgrind. This is not atomic. This must be used only in tests. */ @@ -318,7 +328,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { if (errno == ENOENT) return 0; - if (!IN_SET(errno, EMSGSIZE, ENOBUFS)) + if (!IN_SET(errno, EMSGSIZE, ENOBUFS, EAGAIN)) return -errno; /* Message doesn't fit... Let's dump the data in a memfd or diff --git a/src/libsystemd/sd-journal/journal-send.h b/src/libsystemd/sd-journal/journal-send.h index cf8b199297..558d39a8c0 100644 --- a/src/libsystemd/sd-journal/journal-send.h +++ b/src/libsystemd/sd-journal/journal-send.h @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include <stdbool.h> + +int journal_fd_nonblock(bool nonblock); + #if VALGRIND void close_journal_fd(void); #else diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index c60dee812f..aba08a7563 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1981,7 +1981,7 @@ static int parse_arguments(char **args) { /* Use (argument):n, where n==1 for the first positional arg */ r = parse_line("(argument)", pos, *arg); else - r = read_config_file(*arg, false); + r = read_config_file(*arg, /* ignore_enoent= */ false); if (r < 0) return r; @@ -2011,12 +2011,31 @@ static int read_config_files(char **args) { log_debug("Reading config file \"%s\"%s", *f, special_glyph(SPECIAL_GLYPH_ELLIPSIS)); /* Just warn, ignore result otherwise */ - (void) read_config_file(*f, true); + (void) read_config_file(*f, /* ignore_enoent= */ true); } return 0; } +static int read_credential_lines(void) { + _cleanup_free_ char *j = NULL; + const char *d; + int r; + + r = get_credentials_dir(&d); + if (r == -ENXIO) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to get credentials directory: %m"); + + j = path_join(d, "sysusers.extra"); + if (!j) + return log_oom(); + + (void) read_config_file(j, /* ignore_enoent= */ true); + return 0; +} + static int run(int argc, char *argv[]) { #ifndef STANDALONE _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; @@ -2068,12 +2087,10 @@ static int run(int argc, char *argv[]) { assert(!arg_image); #endif - /* If command line arguments are specified along with --replace, read all - * configuration files and insert the positional arguments at the specified - * place. Otherwise, if command line arguments are specified, execute just - * them, and finally, without --replace= or any positional arguments, just - * read configuration and execute it. - */ + /* If command line arguments are specified along with --replace, read all configuration files and + * insert the positional arguments at the specified place. Otherwise, if command line arguments are + * specified, execute just them, and finally, without --replace= or any positional arguments, just + * read configuration and execute it. */ if (arg_replace || optind >= argc) r = read_config_files(argv + optind); else @@ -2081,11 +2098,15 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our detection - * whether the names or UID/GID area already used otherwise doesn't get confused. After all, even though - * nss-systemd synthesizes these users/groups, they should still appear in /etc/passwd and /etc/group, as the - * synthesizing logic is merely supposed to be fallback for cases where we run with a completely unpopulated - * /etc. */ + r = read_credential_lines(); + if (r < 0) + return r; + + /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our + * detection whether the names or UID/GID area already used otherwise doesn't get confused. After + * all, even though nss-systemd synthesizes these users/groups, they should still appear in + * /etc/passwd and /etc/group, as the synthesizing logic is merely supposed to be fallback for cases + * where we run with a completely unpopulated /etc. */ if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0) return log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m"); |