X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fcoredumpctl.c;h=bcfee46da1d989b273f77ec14a911d50c40758de;hp=03f063fe5fcd714c4aa32df756c42d48bf604383;hb=eb9da376d76b48585b3b63b4f91903b54f7abd36;hpb=2fb7a5ce67fd6196416919535fa6a6065e0ea815 diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c index 03f063fe5..bcfee46da 100644 --- a/src/journal/coredumpctl.c +++ b/src/journal/coredumpctl.c @@ -19,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -33,6 +34,8 @@ #include "log.h" #include "path-util.h" #include "pager.h" +#include "macro.h" +#include "journal-internal.h" static enum { ACTION_NONE, @@ -41,10 +44,11 @@ static enum { ACTION_GDB, } arg_action = ACTION_LIST; -static Set *matches = NULL; static FILE* output = NULL; +static char* field = NULL; static int arg_no_pager = false; +static int arg_no_legend = false; static Set *new_matches(void) { Set *set; @@ -64,10 +68,9 @@ static Set *new_matches(void) { return NULL; } - r = set_put(set, tmp); + r = set_consume(set, tmp); if (r < 0) { log_error("failed to add to set: %s", strerror(-r)); - free(tmp); set_free(set); return NULL; } @@ -81,10 +84,13 @@ static int help(void) { "Flags:\n" " -o --output=FILE Write output to FILE\n" " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not print the column headers.\n\n" "Commands:\n" " -h --help Show this help\n" " --version Print version string\n" + " -F --field=FIELD List all values a certain field takes\n" + " gdb Start gdb for the first matching coredump\n" " list List available coredumps\n" " dump PID Print coredump to stdout\n" " dump PATH Print coredump to stdout\n" @@ -98,7 +104,7 @@ static int add_match(Set *set, const char *match) { unsigned pid; const char* prefix; char *pattern = NULL; - char _cleanup_free_ *p = NULL; + _cleanup_free_ char *p = NULL; if (strchr(match, '=')) prefix = ""; @@ -119,25 +125,25 @@ static int add_match(Set *set, const char *match) { if (!pattern) goto fail; - r = set_put(set, pattern); + log_debug("Adding pattern: %s", pattern); + r = set_consume(set, pattern); if (r < 0) { - log_error("failed to add pattern '%s': %s", + log_error("Failed to add pattern '%s': %s", pattern, strerror(-r)); goto fail; } - log_debug("Added pattern: %s", pattern); return 0; fail: - free(pattern); - log_error("failed to add match: %s", strerror(-r)); + log_error("Failed to add match: %s", strerror(-r)); return r; } -static int parse_argv(int argc, char *argv[]) { +static int parse_argv(int argc, char *argv[], Set *matches) { enum { ARG_VERSION = 0x100, ARG_NO_PAGER, + ARG_NO_LEGEND, }; int r, c; @@ -146,31 +152,36 @@ static int parse_argv(int argc, char *argv[]) { { "help", no_argument, NULL, 'h' }, { "version" , no_argument, NULL, ARG_VERSION }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, { "output", required_argument, NULL, 'o' }, - { NULL, 0, NULL, 0 } + { "field", required_argument, NULL, 'F' }, + {} }; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "ho:F:", options, NULL)) >= 0) switch(c) { + case 'h': - help(); arg_action = ACTION_NONE; - return 0; + return help(); case ARG_VERSION: + arg_action = ACTION_NONE; puts(PACKAGE_STRING); - puts(DISTRIBUTION); puts(SYSTEMD_FEATURES); - arg_action = ACTION_NONE; return 0; case ARG_NO_PAGER: arg_no_pager = true; break; + case ARG_NO_LEGEND: + arg_no_legend = true; + break; + case 'o': if (output) { log_error("cannot set output more than once"); @@ -185,12 +196,20 @@ static int parse_argv(int argc, char *argv[]) { break; + case 'F': + if (field) { + log_error("cannot use --field/-F more than once"); + return -EINVAL; + } + + field = optarg; + break; + case '?': return -EINVAL; default: - log_error("Unknown option code %c", c); - return -EINVAL; + assert_not_reached("Unhandled option"); } if (optind < argc) { @@ -207,6 +226,11 @@ static int parse_argv(int argc, char *argv[]) { } } + if (field && arg_action != ACTION_LIST) { + log_error("Option --field/-F only makes sense with list"); + return -EINVAL; + } + while (optind < argc) { r = add_match(matches, argv[optind]); if (r != 0) @@ -222,28 +246,41 @@ static int retrieve(const void *data, const char *name, const char **var) { - size_t field; + size_t ident; - field = strlen(name) + 1; /* name + "=" */ + ident = strlen(name) + 1; /* name + "=" */ - if (len < field) + if (len < ident) return 0; - if (memcmp(data, name, field - 1) != 0) + if (memcmp(data, name, ident - 1) != 0) return 0; - if (((const char*) data)[field - 1] != '=') + if (((const char*) data)[ident - 1] != '=') return 0; - *var = strndup((const char*)data + field, len - field); - if (!var) + *var = strndup((const char*)data + ident, len - ident); + if (!*var) return log_oom(); return 0; } -static int print_entry(FILE* file, sd_journal *j, int had_header) { - const char _cleanup_free_ +static void print_field(FILE* file, sd_journal *j) { + _cleanup_free_ const char *value = NULL; + const void *d; + size_t l; + + assert(field); + + SD_JOURNAL_FOREACH_DATA(j, d, l) + retrieve(d, l, field, &value); + if (value) + fprintf(file, "%s\n", value); +} + +static int print_entry(FILE* file, sd_journal *j, int had_legend) { + _cleanup_free_ const char *pid = NULL, *uid = NULL, *gid = NULL, *sgnl = NULL, *exe = NULL; const void *d; @@ -278,7 +315,7 @@ static int print_entry(FILE* file, sd_journal *j, int had_header) { format_timestamp(buf, sizeof(buf), t); - if (!had_header) + if (!had_legend && !arg_no_legend) fprintf(file, "%-*s %*s %*s %*s %*s %s\n", FORMAT_TIMESTAMP_MAX-1, "TIME", 6, "PID", @@ -303,10 +340,19 @@ static int dump_list(sd_journal *j) { assert(j); - SD_JOURNAL_FOREACH(j) - print_entry(stdout, j, found++); + /* 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(j) { + if (field) + print_field(stdout, j); + else + print_entry(stdout, j, found++); + } - if (!found) { + if (!field && !found) { log_notice("No coredumps found"); return -ESRCH; } @@ -338,6 +384,9 @@ static int dump_core(sd_journal* j) { assert(j); + /* We want full data, nothing truncated. */ + sd_journal_set_data_threshold(j, 0); + r = focus(j); if (r < 0) return r; @@ -385,6 +434,8 @@ static int run_gdb(sd_journal *j) { assert(j); + sd_journal_set_data_threshold(j, 0); + r = focus(j); if (r < 0) return r; @@ -467,11 +518,13 @@ finish: } int main(int argc, char *argv[]) { - sd_journal *j = NULL; + _cleanup_journal_close_ sd_journal*j = NULL; const char* match; Iterator it; int r = 0; + _cleanup_set_free_free_ Set *matches = NULL; + setlocale(LC_ALL, ""); log_parse_environment(); log_open(); @@ -481,7 +534,7 @@ int main(int argc, char *argv[]) { goto end; } - r = parse_argv(argc, argv); + r = parse_argv(argc, argv, matches); if (r < 0) goto end; @@ -503,11 +556,18 @@ int main(int argc, char *argv[]) { } } + if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { + _cleanup_free_ char *filter; + + filter = journal_make_match_string(j); + log_debug("Journal filter: %s", filter); + } + switch(arg_action) { case ACTION_LIST: if (!arg_no_pager) - pager_open(); + pager_open(false); r = dump_list(j); break; @@ -525,11 +585,6 @@ int main(int argc, char *argv[]) { } end: - if (j) - sd_journal_close(j); - - set_free_free(matches); - pager_close(); if (output)