diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-06-18 23:34:59 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-06-19 00:00:24 +0200 |
commit | e15758cce3c606a56c5aab080b54b02e8b263c9b (patch) | |
tree | 700ac7df08a29a1376f1f74931dd65fe14b620fd | |
parent | a276ae74299fbdcf3321740c74fbf97501c63aad (diff) |
coredump: add new "info" verb to coredumpctl showing detailed information about a coredump
-rw-r--r-- | src/journal/coredumpctl.c | 201 |
1 files changed, 144 insertions, 57 deletions
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c index db0f3d67cc..8699716679 100644 --- a/src/journal/coredumpctl.c +++ b/src/journal/coredumpctl.c @@ -40,13 +40,14 @@ static enum { ACTION_NONE, + ACTION_INFO, ACTION_LIST, ACTION_DUMP, ACTION_GDB, } arg_action = ACTION_LIST; static FILE* output = NULL; -static char* arg_field = NULL; +static const char* arg_field = NULL; static int arg_no_pager = false; static int arg_no_legend = false; @@ -93,6 +94,7 @@ static int help(void) { " --version Print version string\n" " -F --field=FIELD List all values a certain field takes\n" " list [MATCHES...] List available coredumps\n" + " info [MATCHES...] Show detailed information about one or more coredumps\n" " dump [MATCHES...] Print first matching coredump to stdout\n" " gdb [MATCHES...] Start gdb for the first matching coredump\n" , program_invocation_short_name); @@ -203,7 +205,6 @@ static int parse_argv(int argc, char *argv[], Set *matches) { log_error("cannot use --field/-F more than once"); return -EINVAL; } - arg_field = optarg; break; @@ -222,6 +223,8 @@ static int parse_argv(int argc, char *argv[], Set *matches) { arg_action = ACTION_DUMP; else if (streq(cmd, "gdb")) arg_action = ACTION_GDB; + else if (streq(cmd, "info")) + arg_action = ACTION_INFO; else { log_error("Unknown action '%s'", cmd); return -EINVAL; @@ -272,11 +275,63 @@ static int retrieve(const void *data, return 0; } +#define filename_escape(s) xescape((s), "./") + +static int make_coredump_path(sd_journal *j, char **ret) { + _cleanup_free_ char + *pid = NULL, *boot_id = NULL, *tstamp = NULL, *comm = NULL, + *p = NULL, *b = NULL, *t = NULL, *c = NULL; + const void *d; + size_t l; + char *fn; + + assert(j); + assert(ret); + + SD_JOURNAL_FOREACH_DATA(j, d, l) { + retrieve(d, l, "COREDUMP_COMM", &comm); + retrieve(d, l, "COREDUMP_PID", &pid); + retrieve(d, l, "COREDUMP_TIMESTAMP", &tstamp); + retrieve(d, l, "_BOOT_ID", &boot_id); + } + + if (!pid || !comm || !tstamp || !boot_id) { + log_error("Failed to retrieve necessary fields to find coredump on disk."); + return -ENOENT; + } + + p = filename_escape(pid); + if (!p) + return log_oom(); + + t = filename_escape(tstamp); + if (!t) + return log_oom(); + + c = filename_escape(comm); + if (!t) + return log_oom(); + + b = filename_escape(boot_id); + if (!b) + return log_oom(); + + fn = strjoin("/var/lib/systemd/coredump/core.", c, ".", b, ".", p, ".", t, NULL); + if (!fn) + return log_oom(); + + *ret = fn; + return 0; +} + static void print_field(FILE* file, sd_journal *j) { _cleanup_free_ char *value = NULL; const void *d; size_t l; + assert(file); + assert(j); + assert(arg_field); SD_JOURNAL_FOREACH_DATA(j, d, l) @@ -286,7 +341,7 @@ static void print_field(FILE* file, sd_journal *j) { fprintf(file, "%s\n", value); } -static int print_entry(FILE* file, sd_journal *j, int had_legend) { +static int print_list(FILE* file, sd_journal *j, int had_legend) { _cleanup_free_ char *pid = NULL, *uid = NULL, *gid = NULL, *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL; @@ -296,6 +351,9 @@ static int print_entry(FILE* file, sd_journal *j, int had_legend) { char buf[FORMAT_TIMESTAMP_MAX]; int r; + assert(file); + assert(j); + SD_JOURNAL_FOREACH_DATA(j, d, l) { retrieve(d, l, "COREDUMP_PID", &pid); retrieve(d, l, "COREDUMP_UID", &uid); @@ -339,6 +397,80 @@ static int print_entry(FILE* file, sd_journal *j, int had_legend) { return 0; } +static int print_info(FILE *file, sd_journal *j, bool need_space) { + _cleanup_free_ char + *pid = NULL, *uid = NULL, *gid = NULL, + *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL, + *unit = NULL, *user_unit = NULL, *session = NULL, + *boot_id = NULL, *machine_id = NULL, *hostname = NULL, *coredump = NULL; + const void *d; + size_t l; + + assert(file); + assert(j); + + SD_JOURNAL_FOREACH_DATA(j, d, l) { + retrieve(d, l, "COREDUMP_PID", &pid); + retrieve(d, l, "COREDUMP_UID", &uid); + retrieve(d, l, "COREDUMP_GID", &gid); + retrieve(d, l, "COREDUMP_SIGNAL", &sgnl); + retrieve(d, l, "COREDUMP_EXE", &exe); + retrieve(d, l, "COREDUMP_COMM", &comm); + retrieve(d, l, "COREDUMP_CMDLINE", &cmdline); + retrieve(d, l, "COREDUMP_UNIT", &unit); + retrieve(d, l, "COREDUMP_USER_UNIT", &user_unit); + retrieve(d, l, "COREDUMP_SESSION", &session); + retrieve(d, l, "_BOOT_ID", &boot_id); + retrieve(d, l, "_MACHINE_ID", &machine_id); + retrieve(d, l, "_HOSTNAME", &hostname); + } + + if (need_space) + fputs("\n", file); + + fprintf(file, + " PID: %s\n" + " UID: %s\n" + " GID: %s\n", + strna(pid), + strna(uid), + strna(gid)); + + if (sgnl) { + int sig; + + if (safe_atoi(sgnl, &sig) >= 0) + fprintf(file, " Signal: %s (%s)\n", sgnl, signal_to_string(sig)); + else + fprintf(file, " Signal: %s\n", sgnl); + } + + if (exe) + fprintf(file, " Executable: %s\n", exe); + if (comm) + fprintf(file, " Comm: %s\n", comm); + if (cmdline) + fprintf(file, " Command Line: %s\n", cmdline); + if (unit) + fprintf(file, " Unit: %s\n", unit); + if (user_unit) + fprintf(file, " User Unit: %s\n", unit); + if (session) + fprintf(file, " Session: %s\n", session); + if (boot_id) + fprintf(file, " Boot ID: %s\n", boot_id); + if (machine_id) + fprintf(file, " Machine ID: %s\n", machine_id); + if (hostname) + fprintf(file, " Hostname: %s\n", hostname); + + if (make_coredump_path(j, &coredump) >= 0) + if (access(coredump, F_OK) >= 0) + fprintf(file, " Coredump: %s\n", coredump); + + return 0; +} + static int dump_list(sd_journal *j) { int found = 0; @@ -350,10 +482,12 @@ static int dump_list(sd_journal *j) { sd_journal_set_data_threshold(j, 4096); SD_JOURNAL_FOREACH(j) { - if (arg_field) + if (arg_action == ACTION_INFO) + print_info(stdout, j, found++); + else if (arg_field) print_field(stdout, j); else - print_entry(stdout, j, found++); + print_list(stdout, j, found++); } if (!arg_field && !found) { @@ -381,55 +515,6 @@ static int focus(sd_journal *j) { return r; } -#define filename_escape(s) xescape((s), "./") - -static int make_coredump_path(sd_journal *j, char **ret) { - _cleanup_free_ char - *pid = NULL, *boot_id = NULL, *tstamp = NULL, *comm = NULL, - *p = NULL, *b = NULL, *t = NULL, *c = NULL; - const void *d; - size_t l; - char *fn; - - assert(j); - assert(ret); - - SD_JOURNAL_FOREACH_DATA(j, d, l) { - retrieve(d, l, "COREDUMP_COMM", &comm); - retrieve(d, l, "COREDUMP_PID", &pid); - retrieve(d, l, "COREDUMP_TIMESTAMP", &tstamp); - retrieve(d, l, "_BOOT_ID", &boot_id); - } - - if (!pid || !comm || !tstamp || !boot_id) { - log_error("Failed to retrieve necessary fields to find coredump on disk."); - return -ENOENT; - } - - p = filename_escape(pid); - if (!p) - return log_oom(); - - t = filename_escape(tstamp); - if (!t) - return log_oom(); - - c = filename_escape(comm); - if (!t) - return log_oom(); - - b = filename_escape(boot_id); - if (!b) - return log_oom(); - - fn = strjoin("/var/lib/systemd/coredump/core.", c, ".", b, ".", p, ".", t, NULL); - if (!fn) - return log_oom(); - - *ret = fn; - return 0; -} - static int dump_core(sd_journal* j) { const void *data; size_t len, ret; @@ -444,10 +529,10 @@ static int dump_core(sd_journal* j) { if (r < 0) return r; - print_entry(output ? stdout : stderr, j, false); + print_info(output ? stdout : stderr, j, false); if (on_tty() && !output) { - log_error("Refusing to dump core to tty"); + log_error("Refusing to dump core to tty."); return -ENOTTY; } @@ -519,7 +604,8 @@ static int run_gdb(sd_journal *j) { if (r < 0) return r; - print_entry(stdout, j, false); + print_info(stdout, j, false); + fputs("\n", stdout); r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len); if (r < 0) { @@ -675,6 +761,7 @@ int main(int argc, char *argv[]) { switch(arg_action) { case ACTION_LIST: + case ACTION_INFO: if (!arg_no_pager) pager_open(false); |