* size. See DATA_SIZE_MAX in journal-importer.h. */
assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
-CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
-bool arg_compress = true;
-uint64_t arg_process_size_max = PROCESS_SIZE_MAX;
-uint64_t arg_external_size_max = EXTERNAL_SIZE_MAX;
-uint64_t arg_journal_size_max = JOURNAL_SIZE_MAX;
-uint64_t arg_keep_free = UINT64_MAX;
-uint64_t arg_max_use = UINT64_MAX;
-bool arg_enter_namespace = false;
-
static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
[COREDUMP_STORAGE_NONE] = "none",
[COREDUMP_STORAGE_EXTERNAL] = "external",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
-static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage);
-
-int coredump_parse_config(void) {
- static const ConfigTableItem items[] = {
- { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
- { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
- { "Coredump", "ProcessSizeMax", config_parse_iec_uint64, 0, &arg_process_size_max },
- { "Coredump", "ExternalSizeMax", config_parse_iec_uint64_infinity, 0, &arg_external_size_max },
- { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
- { "Coredump", "KeepFree", config_parse_iec_uint64, 0, &arg_keep_free },
- { "Coredump", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
-#if HAVE_DWFL_SET_SYSROOT
- { "Coredump", "EnterNamespace", config_parse_bool, 0, &arg_enter_namespace },
-#else
- { "Coredump", "EnterNamespace", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL },
-#endif
- {}
- };
+DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage);
+int coredump_parse_config(CoredumpConfig *config) {
int r;
+ assert(config);
+
r = config_parse_standard_file_with_dropins(
"systemd/coredump.conf",
"Coredump\0",
- config_item_table_lookup,
- items,
+ config_item_perf_lookup,
+ coredump_gperf_lookup,
CONFIG_PARSE_WARN,
- /* userdata= */ NULL);
+ config);
if (r < 0)
return r;
/* Let's make sure we fix up the maximum size we send to the journal here on the client side, for
* efficiency reasons. journald wouldn't accept anything larger anyway. */
- if (arg_journal_size_max > JOURNAL_SIZE_MAX) {
- log_warning("JournalSizeMax= set to larger value (%s) than journald would accept (%s), lowering automatically.",
- FORMAT_BYTES(arg_journal_size_max), FORMAT_BYTES(JOURNAL_SIZE_MAX));
- arg_journal_size_max = JOURNAL_SIZE_MAX;
+ if (config->journal_size_max > JOURNAL_SIZE_MAX) {
+ log_full(config->storage == COREDUMP_STORAGE_JOURNAL ? LOG_WARNING : LOG_DEBUG,
+ "JournalSizeMax= set to larger value (%s) than journald would accept (%s), lowering automatically.",
+ FORMAT_BYTES(config->journal_size_max), FORMAT_BYTES(JOURNAL_SIZE_MAX));
+ config->journal_size_max = JOURNAL_SIZE_MAX;
}
- log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
- log_debug("Selected compression %s.", yes_no(arg_compress));
+#if !HAVE_DWFL_SET_SYSROOT
+ if (config->enter_namespace) {
+ log_warning("EnterNamespace= is enabled but libdw does not support dwfl_set_sysroot(), disabling.");
+ config->enter_namespace = false;
+ }
+#endif
+
+ log_debug("Selected storage '%s'.", coredump_storage_to_string(config->storage));
+ log_debug("Selected compression %s.", yes_no(config->compress));
return 0;
}
-uint64_t coredump_storage_size_max(void) {
- if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
- return arg_external_size_max;
- if (arg_storage == COREDUMP_STORAGE_JOURNAL)
- return arg_journal_size_max;
- assert(arg_storage == COREDUMP_STORAGE_NONE);
- return 0;
+uint64_t coredump_storage_size_max(const CoredumpConfig *config) {
+ switch (config->storage) {
+ case COREDUMP_STORAGE_NONE:
+ return 0;
+ case COREDUMP_STORAGE_EXTERNAL:
+ return config->external_size_max;
+ case COREDUMP_STORAGE_JOURNAL:
+ return config->journal_size_max;
+ default:
+ assert_not_reached();
+ }
}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#include "basic-forward.h"
+#include "conf-parser-forward.h"
+#include "coredump-forward.h"
/* The maximum size up to which we process coredumps. We use 1G on 32-bit systems, and 32G on 64-bit systems */
#if __SIZEOF_POINTER__ == 4
_COREDUMP_STORAGE_INVALID = -EINVAL,
} CoredumpStorage;
-extern CoredumpStorage arg_storage;
-extern bool arg_compress;
-extern uint64_t arg_process_size_max;
-extern uint64_t arg_external_size_max;
-extern uint64_t arg_journal_size_max;
-extern uint64_t arg_keep_free;
-extern uint64_t arg_max_use;
-extern bool arg_enter_namespace;
-
-int coredump_parse_config(void);
-uint64_t coredump_storage_size_max(void);
+struct CoredumpConfig {
+ CoredumpStorage storage;
+ bool compress;
+ uint64_t process_size_max;
+ uint64_t external_size_max;
+ uint64_t journal_size_max;
+ uint64_t keep_free;
+ uint64_t max_use;
+ bool enter_namespace;
+};
+
+#define COREDUMP_CONFIG_NULL \
+ (CoredumpConfig) { \
+ .storage = COREDUMP_STORAGE_EXTERNAL, \
+ .compress = true, \
+ .process_size_max = PROCESS_SIZE_MAX, \
+ .external_size_max = EXTERNAL_SIZE_MAX, \
+ .journal_size_max = JOURNAL_SIZE_MAX, \
+ .keep_free = UINT64_MAX, \
+ .max_use = UINT64_MAX, \
+ }
+
+int coredump_parse_config(CoredumpConfig *config);
+uint64_t coredump_storage_size_max(const CoredumpConfig *config);
+
+/* Defined in generated coredump-gperf.c */
+const struct ConfigPerfItem* coredump_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_coredump_storage);
#include "basic-forward.h"
+typedef struct CoredumpConfig CoredumpConfig;
typedef struct Context Context;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+%{
+_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
+#if __GNUC__ >= 15
+_Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
+#endif
+#include "conf-parser.h"
+#include "coredump-config.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name coredump_gperf_hash
+%define lookup-function-name coredump_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+Coredump.Storage, config_parse_coredump_storage, 0, offsetof(CoredumpConfig, storage)
+Coredump.Compress, config_parse_bool, 0, offsetof(CoredumpConfig, compress)
+Coredump.ProcessSizeMax, config_parse_iec_uint64, 0, offsetof(CoredumpConfig, process_size_max)
+Coredump.ExternalSizeMax, config_parse_iec_uint64_infinity, 0, offsetof(CoredumpConfig, external_size_max)
+Coredump.JournalSizeMax, config_parse_iec_size, 0, offsetof(CoredumpConfig, journal_size_max)
+Coredump.KeepFree, config_parse_iec_uint64, 0, offsetof(CoredumpConfig, keep_free)
+Coredump.MaxUse, config_parse_iec_uint64, 0, offsetof(CoredumpConfig, max_use)
+Coredump.EnterNamespace, config_parse_bool, 0, offsetof(CoredumpConfig, enter_namespace)
#include "sd-messages.h"
+#include "coredump-config.h"
#include "coredump-context.h"
#include "coredump-kernel-helper.h"
#include "coredump-send.h"
if (r < 0)
return log_error_errno(r, "Failed to connect stdout/stderr to /dev/null: %m");
+ /* Ignore all parse errors */
+ CoredumpConfig config = COREDUMP_CONFIG_NULL;
+ (void) coredump_parse_config(&config);
+
log_debug("Processing coredump received from the kernel...");
iovw = iovw_new();
if (r >= 0)
return 0;
- r = acquire_pid_mount_tree_fd(&context, &context.mount_tree_fd);
+ 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) iovw_put_string_field(iovw, "PRIORITY=", STRINGIFY(LOG_CRIT));
if (context.is_journald || context.is_pid1)
- return coredump_submit(&context, iovw, STDIN_FILENO);
+ return coredump_submit(&config, &context, iovw, STDIN_FILENO);
return coredump_send(iovw, STDIN_FILENO, &context.pidref, context.mount_tree_fd);
}
#include <stdlib.h>
+#include "coredump-config.h"
#include "coredump-context.h"
#include "coredump-receive.h"
#include "coredump-submit.h"
assert(fd >= 0);
log_setup();
-
log_debug("Processing coredump received via socket...");
+ /* Ignore all parse errors */
+ CoredumpConfig config = COREDUMP_CONFIG_NULL;
+ (void) coredump_parse_config(&config);
+
for (;;) {
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
struct msghdr mh = {
"Mandatory argument %s not received on socket, aborting.",
meta_field_names[i]);
- return coredump_submit(&context, &iovw, input_fd);
+ return coredump_submit(&config, &context, &iovw, input_fd);
}
}
static int save_external_coredump(
+ const CoredumpConfig *config,
const Context *context,
int input_fd,
char **ret_filename,
struct stat st;
int r;
+ assert(config);
assert(context);
assert(ret_filename);
assert(ret_node_fd);
"Resource limits disable core dumping for process %s (%s).",
context->meta[META_ARGV_PID], context->meta[META_COMM]);
- process_limit = MAX(arg_process_size_max, coredump_storage_size_max());
+ process_limit = MAX(config->process_size_max, coredump_storage_size_max(config));
if (process_limit == 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADSLT),
"Limits for coredump processing and storage are both 0, not dumping core.");
* should be able to at least store the full compressed core file. */
storage_on_tmpfs = fd_is_temporary_fs(fd) > 0;
- if (storage_on_tmpfs && arg_compress) {
+ if (storage_on_tmpfs && config->compress) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
uint64_t cgroup_limit = UINT64_MAX;
struct statvfs sv;
bool allow_user = grant_user_access(fd, context) > 0;
#if HAVE_COMPRESSION
- if (arg_compress) {
+ if (config->compress) {
_cleanup_(unlink_and_freep) char *tmp_compressed = NULL;
_cleanup_free_ char *fn_compressed = NULL;
_cleanup_close_ int fd_compressed = -EBADF;
}
static int maybe_remove_external_coredump(
- const Context *c,
+ const CoredumpConfig *config,
+ const Context *context,
const char *filename,
uint64_t size) {
- assert(c);
+ assert(config);
+ assert(context);
/* 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 (arg_storage != COREDUMP_STORAGE_NONE && (c->is_pid1 || c->is_journald))
+ if (config->storage != COREDUMP_STORAGE_NONE && (context->is_pid1 || context->is_journald))
return false;
- if (arg_storage == COREDUMP_STORAGE_EXTERNAL &&
- size <= arg_external_size_max)
+ if (config->storage == COREDUMP_STORAGE_EXTERNAL &&
+ size <= config->external_size_max)
return false;
if (!filename)
return true;
}
-int acquire_pid_mount_tree_fd(const Context *context, int *ret_fd) {
+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;
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
int r;
+ assert(config);
assert(context);
assert(ret_fd);
- if (!arg_enter_namespace) {
+ 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.");
return 0;
}
int coredump_submit(
+ const CoredumpConfig *config,
const Context *context,
struct iovec_wrapper *iovw,
int input_fd) {
sd_json_variant *module_json;
int r;
+ assert(config);
assert(context);
assert(iovw);
assert(input_fd >= 0);
/* Vacuum before we write anything again */
- (void) coredump_vacuum(-1, arg_keep_free, arg_max_use);
+ (void) coredump_vacuum(-1, config->keep_free, config->max_use);
/* Always stream the coredump to disk, if that's possible */
written = save_external_coredump(
- context, input_fd,
+ config, context, input_fd,
&filename, &coredump_node_fd, &coredump_fd,
&coredump_size, &coredump_compressed_size, &truncated) >= 0;
if (written) {
* 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(
+ config,
context,
filename,
coredump_node_fd >= 0 ? coredump_compressed_size : coredump_size);
return r;
if (r == 0)
(void) iovw_put_string_field(iovw, "COREDUMP_FILENAME=", filename);
- else if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
+ 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, arg_external_size_max);
+ 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, arg_keep_free, arg_max_use);
+ (void) coredump_vacuum(coredump_node_fd >= 0 ? coredump_node_fd : coredump_fd, config->keep_free, config->max_use);
}
if (context->mount_tree_fd >= 0 && attach_mount_tree(context->mount_tree_fd) >= 0)
if (written) {
/* Try to get a stack trace if we can */
- if (coredump_size > arg_process_size_max)
+ if (coredump_size > config->process_size_max)
log_debug("Not generating stack trace: core size %"PRIu64" is greater "
"than %"PRIu64" (the configured maximum)",
- coredump_size, arg_process_size_max);
+ 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 */
}
/* Optionally store the entire coredump in the journal */
- if (arg_storage == COREDUMP_STORAGE_JOURNAL && coredump_fd >= 0) {
- if (coredump_size <= arg_journal_size_max) {
+ if (config->storage == COREDUMP_STORAGE_JOURNAL && coredump_fd >= 0) {
+ if (coredump_size <= config->journal_size_max) {
size_t sz = 0;
/* Store the coredump itself in the journal */
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);
+ coredump_size, config->journal_size_max);
}
/* If journald is coredumping, we have to be careful that we don't deadlock when trying to write the
#include "coredump-forward.h"
-int acquire_pid_mount_tree_fd(const Context *context, int *ret_fd);
+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);
#include "sd-daemon.h"
#include "coredump-backtrace.h"
-#include "coredump-config.h"
-#include "coredump-context.h"
#include "coredump-kernel-helper.h"
#include "coredump-receive.h"
#include "coredump-util.h"
/* Make sure we never enter a loop */
(void) set_dumpable(SUID_DUMP_DISABLE);
- /* Ignore all parse errors */
- (void) coredump_parse_config();
-
r = sd_listen_fds(false);
if (r < 0)
return log_error_errno(r, "Failed to determine the number of file descriptors: %m");
'coredump-vacuum.c',
)
+coredump_gperf_c = custom_target(
+ input : 'coredump-gperf.gperf',
+ output : 'coredump-gperf.c',
+ command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
+
+generated_sources += coredump_gperf_c
+systemd_coredump_sources += coredump_gperf_c
+
common_dependencies = [
liblz4_cflags,
libxz_cflags,
libexec_template + {
'name' : 'systemd-coredump',
'sources' : systemd_coredump_sources + systemd_coredump_extract_sources,
+ 'include_directories' : [libexec_template['include_directories'], include_directories('.')],
'extract' : systemd_coredump_extract_sources,
'link_with' : [libshared],
'dependencies' : common_dependencies,