]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
coredumpctl: parse and print package metadata
authorLuca Boccassi <luca.boccassi@microsoft.com>
Tue, 6 Apr 2021 17:02:41 +0000 (18:02 +0100)
committerLuca Boccassi <luca.boccassi@microsoft.com>
Tue, 6 Apr 2021 22:12:51 +0000 (23:12 +0100)
src/coredump/coredumpctl.c

index 0c4ef2e123486216213435956539b90482b4454c..3418753a31b3312d09108ba5eec01835f19cb74b 100644 (file)
@@ -545,7 +545,8 @@ 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, *coredump = NULL,
+                *pkgmeta_name = NULL, *pkgmeta_version = NULL, *pkgmeta_json = NULL;
         const void *d;
         size_t l;
         bool normal_coredump;
@@ -574,6 +575,9 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
                 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
                 RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
                 RETRIEVE(d, l, "COREDUMP", coredump);
+                RETRIEVE(d, l, "COREDUMP_PKGMETA_PACKAGE", pkgmeta_name);
+                RETRIEVE(d, l, "COREDUMP_PKGMETA_PACKAGEVERSION", pkgmeta_version);
+                RETRIEVE(d, l, "COREDUMP_PKGMETA_JSON", pkgmeta_json);
                 RETRIEVE(d, l, "_BOOT_ID", boot_id);
                 RETRIEVE(d, l, "_MACHINE_ID", machine_id);
                 RETRIEVE(d, l, "MESSAGE", message);
@@ -716,6 +720,68 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
         else
                 fprintf(file, "       Storage: none\n");
 
+        if (pkgmeta_name && pkgmeta_version)
+                fprintf(file, "       Package: %s/%s\n", pkgmeta_name, pkgmeta_version);
+
+        /* Print out the build-id of the 'main' ELF module, by matching the JSON key
+         * with the 'exe' field. */
+        if (exe && pkgmeta_json) {
+                _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+                r = json_parse(pkgmeta_json, 0, &v, NULL, NULL);
+                if (r < 0) {
+                        log_warning_errno(r, "json_parse on %s failed, ignoring: %m", pkgmeta_json);
+                } else {
+                        const char *module_name;
+                        JsonVariant *module_json;
+
+                        /* Cannot nest two JSON_VARIANT_OBJECT_FOREACH as they define the same
+                        * iterator variable '_state' */
+                        for (struct json_variant_foreach_state _state2 = { (v), 0 };     \
+                             json_variant_is_object(_state2.variant) &&                  \
+                                     _state2.idx < json_variant_elements(_state2.variant) && \
+                                     ({ module_name = json_variant_string(json_variant_by_index(_state2.variant, _state2.idx)); \
+                                        module_json = json_variant_by_index(_state2.variant, _state2.idx + 1); \
+                                        true; });                                  \
+                             _state2.idx += 2) {
+                                _cleanup_free_ char *module_basename = NULL, *exe_basename = NULL;
+                                const char *key;
+                                JsonVariant *w;
+
+                                /* The module name, most likely parsed from the ELF core file,
+                                 * sometimes contains the full path and sometimes does not. */
+                                r = path_extract_filename(module_name, &module_basename);
+                                if (r < 0) {
+                                        log_warning_errno(r, "Failed to parse module basename: %m");
+                                        break;
+                                }
+                                r = path_extract_filename(exe, &exe_basename);
+                                if (r < 0) {
+                                        log_warning_errno(r, "Failed to parse executable basename: %m");
+                                        break;
+                                }
+
+                                /* We only print the build-id for the 'main' ELF module */
+                                if (!streq(module_basename, exe_basename))
+                                        continue;
+
+                                JSON_VARIANT_OBJECT_FOREACH(key, w, module_json) {
+                                        if (!json_variant_is_string(w))
+                                                continue;
+
+                                        if (!streq(key, "buildid"))
+                                                continue;
+
+                                        fprintf(file, "      build-id: %s\n", json_variant_string(w));
+
+                                        break;
+                                }
+
+                                break;
+                        }
+                }
+        }
+
         if (message) {
                 _cleanup_free_ char *m = NULL;