From 329233dcbf769a98eeaa6f1416b6f446d9263f13 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Tue, 7 Apr 2026 16:29:51 +0100 Subject: [PATCH 1/3] sd-journal: make sd_journal_get_data() output params optional Allow callers to pass NULL for ret_data and/or ret_size when they only need to check whether a field exists. Initialize provided output pointers to safe defaults and update the manual page accordingly. Propagate the NULL-ness through to journal_file_data_payload() so that downstream helpers can optimize for the existence-check case. Co-developed-by: Claude Opus 4.6 --- man/sd_journal_get_data.xml | 10 ++++++++-- src/libsystemd/sd-journal/sd-journal.c | 11 ++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/man/sd_journal_get_data.xml b/man/sd_journal_get_data.xml index e3c8e0b5cd..a902d76c73 100644 --- a/man/sd_journal_get_data.xml +++ b/man/sd_journal_get_data.xml @@ -83,8 +83,10 @@ sd_journal_get_data() gets the data object associated with a specific field from the current journal entry. It takes four arguments: the journal context object, a string with the - field name to request, plus a pair of pointers to pointer/size variables where the data object and its - size shall be stored in. The field name should be an entry field name. Well-known field names are listed in + field name to request, plus a pair of optional pointers to pointer/size variables where the data object and + its size shall be stored in. Either pointer may be NULL, in which case the corresponding + value is not returned (this is supported since version 261). The field name should be an entry field name. + Well-known field names are listed in systemd.journal-fields7, but any field can be specified. The returned data is in a read-only memory map and is only valid until the next invocation of sd_journal_get_data(), @@ -162,6 +164,10 @@ -EINVAL One of the required parameters is NULL or invalid. + For sd_journal_get_data(), only the journal context object and field name + are required non-NULL. For sd_journal_enumerate_data() + and sd_journal_enumerate_available_data(), + ret_data and ret_size are required as well. diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c index befa194517..3e5185b23f 100644 --- a/src/libsystemd/sd-journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -2822,8 +2822,6 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** assert_return(j, -EINVAL); assert_return(!journal_origin_changed(j), -ECHILD); assert_return(field, -EINVAL); - assert_return(ret_data, -EINVAL); - assert_return(ret_size, -EINVAL); assert_return(field_is_valid(field), -EINVAL); f = j->current_file; @@ -2846,7 +2844,8 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** size_t l; p = journal_file_entry_item_object_offset(f, o, i); - r = journal_file_data_payload(f, NULL, p, field, field_length, j->data_threshold, &d, &l); + r = journal_file_data_payload(f, NULL, p, field, field_length, j->data_threshold, + ret_data ? &d : NULL, ret_size ? &l : NULL); if (r == 0) continue; if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) { @@ -2856,8 +2855,10 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** if (r < 0) return r; - *ret_data = d; - *ret_size = l; + if (ret_data) + *ret_data = d; + if (ret_size) + *ret_size = l; return 0; } From a5c811591ff25fef3f3fd2b6ae09eaa6eeb7e5bd Mon Sep 17 00:00:00 2001 From: noxiouz Date: Tue, 7 Apr 2026 16:29:56 +0100 Subject: [PATCH 2/3] sd-journal: skip full decompression when caller only checks field existence When both ret_data and ret_size are NULL after decompress_startswith() has confirmed the field matches, skip the decompress_blob() call. This avoids decompressing potentially large payloads (e.g. inline coredumps) just to discard the result. Co-developed-by: Claude Opus 4.6 --- src/libsystemd/sd-journal/journal-file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 363df258a1..235f471224 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -1965,6 +1965,10 @@ static int maybe_decompress_payload( *ret_size = 0; return 0; } + + /* Caller only wants to check field existence, skip full decompression */ + if (!ret_data && !ret_size) + return 1; } r = decompress_blob(compression, payload, size, &f->compress_buffer, &rsize, 0); From 836de2900ba4d3b2afd015308774d26a1de2ca81 Mon Sep 17 00:00:00 2001 From: noxiouz Date: Tue, 7 Apr 2026 16:30:04 +0100 Subject: [PATCH 3/3] coredumpctl: use NULL outputs for COREDUMP existence checks print_list() and print_info() used RETRIEVE() to strndup() the entire COREDUMP field into a heap-allocated string, only to check whether it exists. With sd_journal_set_data_threshold(j, 0) in print_info(), this copies the full coredump binary (potentially hundreds of MB) to heap just to print "Storage: journal". Now that sd_journal_get_data() accepts NULL output pointers, use a direct NULL/NULL existence check instead. Co-developed-by: Claude Opus 4.6 --- src/coredump/coredumpctl.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 96724de12b..86d75bbdc9 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -552,14 +552,14 @@ static int print_list(FILE* file, sd_journal *j, Table *t) { _cleanup_free_ char *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL, *sgnl = NULL, *exe = NULL, *comm = NULL, - *filename = NULL, *truncated = NULL, *coredump = NULL; + *filename = NULL, *truncated = NULL; const void *d; size_t l; usec_t ts; int r, signal_as_int = 0; const char *present = NULL, *color = NULL; uint64_t size = UINT64_MAX; - bool normal_coredump; + bool normal_coredump, has_inline_coredump; uid_t uid_as_int = UID_INVALID; gid_t gid_as_int = GID_INVALID; pid_t pid_as_int = 0; @@ -578,9 +578,11 @@ static int print_list(FILE* file, sd_journal *j, Table *t) { RETRIEVE(d, l, "COREDUMP_COMM", comm); RETRIEVE(d, l, "COREDUMP_FILENAME", filename); RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated); - RETRIEVE(d, l, "COREDUMP", coredump); } + /* Check for an inline coredump without copying the (potentially large) payload to heap. */ + has_inline_coredump = sd_journal_get_data(j, "COREDUMP", NULL, NULL) >= 0; + if (!pid || !uid || !gid || !sgnl || !comm) { log_warning("Found a coredump entry without mandatory fields (PID=%s, UID=%s, GID=%s, SIGNAL=%s, COMM=%s), ignoring.", strna(pid), strna(uid), strna(gid), strna(sgnl), strna(comm)); @@ -604,7 +606,7 @@ static int print_list(FILE* file, sd_journal *j, Table *t) { return r; analyze_coredump_file(filename, &present, &color, &size); - } else if (coredump) + } else if (has_inline_coredump) present = "journal"; else if (normal_coredump) { present = "none"; @@ -640,12 +642,12 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { *boot_id = NULL, *machine_id = NULL, *hostname = NULL, *slice = NULL, *cgroup = NULL, *owner_uid = NULL, *message = NULL, *timestamp = NULL, *filename = NULL, - *truncated = NULL, *coredump = NULL, + *truncated = NULL, *pkgmeta_name = NULL, *pkgmeta_version = NULL, *pkgmeta_json = NULL, *tid = NULL, *thread_name = NULL; const void *d; size_t l; - bool normal_coredump; + bool normal_coredump, has_inline_coredump; int r; assert(file); @@ -672,7 +674,6 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { RETRIEVE(d, l, "COREDUMP_TIMESTAMP", timestamp); RETRIEVE(d, l, "COREDUMP_FILENAME", filename); RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated); - RETRIEVE(d, l, "COREDUMP", coredump); RETRIEVE(d, l, "COREDUMP_PACKAGE_NAME", pkgmeta_name); RETRIEVE(d, l, "COREDUMP_PACKAGE_VERSION", pkgmeta_version); RETRIEVE(d, l, "COREDUMP_PACKAGE_JSON", pkgmeta_json); @@ -683,6 +684,9 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { RETRIEVE(d, l, "MESSAGE", message); } + /* Check for an inline coredump without copying the (potentially large) payload to heap. */ + has_inline_coredump = sd_journal_get_data(j, "COREDUMP", NULL, NULL) >= 0; + if (need_space) fputs("\n", file); @@ -820,7 +824,7 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { if (size != UINT64_MAX) fprintf(file, " Size on Disk: %s\n", FORMAT_BYTES(size)); - } else if (coredump) + } else if (has_inline_coredump) fprintf(file, " Storage: journal\n"); else fprintf(file, " Storage: none\n");