static int submit_coredump(
                const char *context[_CONTEXT_MAX],
                struct iovec *iovec,
                size_t n_iovec_allocated,
                size_t n_iovec,
                int input_fd) {

        _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1;
        _cleanup_free_ char *core_message = NULL, *filename = NULL, *coredump_data = NULL;
        uint64_t coredump_size = UINT64_MAX;
        bool truncated = false, journald_crash;
        int r;

        assert(context);
        assert(iovec);
        assert(n_iovec_allocated >= n_iovec + SUBMIT_COREDUMP_FIELDS);
        assert(input_fd >= 0);

        journald_crash = is_journald_crash(context);

        /* Vacuum before we write anything again */
        (void) coredump_vacuum(-1, arg_keep_free, arg_max_use);

        /* Always stream the coredump to disk, if that's possible */
        r = save_external_coredump(context, input_fd,
                                   &filename, &coredump_node_fd, &coredump_fd, &coredump_size, &truncated);
        if (r < 0)
                /* Skip whole core dumping part */
                goto log;

        /* If we don't want to keep the coredump on disk, remove it now, as later on we will lack the privileges for
         * it. However, we keep the fd to it, so that we can still process it and log it. */
        r = maybe_remove_external_coredump(filename, coredump_size);
        if (r < 0)
                return r;
        if (r == 0) {
                const char *coredump_filename;

                coredump_filename = strjoina("COREDUMP_FILENAME=", filename);
                iovec[n_iovec++] = IOVEC_MAKE_STRING(coredump_filename);
        } else if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
                log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
                         coredump_size, arg_external_size_max);

        /* Vacuum again, but exclude the coredump we just created */
        (void) coredump_vacuum(coredump_node_fd >= 0 ? coredump_node_fd : coredump_fd, arg_keep_free, arg_max_use);

        /* Now, let's drop privileges to become the user who owns the segfaulted process and allocate the coredump
         * memory under the user's uid. This also ensures that the credentials journald will see are the ones of the
         * coredumping user, thus making sure the user gets access to the core dump. Let's also get rid of all
         * capabilities, if we run as root, we won't need them anymore. */
        r = change_uid_gid(context);
        if (r < 0)
                return log_error_errno(r, "Failed to drop privileges: %m");

#if HAVE_ELFUTILS
        /* Try to get a strack trace if we can */
        if (coredump_size <= arg_process_size_max) {
                _cleanup_free_ char *stacktrace = NULL;

                r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace);
                if (r >= 0)
                        core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
                                               " (", context[CONTEXT_COMM], ") of user ",
                                               context[CONTEXT_UID], " dumped core.",
                                               journald_crash ? "\nCoredump diverted to " : "",
                                               journald_crash ? filename : "",
                                               "\n\n", stacktrace);
                else if (r == -EINVAL)
                        log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
                else
                        log_warning_errno(r, "Failed to generate stack trace: %m");
        } else
                log_debug("Not generating stack trace: core size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
                          coredump_size, arg_process_size_max);

        if (!core_message)
#endif
log:
        core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
                               " (", context[CONTEXT_COMM], ") of user ",
                               context[CONTEXT_UID], " dumped core.",
                               journald_crash ? "\nCoredump diverted to " : NULL,
                               journald_crash ? filename : NULL);
        if (!core_message)
                return log_oom();

        if (journald_crash) {
                /* We cannot log to the journal, so just print the message.
                 * The target was set previously to something safe. */
                assert(startswith(core_message, "MESSAGE="));
                log_dispatch(LOG_ERR, 0, core_message + strlen("MESSAGE="));
                return 0;
        }

        iovec[n_iovec++] = IOVEC_MAKE_STRING(core_message);

        if (truncated)
                iovec[n_iovec++] = IOVEC_MAKE_STRING("COREDUMP_TRUNCATED=1");

        /* Optionally store the entire coredump in the journal */
        if (arg_storage == COREDUMP_STORAGE_JOURNAL) {
                if (coredump_size <= arg_journal_size_max) {
                        size_t sz = 0;

                        /* Store the coredump itself in the journal */

                        r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
                        if (r >= 0)
                                iovec[n_iovec++] = IOVEC_MAKE(coredump_data, sz);
                        else
                                log_warning_errno(r, "Failed to attach the core to the journal entry: %m");
                } else
                        log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
                                 coredump_size, arg_journal_size_max);
        }

        assert(n_iovec <= n_iovec_allocated);

        r = sd_journal_sendv(iovec, n_iovec);
        if (r < 0)
                return log_error_errno(r, "Failed to log coredump: %m");

        return 0;
}