X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Fjournal%2Fcoredumpctl.c;h=731468330909589842de9c29db0c260823972bf7;hb=0c51aada566403039544bc8ef094fadb4af29e23;hp=db0f3d67ccac47fa238dd9d12abaa34473849938;hpb=a276ae74299fbdcf3321740c74fbf97501c63aad;p=elogind.git diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c index db0f3d67c..731468330 100644 --- a/src/journal/coredumpctl.c +++ b/src/journal/coredumpctl.c @@ -40,16 +40,17 @@ 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; +static int arg_one = false; + +static FILE* output = NULL; static Set *new_matches(void) { Set *set; @@ -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); @@ -163,7 +165,7 @@ static int parse_argv(int argc, char *argv[], Set *matches) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "ho:F:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "ho:F:1", options, NULL)) >= 0) switch(c) { case 'h': @@ -203,10 +205,13 @@ 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; + case '1': + arg_one = true; + break; + case '?': return -EINVAL; @@ -222,6 +227,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 +279,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 +345,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 +355,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,26 +401,139 @@ static int print_entry(FILE* file, sd_journal *j, int had_legend) { return 0; } -static int dump_list(sd_journal *j) { - int found = 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, *slice = NULL, *cgroup = NULL, + *owner_uid = NULL, *message = NULL; + const void *d; + size_t l; + assert(file); assert(j); - /* The coredumps are likely to compressed, and for just - * listing them we don't need to decompress them, so let's - * pick a fairly low data threshold here */ - sd_journal_set_data_threshold(j, 4096); + 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, "COREDUMP_OWNER_UID", &owner_uid); + retrieve(d, l, "COREDUMP_SLICE", &slice); + retrieve(d, l, "COREDUMP_CGROUP", &cgroup); + retrieve(d, l, "_BOOT_ID", &boot_id); + retrieve(d, l, "_MACHINE_ID", &machine_id); + retrieve(d, l, "_HOSTNAME", &hostname); + retrieve(d, l, "MESSAGE", &message); + } + + if (need_space) + fputs("\n", file); - SD_JOURNAL_FOREACH(j) { - if (arg_field) - print_field(stdout, j); + fprintf(file, + " PID: %s%s%s\n", + ansi_highlight(), strna(pid), ansi_highlight_off()); + + if (uid) { + uid_t n; + + if (parse_uid(uid, &n) >= 0) { + _cleanup_free_ char *u = NULL; + + u = uid_to_name(n); + fprintf(file, + " UID: %s (%s)\n", + uid, u); + } else { + fprintf(file, + " UID: %s\n", + uid); + } + } + + if (gid) { + gid_t n; + + if (parse_gid(gid, &n) >= 0) { + _cleanup_free_ char *g = NULL; + + g = gid_to_name(n); + fprintf(file, + " GID: %s (%s)\n", + gid, g); + } else { + fprintf(file, + " GID: %s\n", + gid); + } + } + + if (sgnl) { + int sig; + + if (safe_atoi(sgnl, &sig) >= 0) + fprintf(file, " Signal: %s (%s)\n", sgnl, signal_to_string(sig)); else - print_entry(stdout, j, found++); + fprintf(file, " Signal: %s\n", sgnl); } - if (!arg_field && !found) { - log_notice("No coredumps found"); - return -ESRCH; + if (exe) + fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_highlight_off()); + if (comm) + fprintf(file, " Comm: %s\n", comm); + if (cmdline) + fprintf(file, " Command Line: %s\n", cmdline); + if (cgroup) + fprintf(file, " Control Group: %s\n", cgroup); + if (unit) + fprintf(file, " Unit: %s\n", unit); + if (user_unit) + fprintf(file, " User Unit: %s\n", unit); + if (slice) + fprintf(file, " Slice: %s\n", slice); + if (session) + fprintf(file, " Session: %s\n", session); + if (owner_uid) { + uid_t n; + + if (parse_uid(owner_uid, &n) >= 0) { + _cleanup_free_ char *u = NULL; + + u = uid_to_name(n); + fprintf(file, + " Owner UID: %s (%s)\n", + owner_uid, u); + } else { + fprintf(file, + " Owner UID: %s\n", + owner_uid); + } + } + 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); + + if (message) { + _cleanup_free_ char *m = NULL; + + m = strreplace(message, "\n", "\n "); + + fprintf(file, " Message: %s\n", strstrip(m ?: message)); } return 0; @@ -375,58 +550,50 @@ static int focus(sd_journal *j) { return r; } if (r == 0) { - log_error("No match found"); + log_error("No match found."); return -ESRCH; } 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; - +static void print_entry(sd_journal *j, unsigned n_found) { 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 (arg_action == ACTION_INFO) + print_info(stdout, j, n_found); + else if (arg_field) + print_field(stdout, j); + else + print_list(stdout, j, n_found); +} - if (!pid || !comm || !tstamp || !boot_id) { - log_error("Failed to retrieve necessary fields to find coredump on disk."); - return -ENOENT; - } +static int dump_list(sd_journal *j) { + unsigned n_found = 0; + int r; - p = filename_escape(pid); - if (!p) - return log_oom(); + assert(j); - t = filename_escape(tstamp); - if (!t) - return log_oom(); + /* The coredumps are likely to compressed, and for just + * listing them we don't need to decompress them, so let's + * pick a fairly low data threshold here */ + sd_journal_set_data_threshold(j, 4096); - c = filename_escape(comm); - if (!t) - return log_oom(); + if (arg_one) { + r = focus(j); + if (r < 0) + return r; - b = filename_escape(boot_id); - if (!b) - return log_oom(); + print_entry(j, 0); + } else { + SD_JOURNAL_FOREACH(j) + print_entry(j, n_found++); - fn = strjoin("/var/lib/systemd/coredump/core.", c, ".", b, ".", p, ".", t, NULL); - if (!fn) - return log_oom(); + if (!arg_field && n_found <= 0) { + log_notice("No coredumps found."); + return -ESRCH; + } + } - *ret = fn; return 0; } @@ -444,10 +611,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 +686,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) { @@ -556,7 +724,7 @@ static int run_gdb(sd_journal *j) { if (errno == ENOENT) log_error("Coredump neither in journal file nor stored externally on disk."); else - log_error("Failed to access coredump fiile: %s", strerror(-r)); + log_error("Failed to access coredump file: %m"); return -errno; } @@ -675,6 +843,7 @@ int main(int argc, char *argv[]) { switch(arg_action) { case ACTION_LIST: + case ACTION_INFO: if (!arg_no_pager) pager_open(false);