mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
coredump: assign random UUID for each crash
Then, make it possible to specify core by the UUID in coredumpctl. This is typically useful to specify a crash that the same executable crashes multiple times, as PID may not be unique.
This commit is contained in:
1 parent
c366d2550d
commit
0d195ea931
8 files changed
+86
-7
No files matched your search
+9
-1
@@ -26,7 +26,7 @@
|
||||
<command>coredumpctl</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<arg choice="req">COMMAND</arg>
|
||||
<arg choice="opt" rep="repeat">PID|COMM|EXE|MATCH</arg>
|
||||
<arg choice="opt" rep="repeat">ID|PID|COMM|EXE|MATCH</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@@ -55,6 +55,14 @@
|
||||
<para>The output is designed to be human-readable and contains a table with the following
|
||||
columns:</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>ID</term>
|
||||
<listitem><para>The UUID of the crash assigned by <command>systemd-coredump</command>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v263"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>TIME</term>
|
||||
<listitem><para>The timestamp of the crash, as reported by the kernel.</para>
|
||||
|
||||
@@ -17,7 +17,8 @@ _coredumpctl_commands(){
|
||||
local -a _dumps
|
||||
cmd="${${_coredumpctl_cmds[(r)$words[1]:*]%%:*}}"
|
||||
if (( $#cmd )); then
|
||||
_dumps=( "${(f)$(coredumpctl list -q --no-legend 2>/dev/null | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $4,$0}')}" )
|
||||
# $5 is PID: columns are ID($1), DATE($2), TIME($3), TIMEZONE($4), PID($5)
|
||||
_dumps=( "${(f)$(coredumpctl list -q --no-legend 2>/dev/null | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $5,$0}')}" )
|
||||
if [[ -n "$_dumps" ]]; then
|
||||
_describe -V -t pids 'coredumps' _dumps
|
||||
else
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
#include "sd-journal.h"
|
||||
#include "sd-messages.h"
|
||||
|
||||
@@ -32,6 +33,10 @@ int coredump_backtrace(int argc, char *argv[]) {
|
||||
|
||||
(void) iovw_replace_string_field(&context.iovw, "MESSAGE_ID=", SD_MESSAGE_BACKTRACE_STR);
|
||||
|
||||
sd_id128_t id;
|
||||
if (sd_id128_randomize(&id) >= 0)
|
||||
(void) iovw_replace_string_field(&context.iovw, "COREDUMP_ID=", SD_ID128_TO_STRING(id));
|
||||
|
||||
for (;;) {
|
||||
r = journal_importer_process_data(&importer);
|
||||
if (r < 0)
|
||||
|
||||
@@ -726,6 +726,10 @@ int coredump_submit(const CoredumpConfig *config, CoredumpContext *context) {
|
||||
|
||||
(void) iovw_put_string_field(&context->iovw, "MESSAGE=", core_message);
|
||||
|
||||
sd_id128_t id;
|
||||
if (sd_id128_randomize(&id) >= 0)
|
||||
(void) iovw_put_string_field(&context->iovw, "COREDUMP_ID=", SD_ID128_TO_STRING(id));
|
||||
|
||||
if (filename)
|
||||
(void) iovw_put_string_field(&context->iovw, "COREDUMP_FILENAME=", filename);
|
||||
if (truncated)
|
||||
|
||||
@@ -117,7 +117,7 @@ error:
|
||||
|
||||
static int print_list(FILE *file, sd_journal *j, Table *t) {
|
||||
_cleanup_free_ char
|
||||
*mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
|
||||
*mid = NULL, *cid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
|
||||
*sgnl = NULL, *exe = NULL, *comm = NULL,
|
||||
*filename = NULL, *truncated = NULL;
|
||||
const void *d;
|
||||
@@ -127,6 +127,7 @@ static int print_list(FILE *file, sd_journal *j, Table *t) {
|
||||
const char *present = NULL, *color = NULL;
|
||||
uint64_t size = UINT64_MAX;
|
||||
bool normal_coredump, has_inline_coredump;
|
||||
sd_id128_t coredump_id = SD_ID128_NULL;
|
||||
uid_t uid_as_int = UID_INVALID;
|
||||
gid_t gid_as_int = GID_INVALID;
|
||||
pid_t pid_as_int = 0;
|
||||
@@ -137,6 +138,7 @@ static int print_list(FILE *file, sd_journal *j, Table *t) {
|
||||
|
||||
SD_JOURNAL_FOREACH_DATA(j, d, l) {
|
||||
RETRIEVE(d, l, "MESSAGE_ID", mid);
|
||||
RETRIEVE(d, l, "COREDUMP_ID", cid);
|
||||
RETRIEVE(d, l, "COREDUMP_PID", pid);
|
||||
RETRIEVE(d, l, "COREDUMP_UID", uid);
|
||||
RETRIEVE(d, l, "COREDUMP_GID", gid);
|
||||
@@ -156,6 +158,8 @@ static int print_list(FILE *file, sd_journal *j, Table *t) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cid)
|
||||
(void) sd_id128_from_string(cid, &coredump_id);
|
||||
(void) parse_uid(uid, &uid_as_int);
|
||||
(void) parse_gid(gid, &gid_as_int);
|
||||
(void) parse_pid(pid, &pid_as_int);
|
||||
@@ -184,6 +188,13 @@ static int print_list(FILE *file, sd_journal *j, Table *t) {
|
||||
if (STRPTR_IN_SET(present, "present", "journal") && truncated && parse_boolean(truncated) > 0)
|
||||
present = "truncated";
|
||||
|
||||
if (sd_id128_is_null(coredump_id))
|
||||
r = table_add_cell(t, /* ret_cell= */ NULL, TABLE_EMPTY, /* data= */ NULL);
|
||||
else
|
||||
r = table_add_cell(t, /* ret_cell= */ NULL, TABLE_ID128, &coredump_id);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
r = table_add_many(
|
||||
t,
|
||||
TABLE_TIMESTAMP, ts,
|
||||
@@ -203,6 +214,7 @@ static int print_list(FILE *file, sd_journal *j, Table *t) {
|
||||
|
||||
typedef enum CoredumpField {
|
||||
COREDUMP_FIELD_MID,
|
||||
COREDUMP_FIELD_ID,
|
||||
COREDUMP_FIELD_PID,
|
||||
COREDUMP_FIELD_UID,
|
||||
COREDUMP_FIELD_GID,
|
||||
@@ -234,6 +246,7 @@ typedef enum CoredumpField {
|
||||
|
||||
static const char* const coredump_field_table[_COREDUMP_FIELD_MAX] = {
|
||||
[COREDUMP_FIELD_MID] = "MESSAGE_ID",
|
||||
[COREDUMP_FIELD_ID] = "COREDUMP_ID",
|
||||
[COREDUMP_FIELD_PID] = "COREDUMP_PID",
|
||||
[COREDUMP_FIELD_UID] = "COREDUMP_UID",
|
||||
[COREDUMP_FIELD_GID] = "COREDUMP_GID",
|
||||
@@ -265,6 +278,7 @@ static const char* const coredump_field_table[_COREDUMP_FIELD_MAX] = {
|
||||
typedef struct CoredumpFields {
|
||||
char *fields[_COREDUMP_FIELD_MAX];
|
||||
|
||||
sd_id128_t coredump_id;
|
||||
bool normal_coredump;
|
||||
const char *storage_state; /* points to a static string, not owned */
|
||||
const char *storage_color; /* points to a static string, not owned */
|
||||
@@ -298,6 +312,12 @@ static int coredump_fields_load(sd_journal *j, CoredumpFields *f) {
|
||||
|
||||
f->normal_coredump = streq_ptr(f->fields[COREDUMP_FIELD_MID], SD_MESSAGE_COREDUMP_STR);
|
||||
|
||||
if (f->fields[COREDUMP_FIELD_ID]) {
|
||||
r = sd_id128_from_string(f->fields[COREDUMP_FIELD_ID], &f->coredump_id);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse coredump ID '%s', ignoring: %m", f->fields[COREDUMP_FIELD_ID]);
|
||||
}
|
||||
|
||||
if (f->fields[COREDUMP_FIELD_FILENAME]) {
|
||||
r = resolve_filename(arg_root, &f->fields[COREDUMP_FIELD_FILENAME]);
|
||||
if (r < 0)
|
||||
@@ -453,6 +473,14 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
if (!sd_id128_is_null(f.coredump_id)) {
|
||||
r = table_add_many(table,
|
||||
TABLE_FIELD, "ID",
|
||||
TABLE_ID128, f.coredump_id);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
if (f.fields[COREDUMP_FIELD_COMM])
|
||||
r = table_add_string_fieldf_full(
|
||||
table, "PID", TABLE_STRING_WITH_ANSI, "%s%s%s (%s)",
|
||||
@@ -672,6 +700,7 @@ static int print_info_json(FILE *file, sd_journal *j) {
|
||||
(void) safe_atou64(f.fields[COREDUMP_FIELD_TIMESTAMP], &ts);
|
||||
|
||||
r = sd_json_build(&v, SD_JSON_BUILD_OBJECT(
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(f.coredump_id), "ID", SD_JSON_BUILD_ID128(f.coredump_id)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(pid_is_valid(pid_as_int), "PID", SD_JSON_BUILD_UNSIGNED(pid_as_int)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!pid_is_valid(pid_as_int) && !!f.fields[COREDUMP_FIELD_PID], "PID", SD_JSON_BUILD_STRING(f.fields[COREDUMP_FIELD_PID])),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(pid_is_valid(tid_as_int), "TID", SD_JSON_BUILD_UNSIGNED(tid_as_int)),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-id128.h"
|
||||
#include "sd-messages.h"
|
||||
|
||||
#include "coredumpctl.h"
|
||||
@@ -15,11 +16,16 @@
|
||||
static int add_match(sd_journal *j, const char *match) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
const char *field;
|
||||
char id_str[SD_ID128_STRING_MAX];
|
||||
sd_id128_t id;
|
||||
int r;
|
||||
|
||||
if (strchr(match, '='))
|
||||
field = NULL;
|
||||
else if (is_path(match)) {
|
||||
else if (sd_id128_from_string(match, &id) >= 0) {
|
||||
match = sd_id128_to_string(id, id_str);
|
||||
field = "COREDUMP_ID";
|
||||
} else if (is_path(match)) {
|
||||
r = path_make_absolute_cwd(match, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match);
|
||||
|
||||
@@ -25,17 +25,19 @@ int verb_dump_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
return r;
|
||||
|
||||
if (!verb_is_info && !arg_field) {
|
||||
t = table_new("time", "pid", "uid", "gid", "sig", "corefile", "exe", "size");
|
||||
t = table_new("id", "time", "pid", "uid", "gid", "sig", "corefile", "exe", "size");
|
||||
if (!t)
|
||||
return log_oom();
|
||||
|
||||
if (arg_full)
|
||||
table_set_width(t, 0);
|
||||
|
||||
(void) table_set_align_percent(t, TABLE_HEADER_CELL(1), 100);
|
||||
(void) table_set_ellipsize_percent(t, TABLE_HEADER_CELL(1), 100);
|
||||
|
||||
(void) table_set_align_percent(t, TABLE_HEADER_CELL(2), 100);
|
||||
(void) table_set_align_percent(t, TABLE_HEADER_CELL(3), 100);
|
||||
(void) table_set_align_percent(t, TABLE_HEADER_CELL(7), 100);
|
||||
(void) table_set_align_percent(t, TABLE_HEADER_CELL(4), 100);
|
||||
(void) table_set_align_percent(t, TABLE_HEADER_CELL(8), 100);
|
||||
|
||||
table_set_ersatz_string(t, TABLE_ERSATZ_DASH);
|
||||
} else if (!sd_json_format_enabled(arg_json_format_flags))
|
||||
|
||||
@@ -199,6 +199,23 @@ coredumpctl info "$CORE_TEST_BIN" | grep "TID:" >/dev/null
|
||||
# Check the field is queryable in the journal
|
||||
coredumpctl -F COREDUMP_TID
|
||||
|
||||
# Test cases for Coredump ID
|
||||
LATEST_ID=$(coredumpctl list -1 --json=short "$CORE_TEST_BIN" | jq -r '.[0].id')
|
||||
[[ -n "$LATEST_ID" ]]
|
||||
[[ "$LATEST_ID" != null ]]
|
||||
# Test with explicit COREDUMP_ID= field
|
||||
coredumpctl list COREDUMP_ID="$LATEST_ID" | grep "$LATEST_ID" >/dev/null
|
||||
coredumpctl info COREDUMP_ID="$LATEST_ID" | grep --fixed-strings "ID: $LATEST_ID" >/dev/null
|
||||
coredumpctl info --json=short COREDUMP_ID="$LATEST_ID" | jq -e ".ID == \"$LATEST_ID\""
|
||||
coredumpctl info --json=pretty COREDUMP_ID="$LATEST_ID" | jq -e ".ID == \"$LATEST_ID\""
|
||||
# Test with bare UUID (without COREDUMP_ID= prefix)
|
||||
coredumpctl info "$LATEST_ID" | grep --fixed-strings "ID: $LATEST_ID" >/dev/null
|
||||
coredumpctl info --json=short "$LATEST_ID" | jq -e ".ID == \"$LATEST_ID\""
|
||||
# Test with dashed UUID format
|
||||
LATEST_ID_DASHED="${LATEST_ID:0:8}-${LATEST_ID:8:4}-${LATEST_ID:12:4}-${LATEST_ID:16:4}-${LATEST_ID:20:12}"
|
||||
coredumpctl info "$LATEST_ID_DASHED" | grep --fixed-strings "ID: $LATEST_ID" >/dev/null
|
||||
coredumpctl info --json=short "$LATEST_ID_DASHED" | jq -e ".ID == \"$LATEST_ID\""
|
||||
|
||||
# If COREDUMP_CODE= is present, check that the expected code is SI_USER (0).
|
||||
if coredumpctl -F COREDUMP_CODE | grep "^0$" >/dev/null; then
|
||||
coredumpctl info "$CORE_TEST_BIN" | grep --fixed-strings "Signal: 5 (TRAP) si_code: SI_USER" >/dev/null
|
||||
@@ -282,6 +299,13 @@ coredumpctl info COREDUMP_HOSTNAME="mymachine"
|
||||
coredumpctl info COREDUMP_TIMESTAMP=1679509902000000
|
||||
coredumpctl info COREDUMP_HOSTNAME="youmachine"
|
||||
coredumpctl info COREDUMP_DUMPABLE="1"
|
||||
# Verify that backtrace entries have COREDUMP_ID set
|
||||
coredumpctl info --json=short COREDUMP_TIMESTAMP=1679509900000000 | jq -e '.ID != null'
|
||||
coredumpctl info --json=short COREDUMP_TIMESTAMP=1679509901000000 | jq -e '.ID != null'
|
||||
coredumpctl info --json=short COREDUMP_TIMESTAMP=1679509902000000 | jq -e '.ID != null'
|
||||
# Verify that backtrace entries can be queried by ID
|
||||
BACKTRACE_ID=$(coredumpctl list -n 1 --json=short COREDUMP_TIMESTAMP=1679509900000000 | jq -r '.[0].id')
|
||||
coredumpctl info "$BACKTRACE_ID" | grep --fixed-strings "ID: $BACKTRACE_ID" >/dev/null
|
||||
|
||||
# This used to cause a stack overflow
|
||||
systemd-run -t --property CoredumpFilter=all ls /tmp
|
||||
|
||||
Reference in new issue
Block a user