coredumpctl: move verb_dump_core and save_core() to coredumpctl-core.c

This commit is contained in:
Yu Watanabe
2026-08-26 02:05:55 +09:00
parent 3e24c014bf
commit ea75664af1
4 changed files with 206 additions and 184 deletions
+194
View File
@@ -0,0 +1,194 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <unistd.h>
#include "sd-journal.h"
#include "chase.h"
#include "compress.h"
#include "coredumpctl.h"
#include "coredumpctl-core.h"
#include "coredumpctl-info.h"
#include "coredumpctl-journal.h"
#include "coredumpctl-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "io-util.h"
#include "log.h"
#include "path-util.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "tmpfile-util.h"
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, fd;
_cleanup_close_ int fdt = -EBADF;
char *temp = NULL;
assert(!(file && path)); /* At most one can be specified */
assert(!!path == !!unlink_temp); /* Those must be specified together */
/* Look for a coredump on disk first. */
r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
if (r == 0) {
_cleanup_free_ char *resolved = NULL;
r = retrieve(data, len, "COREDUMP_FILENAME", &filename);
if (r < 0)
return r;
assert(r > 0);
r = chase_and_access(filename, arg_root, CHASE_PREFIX_ROOT, F_OK, &resolved);
if (r < 0)
return log_error_errno(r, "Cannot access \"%s%s\": %m", strempty(arg_root), filename);
free_and_replace(filename, resolved);
if (path && !ENDSWITH_SET(filename, ".xz", ".lz4", ".zst")) {
*path = TAKE_PTR(filename);
return 0;
}
} 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. */
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 (path) {
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");
temp = path_join(vt, "coredump-XXXXXX");
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);
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 likelihood 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(SYNTHETIC_ERRNO(ENOTTY),
"Refusing to dump core to tty"
" (use shell redirection or specify --output).");
file = stdout;
}
fd = fileno(file);
}
if (filename) {
#if HAVE_COMPRESSION
_cleanup_close_ int fdf = -EBADF;
fdf = open(filename, O_RDONLY | O_CLOEXEC);
if (fdf < 0) {
r = log_error_errno(errno, "Failed to open %s: %m", filename);
goto error;
}
r = decompress_stream_by_filename(filename, fdf, fd, -1);
if (r < 0) {
log_error_errno(r, "Failed to decompress %s: %m", filename);
goto error;
}
#else
r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Cannot decompress file. Compiled without compression support.");
goto error;
#endif
} else {
/* 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");
assert(len >= 9);
data += 9;
len -= 9;
r = loop_write(fd, data, len);
if (r < 0) {
log_error_errno(r, "Failed to write output: %m");
goto error;
}
}
if (temp) {
*path = temp;
*unlink_temp = true;
}
return 0;
error:
if (temp) {
(void) unlink(temp);
log_debug("Removed temporary file %s", temp);
}
return r;
}
int verb_dump_core(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
if (arg_field)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --field/-F only makes sense with list");
r = acquire_journal(&j, strv_skip(argv, 1));
if (r < 0)
return r;
r = focus(j);
if (r < 0)
return r;
if (arg_output) {
f = fopen(arg_output, "we");
if (!f)
return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", arg_output);
}
print_info(f ? stdout : stderr, j, false);
r = save_core(j, f, NULL, NULL);
if (r < 0)
return r;
r = sd_journal_previous(j);
if (r > 0 && !arg_quiet)
log_notice("More than one entry matches, ignoring rest.");
return 0;
}
+8
View File
@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "forward.h"
int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp);
int verb_dump_core(int argc, char *argv[], uintptr_t _data, void *userdata);
+3 -184
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
@@ -16,9 +15,8 @@
#include "bus-error.h"
#include "bus-locator.h"
#include "bus-util.h"
#include "chase.h"
#include "compress.h"
#include "coredumpctl.h"
#include "coredumpctl-core.h"
#include "coredumpctl-info.h"
#include "coredumpctl-journal.h"
#include "coredumpctl-list.h"
@@ -26,11 +24,8 @@
#include "dissect-image.h"
#include "dlopen-note.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fs-util.h"
#include "glob-util.h"
#include "image-policy.h"
#include "io-util.h"
#include "log.h"
#include "logs-show.h"
#include "loop-util.h"
@@ -45,9 +40,7 @@
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "time-util.h"
#include "tmpfile-util.h"
#include "verbs.h"
#define SHORT_BUS_CALL_TIMEOUT_USEC (3 * USEC_PER_SEC)
@@ -235,182 +228,8 @@ VERB_SCOPE(, verb_dump_list, "list", "[MATCHES…]", VERB_ANY, VERB_ANY, VERB_DE
"List available coredumps");
VERB_SCOPE(, verb_dump_list, "info", "[MATCHES…]", VERB_ANY, VERB_ANY, 0,
"Show detailed information about one or more coredumps");
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, fd;
_cleanup_close_ int fdt = -EBADF;
char *temp = NULL;
assert(!(file && path)); /* At most one can be specified */
assert(!!path == !!unlink_temp); /* Those must be specified together */
/* Look for a coredump on disk first. */
r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
if (r == 0) {
_cleanup_free_ char *resolved = NULL;
r = retrieve(data, len, "COREDUMP_FILENAME", &filename);
if (r < 0)
return r;
assert(r > 0);
r = chase_and_access(filename, arg_root, CHASE_PREFIX_ROOT, F_OK, &resolved);
if (r < 0)
return log_error_errno(r, "Cannot access \"%s%s\": %m", strempty(arg_root), filename);
free_and_replace(filename, resolved);
if (path && !ENDSWITH_SET(filename, ".xz", ".lz4", ".zst")) {
*path = TAKE_PTR(filename);
return 0;
}
} 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.
*/
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 (path) {
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");
temp = path_join(vt, "coredump-XXXXXX");
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);
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 likelihood 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(SYNTHETIC_ERRNO(ENOTTY),
"Refusing to dump core to tty"
" (use shell redirection or specify --output).");
file = stdout;
}
fd = fileno(file);
}
if (filename) {
#if HAVE_COMPRESSION
_cleanup_close_ int fdf = -EBADF;
fdf = open(filename, O_RDONLY | O_CLOEXEC);
if (fdf < 0) {
r = log_error_errno(errno, "Failed to open %s: %m", filename);
goto error;
}
r = decompress_stream_by_filename(filename, fdf, fd, -1);
if (r < 0) {
log_error_errno(r, "Failed to decompress %s: %m", filename);
goto error;
}
#else
r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Cannot decompress file. Compiled without compression support.");
goto error;
#endif
} else {
/* 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");
assert(len >= 9);
data += 9;
len -= 9;
r = loop_write(fd, data, len);
if (r < 0) {
log_error_errno(r, "Failed to write output: %m");
goto error;
}
}
if (temp) {
*path = temp;
*unlink_temp = true;
}
return 0;
error:
if (temp) {
(void) unlink(temp);
log_debug("Removed temporary file %s", temp);
}
return r;
}
VERB(verb_dump_core, "dump", "[MATCHES…]", VERB_ANY, VERB_ANY, 0,
"Print first matching coredump to stdout");
static int verb_dump_core(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
if (arg_field)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --field/-F only makes sense with list");
r = acquire_journal(&j, strv_skip(argv, 1));
if (r < 0)
return r;
r = focus(j);
if (r < 0)
return r;
if (arg_output) {
f = fopen(arg_output, "we");
if (!f)
return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", arg_output);
}
print_info(f ? stdout : stderr, j, false);
r = save_core(j, f, NULL, NULL);
if (r < 0)
return r;
r = sd_journal_previous(j);
if (r > 0 && !arg_quiet)
log_notice("More than one entry matches, ignoring rest.");
return 0;
}
VERB_SCOPE(, verb_dump_core, "dump", "[MATCHES…]", VERB_ANY, VERB_ANY, 0,
"Print first matching coredump to stdout");
VERB(verb_run_debug, "debug", "[MATCHES…]", VERB_ANY, VERB_ANY, 0,
"Start a debugger for the first matching coredump");
+1
View File
@@ -19,6 +19,7 @@ systemd_coredump_export_sources = files(
)
coredumpctl_sources = files(
'coredumpctl.c',
'coredumpctl-core.c',
'coredumpctl-info.c',
'coredumpctl-journal.c',
'coredumpctl-list.c',