]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
coredump-context: several cleanups
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 17 Oct 2025 00:30:33 +0000 (09:30 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 28 Oct 2025 05:31:41 +0000 (14:31 +0900)
- Renames Context to CoredumpContext.
- Renames enum meta_argv_t to MetadataField, and use the correct type at
  several pleaces, especially in loop.
- Parses argv (when invoked as kernel helper or with '--backtrace') or
  iov (when invoked through socket) and store values in the context.
  Previously we use the passed string as is, but let's make them in a
  type safe way.
- Stores received or built iovw in the context. Also store input fd and
  mountfs fd in the context.
- Introduces coredump_context_is_pid1() and _is_journald() helper
  functions.
- Adds COREDUMP_PIDFDID= field when the kernel passed pidfd of the
  crashed process.

No effective funtional change. Just refactoring.

src/coredump/coredump-backtrace.c
src/coredump/coredump-context.c
src/coredump/coredump-context.h
src/coredump/coredump-forward.h
src/coredump/coredump-kernel-helper.c
src/coredump/coredump-receive.c
src/coredump/coredump-send.c
src/coredump/coredump-send.h
src/coredump/coredump-submit.c
src/coredump/coredump-submit.h

index 4d80cae24c84e0e43be93024f33f7e5b499179c6..f18b5ff80081a19528e1a671dbdb050c91dbe0e8 100644 (file)
@@ -5,15 +5,15 @@
 
 #include "coredump-backtrace.h"
 #include "coredump-context.h"
-#include "iovec-util.h"
+#include "format-util.h"
 #include "journal-importer.h"
 #include "log.h"
 #include "string-util.h"
+#include "user-util.h"
 
 int coredump_backtrace(int argc, char *argv[]) {
         _cleanup_(journal_importer_cleanup) JournalImporter importer = JOURNAL_IMPORTER_INIT(STDIN_FILENO);
-        _cleanup_(iovw_free_freep) struct iovec_wrapper *iovw = NULL;
-        _cleanup_(context_done) Context context = CONTEXT_NULL;
+        _cleanup_(coredump_context_done) CoredumpContext context = COREDUMP_CONTEXT_NULL;
         int r;
 
         assert(argc >= 2);
@@ -21,23 +21,17 @@ int coredump_backtrace(int argc, char *argv[]) {
         log_setup();
         log_debug("Processing backtrace on stdin...");
 
-        iovw = iovw_new();
-        if (!iovw)
-                return log_oom();
-
-        (void) iovw_put_string_field(iovw, "MESSAGE_ID=", SD_MESSAGE_BACKTRACE_STR);
-        (void) iovw_put_string_field(iovw, "PRIORITY=", STRINGIFY(LOG_CRIT));
-
         /* Collect all process metadata from argv[] by making sure to skip the '--backtrace' option. */
-        r = gather_pid_metadata_from_argv(iovw, &context, argc - 2, argv + 2);
+        r = coredump_context_parse_from_argv(&context, argc - 2, argv + 2);
         if (r < 0)
                 return r;
 
-        /* Collect the rest of the process metadata retrieved from the runtime */
-        r = gather_pid_metadata_from_procfs(iovw, &context);
+        r = coredump_context_build_iovw(&context);
         if (r < 0)
                 return r;
 
+        (void) iovw_replace_string_field(&context.iovw, "MESSAGE_ID=", SD_MESSAGE_BACKTRACE_STR);
+
         for (;;) {
                 r = journal_importer_process_data(&importer);
                 if (r < 0)
@@ -49,24 +43,19 @@ int coredump_backtrace(int argc, char *argv[]) {
 
         if (journal_importer_eof(&importer)) {
                 log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter.");
-
-                const char *message = strjoina("Process ", context.meta[META_ARGV_PID],
-                                               " (", context.meta[META_COMM], ")"
-                                               " of user ", context.meta[META_ARGV_UID],
-                                               " failed with ", context.meta[META_ARGV_SIGNAL]);
-
-                r = iovw_put_string_field(iovw, "MESSAGE=", message);
+                r = iovw_put_string_fieldf(&context.iovw, "MESSAGE=", "Process "PID_FMT" (%s) of user "UID_FMT" failed with %i.",
+                                           context.pidref.pid, context.comm, context.uid, context.signo);
                 if (r < 0)
                         return r;
         } else {
                 /* The imported iovecs are not supposed to be freed by us so let's copy and merge them at the
                  * end of the array. */
-                r = iovw_append(iovw, &importer.iovw);
+                r = iovw_append(&context.iovw, &importer.iovw);
                 if (r < 0)
                         return r;
         }
 
-        r = sd_journal_sendv(iovw->iovec, iovw->count);
+        r = sd_journal_sendv(context.iovw.iovec, context.iovw.count);
         if (r < 0)
                 return log_error_errno(r, "Failed to log backtrace: %m");
 
index 6e62c4615f4eea13478fa0ed0d6fc82e1493763a..db5dd2e141692082a0f04db94d905a28cc06aac0 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "sd-login.h"
+#include "sd-messages.h"
 
 #include "coredump-config.h"
 #include "coredump-context.h"
@@ -8,6 +9,7 @@
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fs-util.h"
+#include "hostname-util.h"
 #include "iovec-wrapper.h"
 #include "log.h"
 #include "memstream-util.h"
 #include "process-util.h"
 #include "signal-util.h"
 #include "special.h"
+#include "string-table.h"
 #include "string-util.h"
+#include "time-util.h"
 #include "user-util.h"
 
-const char * const meta_field_names[_META_MAX] = {
+static const char * const metadata_field_table[_META_MAX] = {
         [META_ARGV_PID]       = "COREDUMP_PID=",
         [META_ARGV_UID]       = "COREDUMP_UID=",
         [META_ARGV_GID]       = "COREDUMP_GID=",
@@ -35,11 +39,30 @@ const char * const meta_field_names[_META_MAX] = {
         [META_PROC_AUXV]      = "COREDUMP_PROC_AUXV=",
 };
 
-void context_done(Context *c) {
-        assert(c);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(metadata_field, MetadataField);
 
-        pidref_done(&c->pidref);
-        c->mount_tree_fd = safe_close(c->mount_tree_fd);
+void coredump_context_done(CoredumpContext *context) {
+        assert(context);
+
+        pidref_done(&context->pidref);
+        free(context->hostname);
+        free(context->comm);
+        free(context->exe);
+        free(context->unit);
+        free(context->auxv);
+        safe_close(context->mount_tree_fd);
+        iovw_done_free(&context->iovw);
+        safe_close(context->input_fd);
+}
+
+bool coredump_context_is_pid1(CoredumpContext *context) {
+        assert(context);
+        return context->pidref.pid == 1 || streq_ptr(context->unit, SPECIAL_INIT_SCOPE);
+}
+
+bool coredump_context_is_journald(CoredumpContext *context) {
+        assert(context);
+        return streq_ptr(context->unit, SPECIAL_JOURNALD_SERVICE);
 }
 
 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
@@ -150,305 +173,388 @@ static int get_process_container_parent_cmdline(PidRef *pid, char** ret_cmdline)
         return 1;
 }
 
-int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *context) {
+int coredump_context_build_iovw(CoredumpContext *context) {
         char *t;
-        size_t size;
         int r;
 
-        assert(iovw);
         assert(context);
+        assert(pidref_is_set(&context->pidref));
 
-        /* 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 iovec fields initialized.) */
+        if (!iovw_isempty(&context->iovw))
+                return 0;
 
         pid_t pid = context->pidref.pid;
 
-        /* The following is mandatory */
-        r = pidref_get_comm(&context->pidref, &t);
+        r = iovw_put_string_fieldf(&context->iovw, "COREDUMP_PID=", PID_FMT, context->pidref.pid);
         if (r < 0)
-                return log_error_errno(r, "Failed to get COMM: %m");
+                return log_error_errno(r, "Failed to add COREDUMP_PID= field: %m");
+
+        if (context->got_pidfd) {
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_BY_PIDFD=", "1");
 
-        r = iovw_put_string_field_free(iovw, "COREDUMP_COMM=", t);
+                if (pidref_acquire_pidfd_id(&context->pidref) >= 0)
+                        (void) iovw_put_string_fieldf(&context->iovw, "COREDUMP_PIDFDID=", "%"PRIu64, context->pidref.fd_id);
+        }
+
+        r = iovw_put_string_fieldf(&context->iovw, "COREDUMP_UID=", UID_FMT, context->uid);
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to add COREDUMP_UID= field: %m");
 
-        /* The following are optional, but we use them if present. */
-        r = get_process_exe(pid, &t);
-        if (r >= 0)
-                r = iovw_put_string_field_free(iovw, "COREDUMP_EXE=", t);
+        r = iovw_put_string_fieldf(&context->iovw, "COREDUMP_GID=", UID_FMT, context->gid);
         if (r < 0)
-                log_warning_errno(r, "Failed to get EXE, ignoring: %m");
+                return log_error_errno(r, "Failed to add COREDUMP_GID= field: %m");
+
+        if (SIGNAL_VALID(context->signo)) {
+                r = iovw_put_string_fieldf(&context->iovw, "COREDUMP_SIGNAL=", "%i", context->signo);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add COREDUMP_SIGNAL= field: %m");
 
-        if (cg_pidref_get_unit(&context->pidref, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_UNIT=", t);
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(context->signo));
+        }
+
+        r = iovw_put_string_fieldf(&context->iovw, "COREDUMP_TIMESTAMP=", USEC_FMT, context->timestamp);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add COREDUMP_TIMESTAMP= field: %m");
+
+        r = iovw_put_string_fieldf(&context->iovw, "COREDUMP_RLIMIT=", "%"PRIu64, context->rlimit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add COREDUMP_RLIMIT= field: %m");
+
+        if (context->hostname)
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_HOSTNAME=", context->hostname);
+
+        (void) iovw_put_string_fieldf(&context->iovw, "COREDUMP_DUMPABLE=", "%u", context->dumpable);
+
+        r = iovw_put_string_field(&context->iovw, "COREDUMP_COMM=", context->comm);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add COREDUMP_COMM= field: %m");
+
+        if (context->exe)
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_EXE=", context->exe);
+
+        (void) iovw_put_string_field(&context->iovw, "COREDUMP_UNIT=", context->unit);
 
         if (cg_pidref_get_user_unit(&context->pidref, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_USER_UNIT=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_USER_UNIT=", t);
 
         if (cg_pidref_get_session(&context->pidref, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_SESSION=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_SESSION=", t);
 
         uid_t owner_uid;
-        if (cg_pidref_get_owner_uid(&context->pidref, &owner_uid) >= 0) {
-                r = asprintf(&t, UID_FMT, owner_uid);
-                if (r > 0)
-                        (void) iovw_put_string_field_free(iovw, "COREDUMP_OWNER_UID=", t);
-        }
+        if (cg_pidref_get_owner_uid(&context->pidref, &owner_uid) >= 0)
+                (void) iovw_put_string_fieldf(&context->iovw, "COREDUMP_OWNER_UID=", UID_FMT, owner_uid);
 
         if (sd_pid_get_slice(pid, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_SLICE=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_SLICE=", t);
 
         if (pidref_get_cmdline(&context->pidref, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_CMDLINE=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_CMDLINE=", t);
 
         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_CGROUP=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_CGROUP=", t);
 
         if (compose_open_fds(pid, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_OPEN_FDS=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_OPEN_FDS=", t);
 
         if (read_full_file(procfs_file_alloca(pid, "status"), &t, /* ret_size= */ NULL) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_STATUS=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_PROC_STATUS=", t);
 
         if (read_full_file(procfs_file_alloca(pid, "maps"), &t, /* ret_size= */ NULL) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MAPS=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_PROC_MAPS=", t);
 
         if (read_full_file(procfs_file_alloca(pid, "limits"), &t, /* ret_size= */ NULL) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_LIMITS=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_PROC_LIMITS=", t);
 
         if (read_full_file(procfs_file_alloca(pid, "cgroup"), &t, /* ret_size= */ NULL) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_CGROUP=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_PROC_CGROUP=", t);
 
         if (read_full_file(procfs_file_alloca(pid, "mountinfo"), &t, /* ret_size= */ NULL) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MOUNTINFO=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_PROC_MOUNTINFO=", t);
 
         /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */
-        if (read_full_file(procfs_file_alloca(pid, "auxv"), &t, &size) >= 0) {
-                char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1);
+        if (context->auxv) {
+                size_t sz = STRLEN("COREDUMP_PROC_AUXV=") + context->auxv_size;
+                char *buf = malloc(sz + 1);
                 if (buf) {
-                        /* Add a dummy terminator to make context_parse_iovw() happy. */
-                        *mempcpy_typesafe(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size) = '\0';
-                        (void) iovw_consume(iovw, buf, size + strlen("COREDUMP_PROC_AUXV="));
+                        /* Add a dummy terminator to make coredump_context_parse_iovw() happy. */
+                        *mempcpy_typesafe(stpcpy(buf, "COREDUMP_PROC_AUXV="), context->auxv, context->auxv_size) = '\0';
+                        (void) iovw_consume(&context->iovw, buf, sz);
                 }
-
-                free(t);
         }
 
         if (get_process_cwd(pid, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_CWD=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_CWD=", t);
 
         if (get_process_root(pid, &t) >= 0) {
                 bool proc_self_root_is_slash;
 
                 proc_self_root_is_slash = strcmp(t, "/") == 0;
 
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_ROOT=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_ROOT=", t);
 
                 /* 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(&context->pidref, &t) > 0)
-                        (void) iovw_put_string_field_free(iovw, "COREDUMP_CONTAINER_CMDLINE=", t);
+                        (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_CONTAINER_CMDLINE=", t);
         }
 
         if (get_process_environ(pid, &t) >= 0)
-                (void) iovw_put_string_field_free(iovw, "COREDUMP_ENVIRON=", t);
+                (void) iovw_put_string_field_free(&context->iovw, "COREDUMP_ENVIRON=", t);
+
+        if (context->forwarded)
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_FORWARDED=", "1");
+
+        (void) iovw_put_string_field(&context->iovw, "PRIORITY=", STRINGIFY(LOG_CRIT));
+        (void) iovw_put_string_field(&context->iovw, "MESSAGE_ID=", SD_MESSAGE_COREDUMP_STR);
 
         /* Now that we have parsed info from /proc/ ensure the pidfd is still valid before continuing. */
         r = pidref_verify(&context->pidref);
         if (r < 0)
                 return log_error_errno(r, "PIDFD validation failed: %m");
 
-        /* We successfully acquired all metadata. */
-        return context_parse_iovw(context, iovw);
+        return 0;
 }
 
-int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
-        const char *unit;
+static int coredump_context_parse_from_procfs(CoredumpContext *context) {
         int r;
 
         assert(context);
-        assert(iovw);
+        assert(pidref_is_set(&context->pidref));
 
-        /* Converts the data in the iovec array iovw into separate fields. Fills in context->meta[] (for
-         * which no memory is allocated, it just contains direct pointers into the iovec array memory). */
+        pid_t pid = context->pidref.pid;
 
-        bool have_signal_name = false;
-        FOREACH_ARRAY(iovec, iovw->iovec, iovw->count) {
-                /* Note that these strings are NUL-terminated, because we made sure that a trailing NUL byte
-                 * is in the buffer, though not included in the iov_len count. See coredump_receive() and
-                 * gather_pid_metadata_*(). */
-                assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
+        r = pidref_get_comm(&context->pidref, &context->comm);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get COMM: %m");
 
-                for (size_t i = 0; i < ELEMENTSOF(meta_field_names); i++) {
-                        const char *p = memory_startswith(iovec->iov_base, iovec->iov_len, meta_field_names[i]);
-                        if (p) {
-                                context->meta[i] = p;
-                                context->meta_size[i] = iovec->iov_len - strlen(meta_field_names[i]);
-                                break;
-                        }
-                }
+        r = get_process_exe(pid, &context->exe);
+        if (r < 0)
+                log_warning_errno(r, "Failed to get EXE, ignoring: %m");
 
-                have_signal_name = have_signal_name ||
-                        memory_startswith(iovec->iov_base, iovec->iov_len, "COREDUMP_SIGNAL_NAME=");
-        }
+        r = cg_pidref_get_unit(&context->pidref, &context->unit);
+        if (r < 0)
+                log_warning_errno(r, "Failed to get unit, ignoring: %m");
 
-        /* The basic fields from argv[] should always be there, refuse early if not. */
-        for (int i = 0; i < _META_ARGV_REQUIRED; i++)
-                if (!context->meta[i])
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "A required (%s) has not been sent, aborting.", meta_field_names[i]);
+        r = read_full_file(procfs_file_alloca(pid, "auxv"), &context->auxv, &context->auxv_size);
+        if (r < 0)
+                log_warning_errno(r, "Failed to get auxv, ignoring: %m");
 
-        pid_t parsed_pid;
-        r = parse_pid(context->meta[META_ARGV_PID], &parsed_pid);
+        r = pidref_verify(&context->pidref);
         if (r < 0)
-                return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[META_ARGV_PID]);
-        if (pidref_is_set(&context->pidref)) {
-                if (context->pidref.pid != parsed_pid)
-                        return log_error_errno(r, "Passed PID " PID_FMT " does not match passed " PID_FMT ": %m",
-                                               parsed_pid, context->pidref.pid);
-        } else {
-                r = pidref_set_pid(&context->pidref, parsed_pid);
+                return log_error_errno(r, "PIDFD validation failed: %m");
+
+        return 0;
+}
+
+static int context_parse_one(CoredumpContext *context, MetadataField meta, bool from_argv, const char *s, size_t size) {
+        int r;
+
+        assert(context);
+        assert(s);
+
+        switch (meta) {
+        case META_ARGV_PID: {
+                /* Store this so that we can check whether the core will be forwarded to a container
+                 * even when the kernel doesn't provide a pidfd. Can be dropped once baseline is
+                 * >= v6.16. */
+                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+                r = pidref_set_pidstr(&pidref, s);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to initialize pidref from pid " PID_FMT ": %m", parsed_pid);
+                        return log_error_errno(r, "Failed to initialize pidref from pid %s: %m", s);
+
+                if (pidref_is_set(&context->pidref)) {
+                        if (!pidref_equal(&context->pidref, &pidref))
+                                return log_error_errno(SYNTHETIC_ERRNO(ESTALE), "Received conflicting pid: %s", s);
+                } else
+                        context->pidref = TAKE_PIDREF(pidref);
+                return 0;
         }
+        case META_ARGV_UID:
+                r = parse_uid(s, &context->uid);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse UID \"%s\": %m", s);
+                return 0;
 
-        r = parse_uid(context->meta[META_ARGV_UID], &context->uid);
-        if (r < 0)
-                return log_error_errno(r, "Failed to parse UID \"%s\": %m", context->meta[META_ARGV_UID]);
+        case META_ARGV_GID:
+                r = parse_gid(s, &context->gid);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse GID \"%s\": %m", s);
+                return 0;
 
-        r = parse_gid(context->meta[META_ARGV_GID], &context->gid);
-        if (r < 0)
-                return log_error_errno(r, "Failed to parse GID \"%s\": %m", context->meta[META_ARGV_GID]);
+        case META_ARGV_SIGNAL:
+                r = parse_signo(s, &context->signo);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse signal number \"%s\", ignoring: %m", s);
+                return 0;
 
-        r = parse_signo(context->meta[META_ARGV_SIGNAL], &context->signo);
-        if (r < 0)
-                log_warning_errno(r, "Failed to parse signal number \"%s\", ignoring: %m", context->meta[META_ARGV_SIGNAL]);
+        case META_ARGV_TIMESTAMP:
+                /* The kernel provides 1 sec granularity timestamps, while we forward it with 1 Î¼sec granularity. */
+                r = parse_time(s, &context->timestamp, from_argv ? USEC_PER_SEC : 1);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse timestamp \"%s\", ignoring: %m", s);
+                return 0;
 
-        r = safe_atou64(context->meta[META_ARGV_RLIMIT], &context->rlimit);
-        if (r < 0)
-                log_warning_errno(r, "Failed to parse resource limit \"%s\", ignoring: %m", context->meta[META_ARGV_RLIMIT]);
+        case META_ARGV_RLIMIT:
+                r = safe_atou64(s, &context->rlimit);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse resource limit \"%s\", ignoring: %m", s);
+                return 0;
+
+        case META_ARGV_HOSTNAME:
+                if (!hostname_is_valid(s, /* flags= */ 0)) {
+                        log_warning("Received coredump with an invalid hostname, ignoring: %s", s);
+                        return 0;
+                }
 
-        /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to SUID_DUMP_SAFE (2),
-         * if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */
-        if (context->meta[META_ARGV_DUMPABLE]) {
-                r = safe_atou(context->meta[META_ARGV_DUMPABLE], &context->dumpable);
+                return free_and_strdup_warn(&context->hostname, s);
+
+        case META_ARGV_DUMPABLE:
+                /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to SUID_DUMP_SAFE (2),
+                 * if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */
+                r = safe_atou(s, &context->dumpable);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", context->meta[META_ARGV_DUMPABLE]);
+                        return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", s);
                 if (context->dumpable > SUID_DUMP_SAFE)
                         log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable);
+                return 0;
+
+        case META_ARGV_PIDFD: {
+                /* We do not forward the index of the file descriptor, as it is meaningless, and always set to 1. */
+                if (!from_argv) {
+                        if (!streq(s, "1"))
+                                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Received unexpected pidfd field: %s", s);
+                        if (!pidref_is_set(&context->pidref) || !context->got_pidfd)
+                                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Received unexpected pidfd field without pidfd.");
+                        return 0;
+                }
+
+                /* If the current kernel doesn't support the %F specifier (which resolves to a pidfd), but we
+                 * included it in the core_pattern expression, we'll receive an empty string here. Deal with
+                 * that gracefully. */
+                if (isempty(s))
+                        return 0;
+
+                r = parse_fd(s);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse pidfd \"%s\": %m", s);
+
+                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+                r = pidref_set_pidfd_consume(&pidref, r);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to initialize pidref from pidfd \"%s\": %m", s);
+
+                if (pidref_is_set(&context->pidref) && !pidref_equal(&context->pidref, &pidref))
+                        return log_error_errno(SYNTHETIC_ERRNO(ESTALE), "Received conflicting pidfd: %s", s);
+
+                /* pidref by pidfd has higher preference over one by pid. */
+                pidref_done(&context->pidref);
+                context->pidref = TAKE_PIDREF(pidref);
+
+                context->got_pidfd = 1;
+                return 0;
         }
+        case META_COMM:
+                return free_and_strdup_warn(&context->comm, s);
 
-        unit = context->meta[META_UNIT];
-        context->is_pid1 = streq(context->meta[META_ARGV_PID], "1") || streq_ptr(unit, SPECIAL_INIT_SCOPE);
-        context->is_journald = streq_ptr(unit, SPECIAL_JOURNALD_SERVICE);
+        case META_EXE:
+                return free_and_strdup_warn(&context->exe, s);
 
-        /* After parsing everything, let's also synthesize a new iovw field for the textual signal name if it
-         * isn't already set. */
-        if (SIGNAL_VALID(context->signo) && !have_signal_name)
-                (void) iovw_put_string_field(iovw, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(context->signo));
+        case META_UNIT:
+                return free_and_strdup_warn(&context->unit, s);
 
-        return 0;
-}
+        case META_PROC_AUXV: {
+                char *t = memdup_suffix0(s, size);
+                if (!t)
+                        return log_oom();
 
-int gather_pid_metadata_from_argv(
-                struct iovec_wrapper *iovw,
-                Context *context,
-                int argc, char **argv) {
+                context->auxv_size = size;
+                return free_and_replace(context->auxv, t);
+        }
 
-        _cleanup_(pidref_done) PidRef local_pidref = PIDREF_NULL;
-        int r, kernel_fd = -EBADF;
+        default:
+                assert_not_reached();
+        }
+}
+
+int coredump_context_parse_iovw(CoredumpContext *context) {
+        int r;
 
-        assert(iovw);
         assert(context);
 
-        /* We gather all metadata that were passed via argv[] into an array of iovecs that
-         * we'll forward to the socket unit.
-         *
-         * We require at least _META_ARGV_REQUIRED args, but will accept more.
-         * We know how to parse _META_ARGV_MAX args. The rest will be ignored. */
+        /* Parse the data in the iovec array iovw into separate fields. */
 
-        if (argc < _META_ARGV_REQUIRED)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Not enough arguments passed by the kernel (%i, expected between %i and %i).",
-                                       argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
+        bool have[_META_MAX] = {};
+        FOREACH_ARRAY(iovec, context->iovw.iovec, context->iovw.count) {
+                /* Note that these strings are NUL-terminated, because we made sure that a trailing NUL byte
+                 * is in the buffer, though not included in the iov_len count. See coredump_receive() and
+                 * coredump_context_parse_from_*(). */
+                assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
 
-        for (int i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
-                _cleanup_free_ char *buf = NULL;
-                const char *t = argv[i];
+                for (MetadataField i = 0; i < _META_MAX; i++) {
+                        const char *s = metadata_field_to_string(i);
+                        const char *p = memory_startswith(iovec->iov_base, iovec->iov_len, s);
+                        if (!p)
+                                continue;
 
-                if (i == META_ARGV_TIMESTAMP) {
-                        /* The journal fields contain the timestamp padded with six
-                         * zeroes, so that the kernel-supplied 1s granularity timestamps
-                         * becomes 1μs granularity, i.e. the granularity systemd usually
-                         * operates in. */
-                        buf = strjoin(argv[i], "000000");
-                        if (!buf)
-                                return log_oom();
+                        size_t size = iovec->iov_len - strlen(s);
+                        if (i != META_PROC_AUXV && strlen(p) != size)
+                                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "%s= field contains NUL character.", s);
 
-                        t = buf;
-                }
+                        if (have[i])
+                                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Message contains duplicated field: %s", s);
+
+                        have[i] = true;
 
-                if (i == META_ARGV_PID) {
-                        /* Store this so that we can check whether the core will be forwarded to a container
-                         * even when the kernel doesn't provide a pidfd. Can be dropped once baseline is
-                         * >= v6.16. */
-                        r = pidref_set_pidstr(&local_pidref, t);
+                        r = context_parse_one(context, i, /* from_argv= */ false, p, size);
                         if (r < 0)
-                                return log_error_errno(r, "Failed to initialize pidref from pid %s: %m", t);
-                }
+                                return r;
 
-                if (i == META_ARGV_PIDFD) {
-                        /* If the current kernel doesn't support the %F specifier (which resolves to a
-                         * pidfd), but we included it in the core_pattern expression, we'll receive an empty
-                         * string here. Deal with that gracefully. */
-                        if (isempty(t))
-                                continue;
+                        break;
+                }
+        }
 
-                        assert(!pidref_is_set(&context->pidref));
-                        assert(kernel_fd < 0);
+        /* Make sure we received all the expected fields. We support being called by an *older* systemd-coredump
+         * from the outside, so we require only the basic set of fields that was being sent when the support for
+         * sending to containers over a socket was added in a108c43e36d3ceb6e34efe37c014fc2cda856000. */
+        MetadataField i;
+        FOREACH_ARGUMENT(i,
+                         META_ARGV_PID,
+                         META_ARGV_UID,
+                         META_ARGV_GID,
+                         META_ARGV_SIGNAL,
+                         META_ARGV_TIMESTAMP,
+                         META_ARGV_RLIMIT,
+                         META_ARGV_HOSTNAME,
+                         META_COMM)
+                if (!have[i])
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Mandatory argument %s not received on socket.",
+                                               metadata_field_to_string(i));
 
-                        kernel_fd = parse_fd(t);
-                        if (kernel_fd < 0)
-                                return log_error_errno(kernel_fd, "Failed to parse pidfd \"%s\": %m", t);
+        return 0;
+}
 
-                        r = pidref_set_pidfd(&context->pidref, kernel_fd);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to initialize pidref from pidfd %d: %m", kernel_fd);
+int coredump_context_parse_from_argv(CoredumpContext *context, int argc, char **argv) {
+        int r;
 
-                        context->got_pidfd = 1;
+        assert(context);
 
-                        /* If there are containers involved with different versions of the code they might
-                         * not be using pidfds, so it would be wrong to set the metadata, skip it. */
-                        r = pidref_in_same_namespace(/* pid1 = */ NULL, &context->pidref, NAMESPACE_PID);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to check pidns of crashing process, ignoring: %m");
-                        if (r <= 0)
-                                continue;
+        /* We gather all metadata that were passed via argv[] into an array of iovecs that
+         * we'll forward to the socket unit.
+         *
+         * We require at least _META_ARGV_REQUIRED args, but will accept more.
+         * We know how to parse _META_ARGV_MAX args. The rest will be ignored. */
 
-                        /* We don't print the fd number in the journal as it's meaningless, but we still
-                         * record that the parsing was done with a kernel-provided fd as it means it's safe
-                         * from races, which is valuable information to provide in the journal record. */
-                        t = "1";
-                }
+        if (argc < _META_ARGV_REQUIRED)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Not enough arguments passed by the kernel (%i, expected between %i and %i).",
+                                       argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
 
-                r = iovw_put_string_field(iovw, meta_field_names[i], t);
+        for (MetadataField i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
+                r = context_parse_one(context, i, /* from_argv= */ true, argv[i], SIZE_MAX);
                 if (r < 0)
                         return r;
         }
 
-        /* Cache some of the process metadata we collected so far and that we'll need to
-         * access soon. */
-        r = context_parse_iovw(context, iovw);
-        if (r < 0)
-                return r;
-
-        /* If the kernel didn't give us a PIDFD, then use the one derived from the
-         * PID immediately, given we have it. */
-        if (!pidref_is_set(&context->pidref))
-                context->pidref = TAKE_PIDREF(local_pidref);
-
-        /* Close the kernel-provided FD as the last thing after everything else succeeded. */
-        kernel_fd = safe_close(kernel_fd);
-
-        return 0;
+        return coredump_context_parse_from_procfs(context);
 }
index 31c236ebc4933511b82c20727e3c58ea5b60b5f9..32557348f92076291c8a158306c0bf070b5eaa5a 100644 (file)
@@ -2,9 +2,10 @@
 #pragma once
 
 #include "coredump-forward.h"
+#include "iovec-wrapper.h"
 #include "pidref.h"
 
-typedef enum {
+typedef enum MetadataField {
         /* We use these as array indexes for our process metadata cache.
          *
          * The first indices of the cache stores the same metadata as the ones passed by the kernel via
@@ -39,37 +40,43 @@ typedef enum {
         META_EXE,
         META_UNIT,
         META_PROC_AUXV,
-        _META_MAX
-} meta_argv_t;
+        _META_MAX,
+        _META_INVALID = -EINVAL,
+} MetadataField;
 
-extern const char * const meta_field_names[_META_MAX];
-
-struct Context {
-        PidRef pidref;
-        uid_t uid;
-        gid_t gid;
-        unsigned dumpable;
-        int signo;
-        uint64_t rlimit;
-        bool is_pid1;
-        bool is_journald;
-        bool got_pidfd;
+struct CoredumpContext {
+        PidRef pidref;     /* META_ARGV_PID and META_ARGV_PIDFD */
+        uid_t uid;         /* META_ARGV_UID */
+        gid_t gid;         /* META_ARGV_GID */
+        int signo;         /* META_ARGV_SIGNAL */
+        usec_t timestamp;  /* META_ARGV_TIMESTAMP */
+        uint64_t rlimit;   /* META_ARGV_RLIMIT */
+        char *hostname;    /* META_ARGV_HOSTNAME */
+        unsigned dumpable; /* META_ARGV_DUMPABLE */
+        char *comm;        /* META_COMM */
+        char *exe;         /* META_EXE */
+        char *unit;        /* META_UNIT */
+        char *auxv;        /* META_PROC_AUXV */
+        size_t auxv_size;  /* META_PROC_AUXV */
+        bool got_pidfd;    /* META_ARGV_PIDFD */
+        bool forwarded;
+        int input_fd;
         int mount_tree_fd;
-
-        /* These point into external memory, are not owned by this object */
-        const char *meta[_META_MAX];
-        size_t meta_size[_META_MAX];
+        struct iovec_wrapper iovw;
 };
 
-#define CONTEXT_NULL                            \
-        (Context) {                             \
+#define COREDUMP_CONTEXT_NULL                   \
+        (CoredumpContext) {                     \
                 .pidref = PIDREF_NULL,          \
                 .uid = UID_INVALID,             \
                 .gid = GID_INVALID,             \
                 .mount_tree_fd = -EBADF,        \
+                .input_fd = -EBADF,             \
         }
 
-void context_done(Context *c);
-int context_parse_iovw(Context *context, struct iovec_wrapper *iovw);
-int gather_pid_metadata_from_argv(struct iovec_wrapper *iovw, Context *context, int argc, char **argv);
-int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *context);
+void coredump_context_done(CoredumpContext *context);
+bool coredump_context_is_pid1(CoredumpContext *context);
+bool coredump_context_is_journald(CoredumpContext *context);
+int coredump_context_build_iovw(CoredumpContext *context);
+int coredump_context_parse_iovw(CoredumpContext *context);
+int coredump_context_parse_from_argv(CoredumpContext *context, int argc, char **argv);
index b5a2d51a5e0e26500b16c1e7a6336fa55eb195f7..0fa18a4a127fc7e52eb17eb6572cadd73cd7bc08 100644 (file)
@@ -4,4 +4,4 @@
 #include "basic-forward.h"
 
 typedef struct CoredumpConfig CoredumpConfig;
-typedef struct Context Context;
+typedef struct CoredumpContext CoredumpContext;
index 9cac410b032c3991ce248acf2fa074b591c6d552..8b75382aba0ba35bcbe2c682fa2499e409c0461c 100644 (file)
@@ -1,7 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#include "sd-messages.h"
-
 #include "coredump-config.h"
 #include "coredump-context.h"
 #include "coredump-kernel-helper.h"
@@ -9,22 +7,28 @@
 #include "coredump-submit.h"
 #include "coredump-util.h"
 #include "fd-util.h"
+#include "format-util.h"
 #include "iovec-wrapper.h"
 #include "log.h"
 #include "namespace-util.h"
 #include "signal-util.h"
 
 int coredump_kernel_helper(int argc, char *argv[]) {
-        _cleanup_(iovw_free_freep) struct iovec_wrapper *iovw = NULL;
-        _cleanup_(context_done) Context context = CONTEXT_NULL;
+        _cleanup_(coredump_context_done) CoredumpContext context = COREDUMP_CONTEXT_NULL;
         int r;
 
         /* When we're invoked by the kernel, stdout/stderr are closed which is dangerous because the fds
          * could get reallocated. To avoid hard to debug issues, let's instead bind stdout/stderr to
-         * /dev/null. */
-        r = rearrange_stdio(STDIN_FILENO, -EBADF, -EBADF);
+         * /dev/null. Also, move stdin to above stdio and then also bind stdin to /dev/null. */
+
+        r = fd_move_above_stdio(STDIN_FILENO);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect stdout/stderr to /dev/null: %m");
+                return log_error_errno(r, "Failed to move stdin above stdio: %m");
+        context.input_fd = r;
+
+        r = make_null_stdio();
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect stdin/stdout/stderr to /dev/null: %m");
 
         /* Ignore all parse errors */
         CoredumpConfig config = COREDUMP_CONFIG_NULL;
@@ -32,28 +36,18 @@ int coredump_kernel_helper(int argc, char *argv[]) {
 
         log_debug("Processing coredump received from the kernel...");
 
-        iovw = iovw_new();
-        if (!iovw)
-                return log_oom();
-
         /* Collect all process metadata passed by the kernel through argv[] */
-        r = gather_pid_metadata_from_argv(iovw, &context, argc - 1, argv + 1);
+        r = coredump_context_parse_from_argv(&context, argc - 1, argv + 1);
         if (r < 0)
                 return r;
 
-        /* Collect the rest of the process metadata retrieved from the runtime */
-        r = gather_pid_metadata_from_procfs(iovw, &context);
-        if (r < 0)
-                return r;
-
-        if (!context.is_journald)
+        if (!coredump_context_is_journald(&context))
                 /* OK, now we know it's not the journal, hence we can make use of it now. */
                 log_set_target_and_open(LOG_TARGET_JOURNAL_OR_KMSG);
 
         /* Log minimal metadata now, so it is not lost if the system is about to shut down. */
-        log_info("Process %s (%s) of user %s terminated abnormally with signal %s/%s, processing...",
-                 context.meta[META_ARGV_PID], context.meta[META_COMM],
-                 context.meta[META_ARGV_UID], context.meta[META_ARGV_SIGNAL],
+        log_info("Process "PID_FMT" (%s) of user "UID_FMT" terminated abnormally with signal %i/%s, processing...",
+                 context.pidref.pid, context.comm, context.uid, context.signo,
                  signal_to_string(context.signo));
 
         r = pidref_in_same_namespace(/* pid1 = */ NULL, &context.pidref, NAMESPACE_PID);
@@ -66,9 +60,7 @@ int coredump_kernel_helper(int argc, char *argv[]) {
                 if (r >= 0)
                         return 0;
 
-                r = acquire_pid_mount_tree_fd(&config, &context, &context.mount_tree_fd);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to access the mount tree of a container, ignoring: %m");
+                (void) acquire_pid_mount_tree_fd(&config, &context);
         }
 
         /* If this is PID 1, disable coredump collection, we'll unlikely be able to process
@@ -77,16 +69,17 @@ int coredump_kernel_helper(int argc, char *argv[]) {
          * FIXME: maybe we should disable coredumps generation from the beginning and
          * re-enable it only when we know it's either safe (i.e. we're not running OOM) or
          * it's not PID 1 ? */
-        if (context.is_pid1) {
+        if (coredump_context_is_pid1(&context)) {
                 log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
                 disable_coredumps();
         }
 
-        (void) iovw_put_string_field(iovw, "MESSAGE_ID=", SD_MESSAGE_COREDUMP_STR);
-        (void) iovw_put_string_field(iovw, "PRIORITY=", STRINGIFY(LOG_CRIT));
+        if (coredump_context_is_journald(&context) || coredump_context_is_pid1(&context))
+                return coredump_submit(&config, &context);
 
-        if (context.is_journald || context.is_pid1)
-                return coredump_submit(&config, &context, iovw, STDIN_FILENO);
+        r = coredump_context_build_iovw(&context);
+        if (r < 0)
+                return r;
 
-        return coredump_send(iovw, STDIN_FILENO, &context.pidref, context.mount_tree_fd);
+        return coredump_send(&context);
 }
index be786be2f1ad0dd13b265ff4b0be5d53208c669e..c1d2df4a7daa9676e74de796fc372f9102d2b441 100644 (file)
@@ -13,9 +13,7 @@
 #include "socket-util.h"
 
 int coredump_receive(int fd) {
-        _cleanup_(iovw_done_free) struct iovec_wrapper iovw = {};
-        _cleanup_(context_done) Context context = CONTEXT_NULL;
-        _cleanup_close_ int input_fd = -EBADF;
+        _cleanup_(coredump_context_done) CoredumpContext context = COREDUMP_CONTEXT_NULL;
         enum {
                 STATE_PAYLOAD,
                 STATE_INPUT_FD_DONE,
@@ -90,8 +88,8 @@ int coredump_receive(int fd) {
                         switch (state) {
 
                         case STATE_PAYLOAD:
-                                assert(input_fd < 0);
-                                input_fd = *CMSG_TYPED_DATA(found, int);
+                                assert(context.input_fd < 0);
+                                context.input_fd = *CMSG_TYPED_DATA(found, int);
                                 state = STATE_INPUT_FD_DONE;
                                 continue;
 
@@ -102,6 +100,7 @@ int coredump_receive(int fd) {
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to initialize pidref: %m");
 
+                                context.got_pidfd = true;
                                 state = STATE_PID_FD_DONE;
                                 continue;
 
@@ -130,37 +129,18 @@ int coredump_receive(int fd) {
                 ((char*) iovec.iov_base)[n] = 0;
                 iovec.iov_len = (size_t) n;
 
-                if (iovw_put(&iovw, iovec.iov_base, iovec.iov_len) < 0)
+                if (iovw_put(&context.iovw, iovec.iov_base, iovec.iov_len) < 0)
                         return log_oom();
 
                 TAKE_STRUCT(iovec);
         }
 
         /* Make sure we got all data we really need */
-        assert(input_fd >= 0);
+        assert(context.input_fd >= 0);
 
-        r = context_parse_iovw(&context, &iovw);
+        r = coredump_context_parse_iovw(&context);
         if (r < 0)
                 return r;
 
-        /* Make sure we received all the expected fields. We support being called by an *older*
-         * systemd-coredump from the outside, so we require only the basic set of fields that
-         * was being sent when the support for sending to containers over a socket was added
-         * in a108c43e36d3ceb6e34efe37c014fc2cda856000. */
-        meta_argv_t i;
-        FOREACH_ARGUMENT(i,
-                         META_ARGV_PID,
-                         META_ARGV_UID,
-                         META_ARGV_GID,
-                         META_ARGV_SIGNAL,
-                         META_ARGV_TIMESTAMP,
-                         META_ARGV_RLIMIT,
-                         META_ARGV_HOSTNAME,
-                         META_COMM)
-                if (!context.meta[i])
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "Mandatory argument %s not received on socket, aborting.",
-                                               meta_field_names[i]);
-
-        return coredump_submit(&config, &context, &iovw, input_fd);
+        return coredump_submit(&config, &context);
 }
index ef2fc02ceb000f7ea4fd2960bfb607ad085a3926..f178a3bf8c310018b451db8736114d5446967a57 100644 (file)
@@ -2,8 +2,6 @@
 
 #include <unistd.h>
 
-#include "sd-messages.h"
-
 #include "coredump-context.h"
 #include "coredump-send.h"
 #include "coredump-util.h"
 #include "process-util.h"
 #include "socket-util.h"
 
-int coredump_send(const struct iovec_wrapper *iovw, int input_fd, PidRef *pidref, int mount_tree_fd) {
+int coredump_send(CoredumpContext *context) {
         _cleanup_close_ int fd = -EBADF;
         int r;
 
-        assert(iovw);
-        assert(input_fd >= 0);
+        assert(context);
+        assert(context->input_fd >= 0);
 
         fd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0);
         if (fd < 0)
@@ -34,9 +32,9 @@ int coredump_send(const struct iovec_wrapper *iovw, int input_fd, PidRef *pidref
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to coredump service: %m");
 
-        for (size_t i = 0; i < iovw->count; i++) {
+        FOREACH_ARRAY(iovec, context->iovw.iovec, context->iovw.count) {
                 struct msghdr mh = {
-                        .msg_iov = iovw->iovec + i,
+                        .msg_iov = iovec,
                         .msg_iovlen = 1,
                 };
                 struct iovec copy[2];
@@ -57,7 +55,7 @@ int coredump_send(const struct iovec_wrapper *iovw, int input_fd, PidRef *pidref
                                          * iovecs, where the first is a (truncated) copy of
                                          * what we want to send, and the second one contains
                                          * the trailing dots. */
-                                        copy[0] = iovw->iovec[i];
+                                        copy[0] = *iovec;
                                         copy[1] = IOVEC_MAKE(((const char[]){'.', '.', '.'}), 3);
 
                                         mh.msg_iov = copy;
@@ -73,30 +71,30 @@ int coredump_send(const struct iovec_wrapper *iovw, int input_fd, PidRef *pidref
         }
 
         /* First sentinel: the coredump fd */
-        r = send_one_fd(fd, input_fd, 0);
+        r = send_one_fd(fd, context->input_fd, 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to send coredump fd: %m");
 
         /* The optional second sentinel: the pidfd */
-        if (!pidref_is_set(pidref) || pidref->fd < 0) /* If we have no pidfd, stop now */
+        if (!pidref_is_set(&context->pidref) || context->pidref.fd < 0) /* If we have no pidfd, stop now */
                 return 0;
 
-        r = send_one_fd(fd, pidref->fd, 0);
+        r = send_one_fd(fd, context->pidref.fd, 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to send pidfd: %m");
 
         /* The optional third sentinel: the mount tree fd */
-        if (mount_tree_fd < 0) /* If we have no mount tree, stop now */
+        if (context->mount_tree_fd < 0) /* If we have no mount tree, stop now */
                 return 0;
 
-        r = send_one_fd(fd, mount_tree_fd, 0);
+        r = send_one_fd(fd, context->mount_tree_fd, 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to send mount tree fd: %m");
 
         return 0;
 }
 
-static int can_forward_coredump(Context *context, const PidRef *pid) {
+static int can_forward_coredump(CoredumpContext *context, const PidRef *pid) {
         _cleanup_free_ char *cgroup = NULL, *path = NULL, *unit = NULL;
         int r;
 
@@ -192,7 +190,7 @@ static int receive_ucred(int transport_fd, struct ucred *ret_ucred) {
         return 0;
 }
 
-int coredump_send_to_container(Context *context) {
+int coredump_send_to_container(CoredumpContext *context) {
         _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, netnsfd = -EBADF, usernsfd = -EBADF, rootfd = -EBADF;
         _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
         pid_t child;
@@ -249,63 +247,26 @@ int coredump_send_to_container(Context *context) {
                         _exit(EXIT_FAILURE);
                 }
 
-                _cleanup_(iovw_free_freep) struct iovec_wrapper *iovw = iovw_new();
-                if (!iovw) {
-                        log_oom();
+                PidRef pidref;
+                r = pidref_set_pid(&pidref, ucred.pid);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to set pid to pidref: %m");
                         _exit(EXIT_FAILURE);
                 }
 
-                (void) iovw_put_string_field(iovw, "MESSAGE_ID=", SD_MESSAGE_COREDUMP_STR);
-                (void) iovw_put_string_field(iovw, "PRIORITY=", STRINGIFY(LOG_CRIT));
-                (void) iovw_put_string_field(iovw, "COREDUMP_FORWARDED=", "1");
-
-                for (int i = 0; i < _META_ARGV_MAX; i++) {
-                        char buf[DECIMAL_STR_MAX(pid_t)];
-                        const char *t = context->meta[i];
-
-                        /* Patch some of the fields with the translated ucred data */
-                        switch (i) {
-
-                        case META_ARGV_PID:
-                                xsprintf(buf, PID_FMT, ucred.pid);
-                                t = buf;
-                                break;
-
-                        case META_ARGV_UID:
-                                xsprintf(buf, UID_FMT, ucred.uid);
-                                t = buf;
-                                break;
-
-                        case META_ARGV_GID:
-                                xsprintf(buf, GID_FMT, ucred.gid);
-                                t = buf;
-                                break;
-
-                        default:
-                                ;
-                        }
+                pidref_done(&context->pidref);
+                context->pidref = TAKE_PIDREF(pidref);
 
-                        r = iovw_put_string_field(iovw, meta_field_names[i], t);
-                        if (r < 0) {
-                                log_debug_errno(r, "Failed to construct iovec: %m");
-                                _exit(EXIT_FAILURE);
-                        }
-                }
+                context->uid = ucred.uid;
+                context->gid = ucred.gid;
 
-                _cleanup_(context_done) Context child_context = CONTEXT_NULL;
-                r = context_parse_iovw(&child_context, iovw);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to save context: %m");
+                r = coredump_context_build_iovw(context);
+                if (r < 0)
                         _exit(EXIT_FAILURE);
-                }
 
-                r = gather_pid_metadata_from_procfs(iovw, &child_context);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to gather metadata from procfs: %m");
-                        _exit(EXIT_FAILURE);
-                }
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_FORWARDED=", "1");
 
-                r = coredump_send(iovw, STDIN_FILENO, &context->pidref, /* mount_tree_fd= */ -EBADF);
+                r = coredump_send(context);
                 if (r < 0) {
                         log_debug_errno(r, "Failed to send iovec to coredump socket: %m");
                         _exit(EXIT_FAILURE);
index 97ddec26c83755afc4fc4dd1ee2573cf6cd7136a..a68be8e83a7806f68ae54af7ea5673b7ab0918f5 100644 (file)
@@ -3,5 +3,5 @@
 
 #include "coredump-forward.h"
 
-int coredump_send(const struct iovec_wrapper *iovw, int input_fd, PidRef *pidref, int mount_tree_fd);
-int coredump_send_to_container(Context *context);
+int coredump_send(CoredumpContext *context);
+int coredump_send_to_container(CoredumpContext *context);
index 56093e2d7b6576395830e6d3e593a8ab392ef07a..ba11e9001a56d44dd31d1ca605ef07fd78fe3d0d 100644 (file)
@@ -40,6 +40,7 @@
 #include "socket-util.h"
 #include "stat-util.h"
 #include "string-util.h"
+#include "time-util.h"
 #include "tmpfile-util.h"
 #include "uid-classification.h"
 #include "user-util.h"
 
 #define MOUNT_TREE_ROOT "/run/systemd/mount-rootfs"
 
-#define filename_escape(s) xescape((s), "./ ")
-
 static const char* coredump_tmpfile_name(const char *s) {
         return s ?: "(unnamed temporary file)";
 }
 
-static int make_filename(const Context *context, char **ret) {
-        _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
-        sd_id128_t boot = {};
+static int make_filename(const CoredumpContext *context, char **ret) {
+        _cleanup_free_ char *c = NULL;
+        sd_id128_t boot;
         int r;
 
         assert(context);
 
-        c = filename_escape(context->meta[META_COMM]);
+        c = xescape(context->comm, "./ ");
         if (!c)
                 return -ENOMEM;
 
-        u = filename_escape(context->meta[META_ARGV_UID]);
-        if (!u)
-                return -ENOMEM;
-
         r = sd_id128_get_boot(&boot);
         if (r < 0)
                 return r;
 
-        p = filename_escape(context->meta[META_ARGV_PID]);
-        if (!p)
-                return -ENOMEM;
-
-        t = filename_escape(context->meta[META_ARGV_TIMESTAMP]);
-        if (!t)
-                return -ENOMEM;
-
         if (asprintf(ret,
-                     "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s",
-                     c,
-                     u,
-                     SD_ID128_FORMAT_VAL(boot),
-                     p,
-                     t) < 0)
+                     "/var/lib/systemd/coredump/core.%s."UID_FMT"." SD_ID128_FORMAT_STR "."PID_FMT"."USEC_FMT,
+                     c, context->uid, SD_ID128_FORMAT_VAL(boot), context->pidref.pid, context->timestamp) < 0)
                 return -ENOMEM;
 
         return 0;
 }
 
-static int grant_user_access(int core_fd, const Context *context) {
+static int grant_user_access(int core_fd, const CoredumpContext *context) {
         int at_secure = -1;
         uid_t uid = UID_INVALID, euid = UID_INVALID;
         uid_t gid = GID_INVALID, egid = GID_INVALID;
@@ -104,7 +87,7 @@ static int grant_user_access(int core_fd, const Context *context) {
         assert(core_fd >= 0);
         assert(context);
 
-        if (!context->meta[META_PROC_AUXV])
+        if (!context->auxv)
                 return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), "No auxv data, not adjusting permissions.");
 
         uint8_t elf[EI_NIDENT];
@@ -131,8 +114,8 @@ static int grant_user_access(int core_fd, const Context *context) {
 
         r = parse_auxv(LOG_WARNING,
                        /* elf_class= */ elf[EI_CLASS],
-                       context->meta[META_PROC_AUXV],
-                       context->meta_size[META_PROC_AUXV],
+                       context->auxv,
+                       context->auxv_size,
                        &at_secure, &uid, &euid, &gid, &egid);
         if (r < 0)
                 return r;
@@ -174,34 +157,50 @@ static int fix_acl(int fd, uid_t uid, bool allow_user) {
         return 0;
 }
 
-static int fix_xattr(int fd, const Context *context) {
-        static const char * const xattrs[_META_MAX] = {
-                [META_ARGV_PID]       = "user.coredump.pid",
-                [META_ARGV_UID]       = "user.coredump.uid",
-                [META_ARGV_GID]       = "user.coredump.gid",
-                [META_ARGV_SIGNAL]    = "user.coredump.signal",
-                [META_ARGV_TIMESTAMP] = "user.coredump.timestamp",
-                [META_ARGV_RLIMIT]    = "user.coredump.rlimit",
-                [META_ARGV_HOSTNAME]  = "user.coredump.hostname",
-                [META_COMM]           = "user.coredump.comm",
-                [META_EXE]            = "user.coredump.exe",
-        };
-
-        int r = 0;
-
+static int fix_xattr_one(int fd, const char *xattr, const char *val) {
         assert(fd >= 0);
+        assert(xattr);
 
-        /* Attach some metadata to coredumps via extended attributes. Just because we can. */
+        if (isempty(val))
+                return 0;
 
-        for (unsigned i = 0; i < _META_MAX; i++) {
-                int k;
+        return RET_NERRNO(fsetxattr(fd, xattr, val, strlen(val), XATTR_CREATE));
+}
 
-                if (isempty(context->meta[i]) || !xattrs[i])
-                        continue;
+_printf_(3, 4)
+static int fix_xattr_format(int fd, const char *xattr, const char *format, ...) {
+        _cleanup_free_ char *value = NULL;
+        va_list ap;
+        int r;
 
-                k = RET_NERRNO(fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE));
-                RET_GATHER(r, k);
-        }
+        assert(format);
+
+        va_start(ap, format);
+        r = vasprintf(&value, format, ap);
+        va_end(ap);
+        if (r < 0)
+                return -ENOMEM;
+
+        return fix_xattr_one(fd, xattr, value);
+}
+
+static int fix_xattr(int fd, const CoredumpContext *context) {
+        int r;
+
+        assert(fd >= 0);
+        assert(context);
+
+        /* Attach some metadata to coredumps via extended attributes. Just because we can. */
+
+        r = fix_xattr_format(fd, "user.coredump.pid", PID_FMT, context->pidref.pid);
+        RET_GATHER(r, fix_xattr_format(fd, "user.coredump.uid", UID_FMT, context->uid));
+        RET_GATHER(r, fix_xattr_format(fd, "user.coredump.gid", GID_FMT, context->gid));
+        RET_GATHER(r, fix_xattr_format(fd, "user.coredump.signal", "%i", context->signo));
+        RET_GATHER(r, fix_xattr_format(fd, "user.coredump.timestamp", USEC_FMT, context->timestamp));
+        RET_GATHER(r, fix_xattr_format(fd, "user.coredump.rlimit", "%"PRIu64, context->rlimit));
+        RET_GATHER(r, fix_xattr_one(fd, "user.coredump.hostname", context->hostname));
+        RET_GATHER(r, fix_xattr_one(fd, "user.coredump.comm", context->comm));
+        RET_GATHER(r, fix_xattr_one(fd, "user.coredump.exe", context->exe));
 
         return r;
 }
@@ -210,7 +209,7 @@ static int fix_permissions_and_link(
                 int fd,
                 const char *filename,
                 const char *target,
-                const Context *context,
+                const CoredumpContext *context,
                 bool allow_user) {
 
         int r;
@@ -233,8 +232,7 @@ static int fix_permissions_and_link(
 
 static int save_external_coredump(
                 const CoredumpConfig *config,
-                const Context *context,
-                int input_fd,
+                const CoredumpContext *context,
                 char **ret_filename,
                 int *ret_node_fd,
                 int *ret_data_fd,
@@ -252,6 +250,7 @@ static int save_external_coredump(
 
         assert(config);
         assert(context);
+        assert(context->input_fd >= 0);
         assert(ret_filename);
         assert(ret_node_fd);
         assert(ret_data_fd);
@@ -265,8 +264,8 @@ static int save_external_coredump(
                  * (the kernel uses ELF_EXEC_PAGESIZE which is not easily accessible, but
                  * is usually the same as PAGE_SIZE. */
                 return log_info_errno(SYNTHETIC_ERRNO(EBADSLT),
-                                      "Resource limits disable core dumping for process %s (%s).",
-                                      context->meta[META_ARGV_PID], context->meta[META_COMM]);
+                                      "Resource limits disable core dumping for process "PID_FMT" (%s).",
+                                      context->pidref.pid, context->comm);
 
         process_limit = MAX(config->process_size_max, coredump_storage_size_max(config));
         if (process_limit == 0)
@@ -344,10 +343,10 @@ static int save_external_coredump(
                 log_debug("Limiting core file size to %" PRIu64 " bytes due to cgroup and/or filesystem limits.", max_size);
         }
 
-        r = copy_bytes(input_fd, fd, max_size, 0);
+        r = copy_bytes(context->input_fd, fd, max_size, 0);
         if (r < 0)
-                return log_error_errno(r, "Cannot store coredump of %s (%s): %m",
-                                       context->meta[META_ARGV_PID], context->meta[META_COMM]);
+                return log_error_errno(r, "Cannot store coredump of "PID_FMT" (%s): %m",
+                                       context->pidref.pid, context->comm);
         truncated = r == 1;
 
         bool allow_user = grant_user_access(fd, context) > 0;
@@ -383,7 +382,7 @@ static int save_external_coredump(
                         tmp = unlink_and_free(tmp);
                         fd = safe_close(fd);
 
-                        r = compress_stream(input_fd, fd_compressed, max_size, &partial_uncompressed_size);
+                        r = compress_stream(context->input_fd, fd_compressed, max_size, &partial_uncompressed_size);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed));
                         uncompressed_size += partial_uncompressed_size;
@@ -437,7 +436,7 @@ static int save_external_coredump(
 
 static int maybe_remove_external_coredump(
                 const CoredumpConfig *config,
-                const Context *context,
+                CoredumpContext *context,
                 const char *filename,
                 uint64_t size) {
 
@@ -447,7 +446,8 @@ static int maybe_remove_external_coredump(
         /* Returns true if might remove, false if will not remove, < 0 on error. */
 
         /* Always keep around in case of journald/pid1, since we cannot rely on the journal to accept them. */
-        if (config->storage != COREDUMP_STORAGE_NONE && (context->is_pid1 || context->is_journald))
+        if (config->storage != COREDUMP_STORAGE_NONE &&
+            (coredump_context_is_pid1(context) || coredump_context_is_journald(context)))
                 return false;
 
         if (config->storage == COREDUMP_STORAGE_EXTERNAL &&
@@ -463,25 +463,21 @@ static int maybe_remove_external_coredump(
         return true;
 }
 
-int acquire_pid_mount_tree_fd(const CoredumpConfig *config, const Context *context, int *ret_fd) {
-        /* Don't bother preparing environment if we can't pass it to libdwfl. */
-#if !HAVE_DWFL_SET_SYSROOT
-        *ret_fd = -EOPNOTSUPP;
-        log_debug("dwfl_set_sysroot() is not supported.");
-#else
+int acquire_pid_mount_tree_fd(const CoredumpConfig *config, CoredumpContext *context) {
+#if HAVE_DWFL_SET_SYSROOT
         _cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF, fd = -EBADF;
         _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
         int r;
 
         assert(config);
         assert(context);
-        assert(ret_fd);
 
-        if (!config->enter_namespace) {
-                *ret_fd = -EHOSTDOWN;
-                log_debug("EnterNamespace=no so we won't use mount tree of the crashed process for generating backtrace.");
+        if (context->mount_tree_fd >= 0)
                 return 0;
-        }
+
+        if (!config->enter_namespace)
+                return log_debug_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
+                                       "EnterNamespace=no so we won't use mount tree of the crashed process for generating backtrace.");
 
         if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, pair) < 0)
                 return log_error_errno(errno, "Failed to create socket pair: %m");
@@ -533,9 +529,12 @@ int acquire_pid_mount_tree_fd(const CoredumpConfig *config, const Context *conte
         if (fd < 0)
                 return log_error_errno(fd, "Failed to receive mount tree: %m");
 
-        *ret_fd = TAKE_FD(fd);
-#endif
+        context->mount_tree_fd = TAKE_FD(fd);
         return 0;
+#else
+        /* Don't bother preparing environment if we can't pass it to libdwfl. */
+        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "dwfl_set_sysroot() is not supported.");
+#endif
 }
 
 static int attach_mount_tree(int mount_tree_fd) {
@@ -569,7 +568,7 @@ static int attach_mount_tree(int mount_tree_fd) {
         return 0;
 }
 
-static int change_uid_gid(const Context *context) {
+static int change_uid_gid(const CoredumpContext *context) {
         int r;
 
         assert(context);
@@ -622,12 +621,7 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
         return 0;
 }
 
-int coredump_submit(
-                const CoredumpConfig *config,
-                const Context *context,
-                struct iovec_wrapper *iovw,
-                int input_fd) {
-
+int coredump_submit(const CoredumpConfig *config, CoredumpContext *context) {
         _cleanup_(sd_json_variant_unrefp) sd_json_variant *json_metadata = NULL;
         _cleanup_close_ int coredump_fd = -EBADF, coredump_node_fd = -EBADF;
         _cleanup_free_ char *filename = NULL, *coredump_data = NULL, *stacktrace = NULL;
@@ -639,15 +633,13 @@ int coredump_submit(
 
         assert(config);
         assert(context);
-        assert(iovw);
-        assert(input_fd >= 0);
 
         /* Vacuum before we write anything again */
         (void) coredump_vacuum(-1, config->keep_free, config->max_use);
 
         /* Always stream the coredump to disk, if that's possible */
         written = save_external_coredump(
-                        config, context, input_fd,
+                        config, context,
                         &filename, &coredump_node_fd, &coredump_fd,
                         &coredump_size, &coredump_compressed_size, &truncated) >= 0;
         if (written) {
@@ -662,11 +654,13 @@ int coredump_submit(
                                 coredump_node_fd >= 0 ? coredump_compressed_size : coredump_size);
                 if (r < 0)
                         return r;
-                if (r == 0)
-                        (void) iovw_put_string_field(iovw, "COREDUMP_FILENAME=", filename);
-                else if (config->storage == COREDUMP_STORAGE_EXTERNAL)
-                        log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
-                                 coredump_node_fd >= 0 ? coredump_compressed_size : coredump_size, config->external_size_max);
+                if (r > 0) {
+                        filename = mfree(filename);
+
+                        if (config->storage == COREDUMP_STORAGE_EXTERNAL)
+                                log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
+                                         coredump_node_fd >= 0 ? coredump_compressed_size : coredump_size, config->external_size_max);
+                }
 
                 /* Vacuum again, but exclude the coredump we just created */
                 (void) coredump_vacuum(coredump_node_fd >= 0 ? coredump_node_fd : coredump_fd, config->keep_free, config->max_use);
@@ -690,10 +684,10 @@ int coredump_submit(
                                   "than %"PRIu64" (the configured maximum)",
                                   coredump_size, config->process_size_max);
                 else if (coredump_fd >= 0) {
-                        bool skip = startswith(context->meta[META_COMM], "systemd-coredum"); /* COMM is 16 bytes usually */
+                        bool skip = startswith(context->comm, "systemd-coredum"); /* COMM is 16 bytes usually */
 
                         (void) parse_elf_object(coredump_fd,
-                                                context->meta[META_EXE],
+                                                context->exe,
                                                 root,
                                                 /* fork_disable_dump= */ skip, /* avoid loops */
                                                 &stacktrace,
@@ -701,16 +695,17 @@ int coredump_submit(
                 }
         }
 
+        r = coredump_context_build_iovw(context);
+        if (r < 0)
+                return r;
+
         _cleanup_free_ char *core_message = NULL;
-        core_message = strjoin(
-                        "Process ", context->meta[META_ARGV_PID],
-                        " (", context->meta[META_COMM],
-                        ") of user ", context->meta[META_ARGV_UID],
-                        written ? " dumped core." : " terminated abnormally without generating a coredump.");
-        if (!core_message)
+        if (asprintf(&core_message, "Process "PID_FMT" (%s) of user "UID_FMT" %s",
+                     context->pidref.pid, context->comm, context->uid,
+                     written ? "dumped core." : "terminated abnormally without generating a coredump.") < 0)
                 return log_oom();
 
-        if (context->is_journald && filename)
+        if (coredump_context_is_journald(context) && filename)
                 if (!strextend(&core_message, "\nCoredump diverted to ", filename))
                         return log_oom();
 
@@ -718,15 +713,17 @@ int coredump_submit(
                 if (!strextend(&core_message, "\n\n", stacktrace))
                         return log_oom();
 
-        if (context->is_journald)
+        if (coredump_context_is_journald(context))
                 /* 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);
 
-        (void) iovw_put_string_field(iovw, "MESSAGE=", core_message);
+        (void) iovw_put_string_field(&context->iovw, "MESSAGE=", core_message);
 
+        if (filename)
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_FILENAME=", filename);
         if (truncated)
-                (void) iovw_put_string_field(iovw, "COREDUMP_TRUNCATED=", "1");
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_TRUNCATED=", "1");
 
         /* If we managed to parse any ELF metadata (build-id, ELF package meta),
          * attach it as journal metadata. */
@@ -737,26 +734,26 @@ int coredump_submit(
                 if (r < 0)
                         return log_error_errno(r, "Failed to format JSON package metadata: %m");
 
-                (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_JSON=", formatted_json);
+                (void) iovw_put_string_field(&context->iovw, "COREDUMP_PACKAGE_JSON=", formatted_json);
         }
 
         /* In the unlikely scenario that context->meta[META_EXE] is not available,
          * let's avoid guessing the module name and skip the loop. */
-        if (context->meta[META_EXE])
+        if (context->exe)
                 JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, json_metadata) {
                         sd_json_variant *t;
 
                         /* We only add structured fields for the 'main' ELF module, and only if we can identify it. */
-                        if (!path_equal_filename(module_name, context->meta[META_EXE]))
+                        if (!path_equal_filename(module_name, context->exe))
                                 continue;
 
                         t = sd_json_variant_by_key(module_json, "name");
                         if (t)
-                                (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_NAME=", sd_json_variant_string(t));
+                                (void) iovw_put_string_field(&context->iovw, "COREDUMP_PACKAGE_NAME=", sd_json_variant_string(t));
 
                         t = sd_json_variant_by_key(module_json, "version");
                         if (t)
-                                (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_VERSION=", sd_json_variant_string(t));
+                                (void) iovw_put_string_field(&context->iovw, "COREDUMP_PACKAGE_VERSION=", sd_json_variant_string(t));
                 }
 
         /* Optionally store the entire coredump in the journal */
@@ -768,7 +765,7 @@ int coredump_submit(
 
                         r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
                         if (r >= 0) {
-                                if (iovw_put(iovw, coredump_data, sz) >= 0)
+                                if (iovw_put(&context->iovw, coredump_data, sz) >= 0)
                                         TAKE_PTR(coredump_data);
                         } else
                                 log_warning_errno(r, "Failed to attach the core to the journal entry: %m");
@@ -781,15 +778,15 @@ int coredump_submit(
          * 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) {
+        if (coredump_context_is_journald(context)) {
                 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);
+        r = sd_journal_sendv(context->iovw.iovec, context->iovw.count);
 
-        if (context->is_journald) {
+        if (coredump_context_is_journald(context)) {
                 int k;
 
                 k = journal_fd_nonblock(false);
@@ -797,7 +794,7 @@ int coredump_submit(
                         return log_error_errno(k, "Failed to make journal socket blocking: %m");
         }
 
-        if (r == -EAGAIN && context->is_journald)
+        if (r == -EAGAIN && coredump_context_is_journald(context))
                 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");
index 460b2d14b1184a154f04027509b9c054536129c7..b36790f9164fb1518e9e30c768861de54b251aaa 100644 (file)
@@ -3,12 +3,5 @@
 
 #include "coredump-forward.h"
 
-int acquire_pid_mount_tree_fd(
-                const CoredumpConfig *config,
-                const Context *context,
-                int *ret_fd);
-int coredump_submit(
-                const CoredumpConfig *config,
-                const Context *context,
-                struct iovec_wrapper *iovw,
-                int input_fd);
+int acquire_pid_mount_tree_fd(const CoredumpConfig *config, CoredumpContext *context);
+int coredump_submit(const CoredumpConfig *config, CoredumpContext *context);