summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-06-18 23:34:59 +0200
committerLennart Poettering <lennart@poettering.net>2014-06-19 00:00:24 +0200
commite15758cce3c606a56c5aab080b54b02e8b263c9b (patch)
tree700ac7df08a29a1376f1f74931dd65fe14b620fd
parenta276ae74299fbdcf3321740c74fbf97501c63aad (diff)
coredump: add new "info" verb to coredumpctl showing detailed information about a coredump
-rw-r--r--src/journal/coredumpctl.c201
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);