diff options
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | catalog/systemd.catalog.in | 11 | ||||
-rw-r--r-- | man/coredump.conf.xml | 17 | ||||
-rw-r--r-- | src/coredump/coredump.c | 74 | ||||
-rw-r--r-- | src/coredump/coredumpctl.c | 350 | ||||
-rw-r--r-- | src/systemd/sd-messages.h | 1 |
6 files changed, 264 insertions, 190 deletions
@@ -670,6 +670,7 @@ Features: * coredump: - save coredump in Windows/Mozilla minidump format + - when truncating coredumps, also log the full size that the process had, and make a metadata field so we can report truncated coredumps * support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting) diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in index 8de8597fe9..2c72d31290 100644 --- a/catalog/systemd.catalog.in +++ b/catalog/systemd.catalog.in @@ -88,6 +88,17 @@ Process @COREDUMP_PID@ (@COREDUMP_COMM@) crashed and dumped core. This usually indicates a programming error in the crashing program and should be reported to its vendor as a bug. +-- 5aadd8e954dc4b1a8c954d63fd9e1137 +Subject: Core file was truncated to @SIZE_LIMIT@ bytes. +Defined-By: systemd +Support: %SUPPORT_URL% +Documentation: man:coredump.conf(5) + +The process had more memory mapped than the configured maximum for processing +and storage by systemd-coredump(8). Only the first @SIZE_LIMIT@ bytes were +saved. This core might still be usable, but various tools like gdb(1) will warn +about the file being truncated. + -- fc2e22bc6ee647b6b90729ab34a250b1 de Subject: Speicherabbild für Prozess @COREDUMP_PID@ (@COREDUMP_COMM) generiert Defined-By: systemd diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml index 4f95680a3a..77b4dac51c 100644 --- a/man/coredump.conf.xml +++ b/man/coredump.conf.xml @@ -83,16 +83,13 @@ <varlistentry> <term><varname>Storage=</varname></term> - <listitem><para>Controls where to store cores. One of - <literal>none</literal>, <literal>external</literal>, - <literal>journal</literal>, and <literal>both</literal>. When - <literal>none</literal>, the core dumps will be logged but not - stored permanently. When <literal>external</literal> (the - default), cores will be stored in <filename>/var/lib/systemd/coredump</filename>. - When <literal>journal</literal>, cores will be stored in - the journal and rotated following normal journal - rotation patterns. When <literal>both</literal>, cores - will be stored in both locations.</para> + <listitem><para>Controls where to store cores. One of <literal>none</literal>, + <literal>external</literal>, and <literal>journal</literal>. When + <literal>none</literal>, the core dumps will be logged (included the traceback if + possible), but not stored permanently. When <literal>external</literal> (the + default), cores will be stored in <filename>/var/lib/systemd/coredump/</filename>. + When <literal>journal</literal>, cores will be stored in the journal and rotated + following normal journal rotation patterns.</para> <para>When cores are stored in the journal, they might be compressed following journal compression settings, see diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 7cc3f3fca2..db60d0af7a 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -28,9 +28,10 @@ #include <elfutils/libdwfl.h> #endif +#include "sd-daemon.h" #include "sd-journal.h" #include "sd-login.h" -#include "sd-daemon.h" +#include "sd-messages.h" #include "acl-util.h" #include "alloc-util.h" @@ -93,7 +94,6 @@ typedef enum CoredumpStorage { COREDUMP_STORAGE_NONE, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_JOURNAL, - COREDUMP_STORAGE_BOTH, _COREDUMP_STORAGE_MAX, _COREDUMP_STORAGE_INVALID = -1 } CoredumpStorage; @@ -102,7 +102,6 @@ static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = { [COREDUMP_STORAGE_NONE] = "none", [COREDUMP_STORAGE_EXTERNAL] = "external", [COREDUMP_STORAGE_JOURNAL] = "journal", - [COREDUMP_STORAGE_BOTH] = "both", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage); @@ -135,6 +134,10 @@ static int parse_config(void) { false, NULL); } +static inline uint64_t storage_size_max(void) { + return arg_storage == COREDUMP_STORAGE_EXTERNAL ? arg_external_size_max : arg_journal_size_max; +} + static int fix_acl(int fd, uid_t uid) { #ifdef HAVE_ACL @@ -247,7 +250,7 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) { /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */ - if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) && + if (arg_storage == COREDUMP_STORAGE_EXTERNAL && size <= arg_external_size_max) return 0; @@ -331,12 +334,13 @@ static int save_external_coredump( /* Is coredumping disabled? Then don't bother saving/processing the coredump. * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */ - log_info("Core dumping has been disabled for process %s (%s).", context[CONTEXT_PID], context[CONTEXT_COMM]); + log_info("Resource limits disable core dumping for process %s (%s).", + context[CONTEXT_PID], context[CONTEXT_COMM]); return -EBADSLT; } /* Never store more than the process configured, or than we actually shall keep or process */ - max_size = MIN(rlimit, MAX(arg_process_size_max, arg_external_size_max)); + max_size = MIN(rlimit, MAX(arg_process_size_max, storage_size_max())); r = make_filename(context, &fn); if (r < 0) @@ -349,19 +353,18 @@ static int save_external_coredump( return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn); r = copy_bytes(input_fd, fd, max_size, false); - if (r == -EFBIG) { - log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", context[CONTEXT_PID], context[CONTEXT_COMM]); - goto fail; - } else if (IN_SET(r, -EDQUOT, -ENOSPC)) { - log_error("Not enough disk space for coredump of %s (%s), refusing.", context[CONTEXT_PID], context[CONTEXT_COMM]); - goto fail; - } else if (r < 0) { - log_error_errno(r, "Failed to dump coredump to file: %m"); + if (r < 0) { + log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]); goto fail; - } + } else if (r == 1) + 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), + NULL); if (fstat(fd, &st) < 0) { - log_error_errno(errno, "Failed to fstat coredump %s: %m", coredump_tmpfile_name(tmp)); + log_error_errno(errno, "Failed to fstat core file %s: %m", coredump_tmpfile_name(tmp)); goto fail; } @@ -372,8 +375,7 @@ static int save_external_coredump( #if defined(HAVE_XZ) || defined(HAVE_LZ4) /* If we will remove the coredump anyway, do not compress. */ - if (maybe_remove_external_coredump(NULL, st.st_size) == 0 - && arg_compress) { + if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) { _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL; _cleanup_close_ int fd_compressed = -1; @@ -705,7 +707,9 @@ static int submit_coredump( coredump_filename = strjoina("COREDUMP_FILENAME=", filename); IOVEC_SET_STRING(iovec[n_iovec++], coredump_filename); - } + } else if (arg_storage == COREDUMP_STORAGE_EXTERNAL) + log_info("The core will not be stored: size %zu is greater than %zu (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); @@ -730,7 +734,9 @@ static int submit_coredump( 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 %zu is greater than %zu (the configured maximum)", + coredump_size, arg_process_size_max); if (!core_message) #endif @@ -740,18 +746,22 @@ log: IOVEC_SET_STRING(iovec[n_iovec++], core_message); /* Optionally store the entire coredump in the journal */ - if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && - 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].iov_base = coredump_data; - iovec[n_iovec].iov_len = sz; - n_iovec++; - } + 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].iov_base = coredump_data; + iovec[n_iovec].iov_len = sz; + n_iovec++; + } 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 %zu is greater than %zu (the configured maximum)", + coredump_size, arg_journal_size_max); } assert(n_iovec <= n_iovec_allocated); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 8ba7c08eed..0e5351e621 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -280,11 +280,10 @@ static int retrieve(const void *data, free(*var); *var = v; - return 0; + return 1; } -static void print_field(FILE* file, sd_journal *j) { - _cleanup_free_ char *value = NULL; +static int print_field(FILE* file, sd_journal *j) { const void *d; size_t l; @@ -293,37 +292,59 @@ static void print_field(FILE* file, sd_journal *j) { assert(arg_field); - SD_JOURNAL_FOREACH_DATA(j, d, l) - retrieve(d, l, arg_field, &value); + /* A (user-specified) field may appear more than once for a given entry. + * We will print all of the occurences. + * This is different below for fields that systemd-coredump uses, + * because they cannot meaningfully appear more than once. + */ + SD_JOURNAL_FOREACH_DATA(j, d, l) { + _cleanup_free_ char *value = NULL; + int r; + + r = retrieve(d, l, arg_field, &value); + if (r < 0) + return r; + if (r > 0) + fprintf(file, "%s\n", value); + } - if (value) - fprintf(file, "%s\n", value); + return 0; } +#define RETRIEVE(d, l, name, arg) \ + { \ + int _r = retrieve(d, l, name, &arg); \ + if (_r < 0) \ + return _r; \ + if (_r > 0) \ + continue; \ + } + static int print_list(FILE* file, sd_journal *j, int had_legend) { _cleanup_free_ char *pid = NULL, *uid = NULL, *gid = NULL, *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL, - *filename = NULL; + *filename = NULL, *coredump = NULL; const void *d; size_t l; usec_t t; char buf[FORMAT_TIMESTAMP_MAX]; int r; - bool present; + const char *present; assert(file); assert(j); SD_JOURNAL_FOREACH_DATA(j, d, l) { - retrieve(d, l, "COREDUMP_PID", &pid); - retrieve(d, l, "COREDUMP_UID", &uid); - retrieve(d, l, "COREDUMP_GID", &gid); - retrieve(d, l, "COREDUMP_SIGNAL", &sgnl); - retrieve(d, l, "COREDUMP_EXE", &exe); - retrieve(d, l, "COREDUMP_COMM", &comm); - retrieve(d, l, "COREDUMP_CMDLINE", &cmdline); - retrieve(d, l, "COREDUMP_FILENAME", &filename); + RETRIEVE(d, l, "COREDUMP_PID", pid); + RETRIEVE(d, l, "COREDUMP_UID", uid); + RETRIEVE(d, l, "COREDUMP_GID", gid); + RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl); + RETRIEVE(d, l, "COREDUMP_EXE", exe); + RETRIEVE(d, l, "COREDUMP_COMM", comm); + RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline); + RETRIEVE(d, l, "COREDUMP_FILENAME", filename); + RETRIEVE(d, l, "COREDUMP", coredump); } if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) { @@ -336,7 +357,6 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) { return log_error_errno(r, "Failed to get realtime timestamp: %m"); format_timestamp(buf, sizeof(buf), t); - present = filename && access(filename, F_OK) == 0; if (!had_legend && !arg_no_legend) fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n", @@ -345,16 +365,28 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) { 5, "UID", 5, "GID", 3, "SIG", - 1, "PRESENT", + 8, "COREFILE", "EXE"); - fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n", + if (filename) + if (access(filename, R_OK) == 0) + present = "present"; + else if (errno == ENOENT) + present = "missing"; + else + present = "error"; + else if (coredump) + present = "journal"; + else + present = "none"; + + 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), - 1, present ? "*" : "", + 8, present, strna(exe ?: (comm ?: cmdline))); return 0; @@ -367,7 +399,8 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { *unit = NULL, *user_unit = NULL, *session = NULL, *boot_id = NULL, *machine_id = NULL, *hostname = NULL, *slice = NULL, *cgroup = NULL, *owner_uid = NULL, - *message = NULL, *timestamp = NULL, *filename = NULL; + *message = NULL, *timestamp = NULL, *filename = NULL, + *coredump = NULL; const void *d; size_t l; int r; @@ -376,25 +409,26 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { assert(j); SD_JOURNAL_FOREACH_DATA(j, d, l) { - retrieve(d, l, "COREDUMP_PID", &pid); - retrieve(d, l, "COREDUMP_UID", &uid); - retrieve(d, l, "COREDUMP_GID", &gid); - retrieve(d, l, "COREDUMP_SIGNAL", &sgnl); - retrieve(d, l, "COREDUMP_EXE", &exe); - retrieve(d, l, "COREDUMP_COMM", &comm); - retrieve(d, l, "COREDUMP_CMDLINE", &cmdline); - retrieve(d, l, "COREDUMP_UNIT", &unit); - retrieve(d, l, "COREDUMP_USER_UNIT", &user_unit); - retrieve(d, l, "COREDUMP_SESSION", &session); - retrieve(d, l, "COREDUMP_OWNER_UID", &owner_uid); - retrieve(d, l, "COREDUMP_SLICE", &slice); - retrieve(d, l, "COREDUMP_CGROUP", &cgroup); - retrieve(d, l, "COREDUMP_TIMESTAMP", ×tamp); - retrieve(d, l, "COREDUMP_FILENAME", &filename); - retrieve(d, l, "_BOOT_ID", &boot_id); - retrieve(d, l, "_MACHINE_ID", &machine_id); - retrieve(d, l, "_HOSTNAME", &hostname); - retrieve(d, l, "MESSAGE", &message); + RETRIEVE(d, l, "COREDUMP_PID", pid); + RETRIEVE(d, l, "COREDUMP_UID", uid); + RETRIEVE(d, l, "COREDUMP_GID", gid); + RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl); + RETRIEVE(d, l, "COREDUMP_EXE", exe); + RETRIEVE(d, l, "COREDUMP_COMM", comm); + RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline); + RETRIEVE(d, l, "COREDUMP_UNIT", unit); + RETRIEVE(d, l, "COREDUMP_USER_UNIT", user_unit); + RETRIEVE(d, l, "COREDUMP_SESSION", session); + RETRIEVE(d, l, "COREDUMP_OWNER_UID", owner_uid); + RETRIEVE(d, l, "COREDUMP_SLICE", slice); + RETRIEVE(d, l, "COREDUMP_CGROUP", cgroup); + RETRIEVE(d, l, "COREDUMP_TIMESTAMP", timestamp); + RETRIEVE(d, l, "COREDUMP_FILENAME", filename); + RETRIEVE(d, l, "COREDUMP", coredump); + RETRIEVE(d, l, "_BOOT_ID", boot_id); + RETRIEVE(d, l, "_MACHINE_ID", machine_id); + RETRIEVE(d, l, "_HOSTNAME", hostname); + RETRIEVE(d, l, "MESSAGE", message); } if (need_space) @@ -477,7 +511,7 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { if (unit) fprintf(file, " Unit: %s\n", unit); if (user_unit) - fprintf(file, " User Unit: %s\n", unit); + fprintf(file, " User Unit: %s\n", user_unit); if (slice) fprintf(file, " Slice: %s\n", slice); if (session) @@ -505,8 +539,13 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { if (hostname) fprintf(file, " Hostname: %s\n", hostname); - if (filename && access(filename, F_OK) == 0) - fprintf(file, " Coredump: %s\n", filename); + if (filename) + fprintf(file, " Storage: %s%s\n", filename, + access(filename, R_OK) < 0 ? " (inaccessible)" : ""); + else if (coredump) + fprintf(file, " Storage: journal\n"); + else + fprintf(file, " Storage: none\n"); if (message) { _cleanup_free_ char *m = NULL; @@ -534,15 +573,15 @@ static int focus(sd_journal *j) { return r; } -static void print_entry(sd_journal *j, unsigned n_found) { +static int print_entry(sd_journal *j, unsigned n_found) { assert(j); if (arg_action == ACTION_INFO) - print_info(stdout, j, n_found); + return print_info(stdout, j, n_found); else if (arg_field) - print_field(stdout, j); + return print_field(stdout, j); else - print_list(stdout, j, n_found); + return print_list(stdout, j, n_found); } static int dump_list(sd_journal *j) { @@ -561,10 +600,13 @@ static int dump_list(sd_journal *j) { if (r < 0) return r; - print_entry(j, 0); + return print_entry(j, 0); } else { - SD_JOURNAL_FOREACH(j) - print_entry(j, n_found++); + SD_JOURNAL_FOREACH(j) { + r = print_entry(j, n_found++); + if (r < 0) + return r; + } if (!arg_field && n_found <= 0) { log_notice("No coredumps found."); @@ -575,122 +617,142 @@ static int dump_list(sd_journal *j) { return 0; } -static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) { +static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp) { const char *data; _cleanup_free_ char *filename = NULL; size_t len; - int r; + int r, fd; + _cleanup_close_ int fdt = -1; + char *temp = NULL; - assert((fd >= 0) != !!path); - assert(!!path == !!unlink_temp); + assert(!(file && path)); /* At most one can be specified */ + assert(!!path == !!unlink_temp); /* Those must be specified together */ - /* Prefer uncompressed file to journal (probably cached) to - * compressed file (probably uncached). */ + /* Look for a coredump on disk first. */ r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len); - if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to retrieve COREDUMP_FILENAME: %m"); - else if (r == 0) + if (r == 0) retrieve(data, len, "COREDUMP_FILENAME", &filename); + else { + if (r != -ENOENT) + return log_error_errno(r, "Failed to retrieve COREDUMP_FILENAME field: %m"); + /* Check that we can have a COREDUMP field. We still haven't set a high + * data threshold, so we'll get a few kilobytes at most. + */ - if (filename && access(filename, R_OK) < 0) { - log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, - "File %s is not readable: %m", filename); - filename = mfree(filename); + r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len); + if (r == -ENOENT) + return log_error_errno(r, "Coredump entry has no core attached (neither internally in the journal nor externally on disk)."); + if (r < 0) + return log_error_errno(r, "Failed to retrieve COREDUMP field: %m"); } - if (filename && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) { - if (path) { + if (filename) { + if (access(filename, R_OK) < 0) + return log_error_errno(errno, "File \"%s\" is not readable: %m", filename); + + if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) { *path = filename; filename = NULL; + + return 0; } + } - return 0; - } else { - _cleanup_close_ int fdt = -1; - char *temp = NULL; + if (path) { + const char *vt; - if (fd < 0) { - const char *vt; + /* Create a temporary file to write the uncompressed core to. */ - r = var_tmp_dir(&vt); - if (r < 0) - return log_error_errno(r, "Failed to acquire temporary directory path: %m"); + r = var_tmp_dir(&vt); + if (r < 0) + return log_error_errno(r, "Failed to acquire temporary directory path: %m"); - temp = strjoin(vt, "/coredump-XXXXXX", NULL); - if (!temp) - return log_oom(); + temp = strjoin(vt, "/coredump-XXXXXX", NULL); + if (!temp) + return log_oom(); - fdt = mkostemp_safe(temp); - if (fdt < 0) - return log_error_errno(fdt, "Failed to create temporary file: %m"); - log_debug("Created temporary file %s", temp); + fdt = mkostemp_safe(temp); + if (fdt < 0) + return log_error_errno(fdt, "Failed to create temporary file: %m"); + log_debug("Created temporary file %s", temp); - fd = fdt; + fd = fdt; + } else { + /* If neither path or file are specified, we will write to stdout. Let's now check + * if stdout is connected to a tty. We checked that the file exists, or that the + * core might be stored in the journal. In this second case, if we found the entry, + * in all likelyhood we will be able to access the COREDUMP= field. In either case, + * we stop before doing any "real" work, i.e. before starting decompression or + * reading from the file or creating temporary files. + */ + if (!file) { + if (on_tty()) + return log_error_errno(ENOTTY, "Refusing to dump core to tty" + " (use shell redirection or specify --output)."); + file = stdout; } - r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len); - if (r == 0) { - ssize_t sz; - - assert(len >= 9); - data += 9; - len -= 9; - - sz = write(fdt, data, len); - if (sz < 0) { - r = log_error_errno(errno, - "Failed to write temporary file: %m"); - goto error; - } - if (sz != (ssize_t) len) { - log_error("Short write to temporary file."); - r = -EIO; - goto error; - } - } else if (filename) { + fd = fileno(file); + } + + if (filename) { #if defined(HAVE_XZ) || defined(HAVE_LZ4) - _cleanup_close_ int fdf; - - fdf = open(filename, O_RDONLY | O_CLOEXEC); - if (fdf < 0) { - r = log_error_errno(errno, - "Failed to open %s: %m", - filename); - goto error; - } + _cleanup_close_ int fdf; - r = decompress_stream(filename, fdf, fd, -1); - if (r < 0) { - log_error_errno(r, "Failed to decompress %s: %m", filename); - goto error; - } -#else - log_error("Cannot decompress file. Compiled without compression support."); - r = -EOPNOTSUPP; + fdf = open(filename, O_RDONLY | O_CLOEXEC); + if (fdf < 0) { + r = log_error_errno(errno, "Failed to open %s: %m", filename); goto error; -#endif - } else { - if (r == -ENOENT) - log_error("Cannot retrieve coredump from journal or disk."); - else - log_error_errno(r, "Failed to retrieve COREDUMP field: %m"); + } + + r = decompress_stream(filename, fdf, fd, -1); + if (r < 0) { + log_error_errno(r, "Failed to decompress %s: %m", filename); goto error; } +#else + log_error("Cannot decompress file. Compiled without compression support."); + r = -EOPNOTSUPP; + goto error; +#endif + } else { + ssize_t sz; + + /* We want full data, nothing truncated. */ + sd_journal_set_data_threshold(j, 0); + + r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len); + if (r < 0) + return log_error_errno(r, "Failed to retrieve COREDUMP field: %m"); - if (temp) { - *path = temp; - *unlink_temp = true; + assert(len >= 9); + data += 9; + len -= 9; + + sz = write(fd, data, len); + if (sz < 0) { + r = log_error_errno(errno, "Failed to write output: %m"); + goto error; + } + if (sz != (ssize_t) len) { + log_error("Short write to output."); + r = -EIO; + goto error; } + } - return 0; + if (temp) { + *path = temp; + *unlink_temp = true; + } + return 0; error: - if (temp) { - unlink(temp); - log_debug("Removed temporary file %s", temp); - } - return r; + if (temp) { + unlink(temp); + log_debug("Removed temporary file %s", temp); } + return r; } static int dump_core(sd_journal* j) { @@ -704,17 +766,12 @@ static int dump_core(sd_journal* j) { print_info(arg_output ? stdout : stderr, j, false); - if (on_tty() && !arg_output) { - log_error("Refusing to dump core to tty."); - return -ENOTTY; - } - - r = save_core(j, arg_output ? fileno(arg_output) : STDOUT_FILENO, NULL, NULL); + r = save_core(j, arg_output, NULL, NULL); if (r < 0) - return log_error_errno(r, "Coredump retrieval failed: %m"); + return r; r = sd_journal_previous(j); - if (r >= 0) + if (r > 0) log_warning("More than one entry matches, ignoring rest."); return 0; @@ -760,9 +817,9 @@ static int run_gdb(sd_journal *j) { return -ENOENT; } - r = save_core(j, -1, &path, &unlink_path); + r = save_core(j, NULL, &path, &unlink_path); if (r < 0) - return log_error_errno(r, "Failed to retrieve core: %m"); + return r; pid = fork(); if (pid < 0) { @@ -836,9 +893,6 @@ int main(int argc, char *argv[]) { } } - /* We want full data, nothing truncated. */ - sd_journal_set_data_threshold(j, 0); - SET_FOREACH(match, matches, it) { r = sd_journal_add_match(j, match, strlen(match)); if (r != 0) { diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 3c44d63021..79246ae060 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -40,6 +40,7 @@ _SD_BEGIN_DECLARATIONS; #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) |