2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <getopt.h>
|
2012-11-12 20:16:07 +01:00
|
|
|
#include <locale.h>
|
2012-10-19 12:29:46 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2012-10-27 01:19:47 +02:00
|
|
|
#include <unistd.h>
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2017-02-21 11:08:35 +01:00
|
|
|
#include "sd-bus.h"
|
2015-01-05 00:52:47 +01:00
|
|
|
#include "sd-journal.h"
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
#include "sd-messages.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2017-02-21 11:08:35 +01:00
|
|
|
#include "bus-error.h"
|
|
|
|
#include "bus-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "compress.h"
|
2018-10-01 17:44:46 +02:00
|
|
|
#include "def.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2016-07-26 17:23:28 +02:00
|
|
|
#include "fs-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "journal-internal.h"
|
2017-02-27 00:07:39 +01:00
|
|
|
#include "journal-util.h"
|
2012-10-19 12:29:46 +02:00
|
|
|
#include "log.h"
|
2013-03-18 04:36:25 +01:00
|
|
|
#include "macro.h"
|
2018-11-20 09:50:07 +01:00
|
|
|
#include "main-func.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "pager.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "path-util.h"
|
2018-11-20 15:42:57 +01:00
|
|
|
#include "pretty-print.h"
|
2015-04-10 19:10:00 +02:00
|
|
|
#include "process-util.h"
|
2018-10-01 17:44:46 +02:00
|
|
|
#include "rlimit-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "sigbus.h"
|
2015-05-29 20:14:11 +02:00
|
|
|
#include "signal-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2016-11-06 17:29:31 +01:00
|
|
|
#include "strv.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "terminal-util.h"
|
2018-11-30 21:05:27 +01:00
|
|
|
#include "tmpfile-util.h"
|
2015-10-25 22:32:30 +01:00
|
|
|
#include "user-util.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "util.h"
|
2018-03-14 09:46:34 +01:00
|
|
|
#include "verbs.h"
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2017-03-01 16:00:47 +01:00
|
|
|
#define SHORT_BUS_CALL_TIMEOUT_USEC (3 * USEC_PER_SEC)
|
|
|
|
|
2017-02-24 20:29:40 +01:00
|
|
|
static usec_t arg_since = USEC_INFINITY, arg_until = USEC_INFINITY;
|
2014-06-18 23:34:59 +02:00
|
|
|
static const char* arg_field = NULL;
|
2018-04-18 21:32:17 +02:00
|
|
|
static const char *arg_debugger = NULL;
|
2015-08-25 10:36:49 +02:00
|
|
|
static const char *arg_directory = NULL;
|
2018-11-11 12:56:29 +01:00
|
|
|
static PagerFlags arg_pager_flags = 0;
|
2012-10-30 09:45:19 +01:00
|
|
|
static int arg_no_legend = false;
|
2014-06-19 12:24:00 +02:00
|
|
|
static int arg_one = false;
|
2018-11-20 09:27:19 +01:00
|
|
|
static const char* arg_output = NULL;
|
2017-02-13 14:55:25 +01:00
|
|
|
static bool arg_reverse = false;
|
2017-02-27 00:07:39 +01:00
|
|
|
static bool arg_quiet = false;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2016-11-06 17:29:31 +01:00
|
|
|
static int add_match(sd_journal *j, const char *match) {
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2018-03-21 11:46:08 +01:00
|
|
|
const char* prefix, *pattern;
|
2015-10-22 19:28:31 +02:00
|
|
|
pid_t pid;
|
|
|
|
int r;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
if (strchr(match, '='))
|
|
|
|
prefix = "";
|
|
|
|
else if (strchr(match, '/')) {
|
2015-10-22 19:28:31 +02:00
|
|
|
r = path_make_absolute_cwd(match, &p);
|
|
|
|
if (r < 0)
|
2016-11-06 17:29:31 +01:00
|
|
|
return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match);
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
match = p;
|
|
|
|
prefix = "COREDUMP_EXE=";
|
2015-10-22 19:28:31 +02:00
|
|
|
} else if (parse_pid(match, &pid) >= 0)
|
2012-10-19 12:29:46 +02:00
|
|
|
prefix = "COREDUMP_PID=";
|
|
|
|
else
|
|
|
|
prefix = "COREDUMP_COMM=";
|
|
|
|
|
2018-03-05 08:39:52 +01:00
|
|
|
pattern = strjoina(prefix, match);
|
2016-11-06 17:29:31 +01:00
|
|
|
log_debug("Adding match: %s", pattern);
|
|
|
|
r = sd_journal_add_match(j, pattern, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add match \"%s\": %m", match);
|
2018-03-21 11:46:08 +01:00
|
|
|
|
2016-11-06 17:29:31 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
static int add_matches(sd_journal *j, char **matches) {
|
2016-11-06 17:29:31 +01:00
|
|
|
char **match;
|
|
|
|
int r;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0);
|
2015-10-22 19:28:31 +02:00
|
|
|
if (r < 0)
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
|
2016-11-06 17:29:31 +01:00
|
|
|
|
2016-11-06 19:34:31 +01:00
|
|
|
r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
STRV_FOREACH(match, matches) {
|
2016-11-06 17:29:31 +01:00
|
|
|
r = add_match(j, *match);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
static int acquire_journal(sd_journal **ret, char **matches) {
|
|
|
|
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
if (arg_directory) {
|
|
|
|
r = sd_journal_open_directory(&j, arg_directory, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory);
|
|
|
|
} else {
|
|
|
|
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open journal: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
r = journal_access_check_and_warn(j, arg_quiet, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = add_matches(j, matches);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (DEBUG_LOGGING) {
|
|
|
|
_cleanup_free_ char *filter;
|
|
|
|
|
|
|
|
filter = journal_make_match_string(j);
|
|
|
|
log_debug("Journal filter: %s", filter);
|
|
|
|
}
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(j);
|
2018-03-14 09:46:34 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int help(void) {
|
2018-08-09 10:32:31 +02:00
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = terminal_urlify_man("coredumpctl", "1", &link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
2014-08-02 17:12:21 +02:00
|
|
|
printf("%s [OPTIONS...]\n\n"
|
|
|
|
"List or retrieve coredumps from the journal.\n\n"
|
|
|
|
"Flags:\n"
|
2018-04-18 21:32:17 +02:00
|
|
|
" -h --help Show this help\n"
|
|
|
|
" --version Print version string\n"
|
|
|
|
" --no-pager Do not pipe output into a pager\n"
|
|
|
|
" --no-legend Do not print the column headers\n"
|
|
|
|
" --debugger=DEBUGGER Use the given debugger\n"
|
|
|
|
" -1 Show information about most recent entry only\n"
|
|
|
|
" -S --since=DATE Only print coredumps since the date\n"
|
|
|
|
" -U --until=DATE Only print coredumps until the date\n"
|
|
|
|
" -r --reverse Show the newest entries first\n"
|
|
|
|
" -F --field=FIELD List all values a certain field takes\n"
|
|
|
|
" -o --output=FILE Write output to FILE\n"
|
|
|
|
" -D --directory=DIR Use journal files from directory\n\n"
|
|
|
|
" -q --quiet Do not show info messages and privilege warning\n"
|
2014-08-02 17:12:21 +02:00
|
|
|
"Commands:\n"
|
|
|
|
" list [MATCHES...] List available coredumps (default)\n"
|
|
|
|
" info [MATCHES...] Show detailed information about one or more coredumps\n"
|
|
|
|
" dump [MATCHES...] Print first matching coredump to stdout\n"
|
2018-04-18 21:32:17 +02:00
|
|
|
" debug [MATCHES...] Start a debugger for the first matching coredump\n"
|
2018-08-09 10:32:31 +02:00
|
|
|
"\nSee the %s for details.\n"
|
|
|
|
, program_invocation_short_name
|
|
|
|
, link
|
|
|
|
);
|
2018-03-14 09:46:34 +01:00
|
|
|
|
|
|
|
return 0;
|
2014-08-02 17:12:21 +02:00
|
|
|
}
|
|
|
|
|
2016-11-06 17:29:31 +01:00
|
|
|
static int parse_argv(int argc, char *argv[]) {
|
2012-10-19 12:29:46 +02:00
|
|
|
enum {
|
|
|
|
ARG_VERSION = 0x100,
|
|
|
|
ARG_NO_PAGER,
|
2012-10-30 09:45:19 +01:00
|
|
|
ARG_NO_LEGEND,
|
2018-04-18 21:32:17 +02:00
|
|
|
ARG_DEBUGGER,
|
2012-10-19 12:29:46 +02:00
|
|
|
};
|
|
|
|
|
2017-02-24 20:29:40 +01:00
|
|
|
int c, r;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
static const struct option options[] = {
|
2012-10-30 09:35:53 +01:00
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "version" , no_argument, NULL, ARG_VERSION },
|
|
|
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
2012-10-30 09:45:19 +01:00
|
|
|
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
2018-04-18 21:32:17 +02:00
|
|
|
{ "debugger", required_argument, NULL, ARG_DEBUGGER },
|
2012-10-30 09:35:53 +01:00
|
|
|
{ "output", required_argument, NULL, 'o' },
|
2012-10-30 11:15:24 +01:00
|
|
|
{ "field", required_argument, NULL, 'F' },
|
2015-08-25 10:36:49 +02:00
|
|
|
{ "directory", required_argument, NULL, 'D' },
|
2017-02-13 14:55:25 +01:00
|
|
|
{ "reverse", no_argument, NULL, 'r' },
|
2017-02-24 20:29:40 +01:00
|
|
|
{ "since", required_argument, NULL, 'S' },
|
|
|
|
{ "until", required_argument, NULL, 'U' },
|
2017-02-27 00:07:39 +01:00
|
|
|
{ "quiet", no_argument, NULL, 'q' },
|
2013-11-06 18:28:39 +01:00
|
|
|
{}
|
2012-10-19 12:29:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
assert(argv);
|
|
|
|
|
2017-02-27 00:07:39 +01:00
|
|
|
while ((c = getopt_long(argc, argv, "ho:F:1D:rS:U:q", options, NULL)) >= 0)
|
2012-10-19 12:29:46 +02:00
|
|
|
switch(c) {
|
|
|
|
case 'h':
|
2018-03-14 09:46:34 +01:00
|
|
|
return help();
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
case ARG_VERSION:
|
2015-09-23 03:01:06 +02:00
|
|
|
return version();
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
case ARG_NO_PAGER:
|
2018-11-11 12:56:29 +01:00
|
|
|
arg_pager_flags |= PAGER_DISABLE;
|
2012-10-19 12:29:46 +02:00
|
|
|
break;
|
|
|
|
|
2012-10-30 09:45:19 +01:00
|
|
|
case ARG_NO_LEGEND:
|
|
|
|
arg_no_legend = true;
|
|
|
|
break;
|
|
|
|
|
2018-04-18 21:32:17 +02:00
|
|
|
case ARG_DEBUGGER:
|
|
|
|
arg_debugger = optarg;
|
|
|
|
break;
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
case 'o':
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_output)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Cannot set output more than once.");
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2018-11-20 09:27:19 +01:00
|
|
|
arg_output = optarg;
|
2012-10-19 12:29:46 +02:00
|
|
|
break;
|
2012-10-30 09:35:53 +01:00
|
|
|
|
2017-02-24 20:29:40 +01:00
|
|
|
case 'S':
|
|
|
|
r = parse_timestamp(optarg, &arg_since);
|
|
|
|
if (r < 0)
|
2018-10-19 18:43:13 +02:00
|
|
|
return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg);
|
2017-02-24 20:29:40 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'U':
|
|
|
|
r = parse_timestamp(optarg, &arg_until);
|
|
|
|
if (r < 0)
|
2018-10-19 18:43:13 +02:00
|
|
|
return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg);
|
2017-02-24 20:29:40 +01:00
|
|
|
break;
|
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
case 'F':
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_field)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Cannot use --field/-F more than once.");
|
2014-06-18 23:05:15 +02:00
|
|
|
arg_field = optarg;
|
2012-10-30 11:15:24 +01:00
|
|
|
break;
|
|
|
|
|
2014-06-19 12:24:00 +02:00
|
|
|
case '1':
|
|
|
|
arg_one = true;
|
|
|
|
break;
|
|
|
|
|
2015-08-25 10:36:49 +02:00
|
|
|
case 'D':
|
|
|
|
arg_directory = optarg;
|
|
|
|
break;
|
|
|
|
|
2017-02-13 14:55:25 +01:00
|
|
|
case 'r':
|
|
|
|
arg_reverse = true;
|
|
|
|
break;
|
|
|
|
|
2017-02-27 00:07:39 +01:00
|
|
|
case 'q':
|
|
|
|
arg_quiet = true;
|
|
|
|
break;
|
|
|
|
|
2012-10-30 09:35:53 +01:00
|
|
|
case '?':
|
|
|
|
return -EINVAL;
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
default:
|
2013-11-06 18:28:39 +01:00
|
|
|
assert_not_reached("Unhandled option");
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|
|
|
|
|
2017-02-24 20:29:40 +01:00
|
|
|
if (arg_since != USEC_INFINITY && arg_until != USEC_INFINITY &&
|
2018-11-20 23:40:44 +01:00
|
|
|
arg_since > arg_until)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"--since= must be before --until=.");
|
2017-02-24 20:29:40 +01:00
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
return 1;
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|
|
|
|
|
2012-10-26 20:25:10 +02:00
|
|
|
static int retrieve(const void *data,
|
|
|
|
size_t len,
|
|
|
|
const char *name,
|
2014-06-18 23:05:15 +02:00
|
|
|
char **var) {
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
size_t ident;
|
2014-06-18 23:05:15 +02:00
|
|
|
char *v;
|
2012-10-26 20:25:10 +02:00
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
ident = strlen(name) + 1; /* name + "=" */
|
2012-10-26 20:25:10 +02:00
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
if (len < ident)
|
2012-10-26 20:25:10 +02:00
|
|
|
return 0;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
if (memcmp(data, name, ident - 1) != 0)
|
2012-10-26 20:25:10 +02:00
|
|
|
return 0;
|
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
if (((const char*) data)[ident - 1] != '=')
|
2012-10-26 20:25:10 +02:00
|
|
|
return 0;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2014-06-18 23:05:15 +02:00
|
|
|
v = strndup((const char*)data + ident, len - ident);
|
|
|
|
if (!v)
|
2012-10-19 12:29:46 +02:00
|
|
|
return log_oom();
|
|
|
|
|
2014-06-18 23:05:15 +02:00
|
|
|
free(*var);
|
|
|
|
*var = v;
|
|
|
|
|
2016-09-27 10:52:10 +02:00
|
|
|
return 1;
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|
|
|
|
|
2016-09-27 10:52:10 +02:00
|
|
|
static int print_field(FILE* file, sd_journal *j) {
|
2012-10-30 11:15:24 +01:00
|
|
|
const void *d;
|
|
|
|
size_t l;
|
|
|
|
|
2014-06-18 23:34:59 +02:00
|
|
|
assert(file);
|
|
|
|
assert(j);
|
|
|
|
|
2014-06-18 23:05:15 +02:00
|
|
|
assert(arg_field);
|
2012-10-30 11:15:24 +01:00
|
|
|
|
2016-09-27 10:52:10 +02:00
|
|
|
/* A (user-specified) field may appear more than once for a given entry.
|
|
|
|
* We will print all of the occurences.
|
|
|
|
* This is different below for fields that systemd-coredump uses,
|
|
|
|
* because they cannot meaningfully appear more than once.
|
|
|
|
*/
|
|
|
|
SD_JOURNAL_FOREACH_DATA(j, d, l) {
|
|
|
|
_cleanup_free_ char *value = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = retrieve(d, l, arg_field, &value);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0)
|
|
|
|
fprintf(file, "%s\n", value);
|
|
|
|
}
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2016-09-27 10:52:10 +02:00
|
|
|
return 0;
|
2012-10-30 11:15:24 +01:00
|
|
|
}
|
|
|
|
|
2016-09-27 10:52:10 +02:00
|
|
|
#define RETRIEVE(d, l, name, arg) \
|
|
|
|
{ \
|
|
|
|
int _r = retrieve(d, l, name, &arg); \
|
|
|
|
if (_r < 0) \
|
|
|
|
return _r; \
|
|
|
|
if (_r > 0) \
|
|
|
|
continue; \
|
|
|
|
}
|
|
|
|
|
2014-06-18 23:34:59 +02:00
|
|
|
static int print_list(FILE* file, sd_journal *j, int had_legend) {
|
2014-06-18 23:05:15 +02:00
|
|
|
_cleanup_free_ char
|
2016-11-06 19:34:31 +01:00
|
|
|
*mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
|
2014-06-26 05:38:49 +02:00
|
|
|
*sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
|
2017-02-25 23:29:14 +01:00
|
|
|
*filename = NULL, *truncated = NULL, *coredump = NULL;
|
2012-10-26 20:25:10 +02:00
|
|
|
const void *d;
|
|
|
|
size_t l;
|
2012-10-26 20:34:39 +02:00
|
|
|
usec_t t;
|
|
|
|
char buf[FORMAT_TIMESTAMP_MAX];
|
|
|
|
int r;
|
2016-09-27 01:41:38 +02:00
|
|
|
const char *present;
|
2016-11-06 19:34:31 +01:00
|
|
|
bool normal_coredump;
|
2012-10-26 20:25:10 +02:00
|
|
|
|
2014-06-18 23:34:59 +02:00
|
|
|
assert(file);
|
|
|
|
assert(j);
|
|
|
|
|
2012-10-26 20:25:10 +02:00
|
|
|
SD_JOURNAL_FOREACH_DATA(j, d, l) {
|
2016-11-06 19:34:31 +01:00
|
|
|
RETRIEVE(d, l, "MESSAGE_ID", mid);
|
2016-09-27 10:52:10 +02:00
|
|
|
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_FILENAME", filename);
|
2017-02-25 23:29:14 +01:00
|
|
|
RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
|
2016-09-27 10:52:10 +02:00
|
|
|
RETRIEVE(d, l, "COREDUMP", coredump);
|
2012-10-26 20:25:10 +02:00
|
|
|
}
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) {
|
2012-10-26 20:34:39 +02:00
|
|
|
log_warning("Empty coredump log entry");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_journal_get_realtime_usec(j, &t);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get realtime timestamp: %m");
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2012-10-26 20:34:39 +02:00
|
|
|
format_timestamp(buf, sizeof(buf), t);
|
|
|
|
|
2012-10-30 09:45:19 +01:00
|
|
|
if (!had_legend && !arg_no_legend)
|
2017-02-25 23:29:14 +01:00
|
|
|
fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n",
|
2014-06-19 17:29:39 +02:00
|
|
|
FORMAT_TIMESTAMP_WIDTH, "TIME",
|
2012-10-19 12:29:46 +02:00
|
|
|
6, "PID",
|
|
|
|
5, "UID",
|
|
|
|
5, "GID",
|
2012-10-26 20:34:39 +02:00
|
|
|
3, "SIG",
|
2017-02-25 23:29:14 +01:00
|
|
|
9, "COREFILE",
|
2012-10-26 20:34:39 +02:00
|
|
|
"EXE");
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2016-11-06 19:34:31 +01:00
|
|
|
normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
|
|
|
|
|
2016-09-27 01:41:38 +02:00
|
|
|
if (filename)
|
|
|
|
if (access(filename, R_OK) == 0)
|
|
|
|
present = "present";
|
|
|
|
else if (errno == ENOENT)
|
|
|
|
present = "missing";
|
|
|
|
else
|
|
|
|
present = "error";
|
|
|
|
else if (coredump)
|
|
|
|
present = "journal";
|
2016-11-06 19:34:31 +01:00
|
|
|
else if (normal_coredump)
|
2016-09-27 01:41:38 +02:00
|
|
|
present = "none";
|
2016-11-06 19:34:31 +01:00
|
|
|
else
|
|
|
|
present = "-";
|
2016-09-27 01:41:38 +02:00
|
|
|
|
2017-03-01 15:46:54 +01:00
|
|
|
if (STR_IN_SET(present, "present", "journal") && truncated && parse_boolean(truncated) > 0)
|
2017-02-25 23:29:14 +01:00
|
|
|
present = "truncated";
|
|
|
|
|
2016-09-27 01:41:38 +02:00
|
|
|
fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n",
|
2014-06-19 17:29:39 +02:00
|
|
|
FORMAT_TIMESTAMP_WIDTH, buf,
|
2014-06-18 23:05:15 +02:00
|
|
|
6, strna(pid),
|
|
|
|
5, strna(uid),
|
|
|
|
5, strna(gid),
|
2016-11-06 19:34:31 +01:00
|
|
|
3, normal_coredump ? strna(sgnl) : "-",
|
2017-02-25 23:29:14 +01:00
|
|
|
9, present,
|
2014-06-18 23:05:15 +02:00
|
|
|
strna(exe ?: (comm ?: cmdline)));
|
2012-10-26 20:34:39 +02:00
|
|
|
|
|
|
|
return 0;
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|
|
|
|
|
2014-06-18 23:34:59 +02:00
|
|
|
static int print_info(FILE *file, sd_journal *j, bool need_space) {
|
|
|
|
_cleanup_free_ char
|
2016-11-06 19:34:31 +01:00
|
|
|
*mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
|
2014-06-18 23:34:59 +02:00
|
|
|
*sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
|
|
|
|
*unit = NULL, *user_unit = NULL, *session = NULL,
|
2014-06-18 23:55:36 +02:00
|
|
|
*boot_id = NULL, *machine_id = NULL, *hostname = NULL,
|
2014-06-26 05:38:49 +02:00
|
|
|
*slice = NULL, *cgroup = NULL, *owner_uid = NULL,
|
2016-09-27 01:19:01 +02:00
|
|
|
*message = NULL, *timestamp = NULL, *filename = NULL,
|
2017-02-25 23:29:14 +01:00
|
|
|
*truncated = NULL, *coredump = NULL;
|
2014-06-18 23:34:59 +02:00
|
|
|
const void *d;
|
|
|
|
size_t l;
|
2016-11-06 19:34:31 +01:00
|
|
|
bool normal_coredump;
|
2014-06-23 15:51:09 +02:00
|
|
|
int r;
|
2014-06-18 23:34:59 +02:00
|
|
|
|
|
|
|
assert(file);
|
|
|
|
assert(j);
|
|
|
|
|
|
|
|
SD_JOURNAL_FOREACH_DATA(j, d, l) {
|
2016-11-06 19:34:31 +01:00
|
|
|
RETRIEVE(d, l, "MESSAGE_ID", mid);
|
2016-09-27 10:52:10 +02:00
|
|
|
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, "COREDUMP_TIMESTAMP", timestamp);
|
|
|
|
RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
|
2017-02-25 23:29:14 +01:00
|
|
|
RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
|
2016-09-27 10:52:10 +02:00
|
|
|
RETRIEVE(d, l, "COREDUMP", coredump);
|
|
|
|
RETRIEVE(d, l, "_BOOT_ID", boot_id);
|
|
|
|
RETRIEVE(d, l, "_MACHINE_ID", machine_id);
|
|
|
|
RETRIEVE(d, l, "_HOSTNAME", hostname);
|
|
|
|
RETRIEVE(d, l, "MESSAGE", message);
|
2014-06-18 23:34:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (need_space)
|
|
|
|
fputs("\n", file);
|
|
|
|
|
2016-11-06 19:34:31 +01:00
|
|
|
normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
|
|
|
|
|
2014-06-23 15:55:24 +02:00
|
|
|
if (comm)
|
|
|
|
fprintf(file,
|
|
|
|
" PID: %s%s%s (%s)\n",
|
2015-09-19 00:45:05 +02:00
|
|
|
ansi_highlight(), strna(pid), ansi_normal(), comm);
|
2014-06-23 15:55:24 +02:00
|
|
|
else
|
|
|
|
fprintf(file,
|
|
|
|
" PID: %s%s%s\n",
|
2015-09-19 00:45:05 +02:00
|
|
|
ansi_highlight(), strna(pid), ansi_normal());
|
2014-06-18 23:55:36 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2014-06-18 23:34:59 +02:00
|
|
|
|
|
|
|
if (sgnl) {
|
|
|
|
int sig;
|
2016-11-06 19:34:31 +01:00
|
|
|
const char *name = normal_coredump ? "Signal" : "Reason";
|
2014-06-18 23:34:59 +02:00
|
|
|
|
2016-11-06 19:34:31 +01:00
|
|
|
if (normal_coredump && safe_atoi(sgnl, &sig) >= 0)
|
|
|
|
fprintf(file, " %s: %s (%s)\n", name, sgnl, signal_to_string(sig));
|
2014-06-18 23:34:59 +02:00
|
|
|
else
|
2016-11-06 19:34:31 +01:00
|
|
|
fprintf(file, " %s: %s\n", name, sgnl);
|
2014-06-18 23:34:59 +02:00
|
|
|
}
|
|
|
|
|
2014-06-23 15:51:09 +02:00
|
|
|
if (timestamp) {
|
|
|
|
usec_t u;
|
|
|
|
|
|
|
|
r = safe_atou64(timestamp, &u);
|
|
|
|
if (r >= 0) {
|
|
|
|
char absolute[FORMAT_TIMESTAMP_MAX], relative[FORMAT_TIMESPAN_MAX];
|
|
|
|
|
|
|
|
fprintf(file,
|
|
|
|
" Timestamp: %s (%s)\n",
|
|
|
|
format_timestamp(absolute, sizeof(absolute), u),
|
|
|
|
format_timestamp_relative(relative, sizeof(relative), u));
|
|
|
|
|
|
|
|
} else
|
|
|
|
fprintf(file, " Timestamp: %s\n", timestamp);
|
|
|
|
}
|
|
|
|
|
2014-06-18 23:34:59 +02:00
|
|
|
if (cmdline)
|
|
|
|
fprintf(file, " Command Line: %s\n", cmdline);
|
2014-06-23 15:55:24 +02:00
|
|
|
if (exe)
|
2015-09-19 00:45:05 +02:00
|
|
|
fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_normal());
|
2014-06-18 23:55:36 +02:00
|
|
|
if (cgroup)
|
|
|
|
fprintf(file, " Control Group: %s\n", cgroup);
|
2014-06-18 23:34:59 +02:00
|
|
|
if (unit)
|
|
|
|
fprintf(file, " Unit: %s\n", unit);
|
|
|
|
if (user_unit)
|
2016-09-27 01:18:48 +02:00
|
|
|
fprintf(file, " User Unit: %s\n", user_unit);
|
2014-06-18 23:55:36 +02:00
|
|
|
if (slice)
|
|
|
|
fprintf(file, " Slice: %s\n", slice);
|
2014-06-18 23:34:59 +02:00
|
|
|
if (session)
|
|
|
|
fprintf(file, " Session: %s\n", session);
|
2014-06-18 23:55:36 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2014-06-18 23:34:59 +02:00
|
|
|
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);
|
|
|
|
|
2017-02-25 23:29:14 +01:00
|
|
|
if (filename) {
|
2017-03-01 15:46:54 +01:00
|
|
|
bool inacc, trunc;
|
|
|
|
|
|
|
|
inacc = access(filename, R_OK) < 0;
|
|
|
|
trunc = truncated && parse_boolean(truncated) > 0;
|
2017-02-25 23:29:14 +01:00
|
|
|
|
|
|
|
if (inacc || trunc)
|
|
|
|
fprintf(file, " Storage: %s%s (%s%s%s)%s\n",
|
|
|
|
ansi_highlight_red(),
|
|
|
|
filename,
|
|
|
|
inacc ? "inaccessible" : "",
|
|
|
|
inacc && trunc ? ", " : "",
|
|
|
|
trunc ? "truncated" : "",
|
|
|
|
ansi_normal());
|
|
|
|
else
|
|
|
|
fprintf(file, " Storage: %s\n", filename);
|
|
|
|
}
|
|
|
|
|
2016-09-27 01:19:01 +02:00
|
|
|
else if (coredump)
|
|
|
|
fprintf(file, " Storage: journal\n");
|
|
|
|
else
|
|
|
|
fprintf(file, " Storage: none\n");
|
2014-06-18 23:34:59 +02:00
|
|
|
|
2014-06-19 12:07:12 +02:00
|
|
|
if (message) {
|
|
|
|
_cleanup_free_ char *m = NULL;
|
|
|
|
|
|
|
|
m = strreplace(message, "\n", "\n ");
|
|
|
|
|
|
|
|
fprintf(file, " Message: %s\n", strstrip(m ?: message));
|
|
|
|
}
|
|
|
|
|
2014-06-18 23:34:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-27 01:19:47 +02:00
|
|
|
static int focus(sd_journal *j) {
|
2012-10-19 12:29:46 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sd_journal_seek_tail(j);
|
|
|
|
if (r == 0)
|
|
|
|
r = sd_journal_previous(j);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to search journal: %m");
|
2018-11-20 23:40:44 +01:00
|
|
|
if (r == 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
|
|
|
|
"No match found.");
|
2012-10-27 01:19:47 +02:00
|
|
|
return r;
|
|
|
|
}
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
static int print_entry(sd_journal *j, unsigned n_found, bool verb_is_info) {
|
2014-06-19 12:24:00 +02:00
|
|
|
assert(j);
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
if (verb_is_info)
|
2016-09-27 10:52:10 +02:00
|
|
|
return print_info(stdout, j, n_found);
|
2014-06-19 12:24:00 +02:00
|
|
|
else if (arg_field)
|
2016-09-27 10:52:10 +02:00
|
|
|
return print_field(stdout, j);
|
2014-06-19 12:24:00 +02:00
|
|
|
else
|
2016-09-27 10:52:10 +02:00
|
|
|
return print_list(stdout, j, n_found);
|
2014-06-19 12:24:00 +02:00
|
|
|
}
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
static int dump_list(int argc, char **argv, void *userdata) {
|
|
|
|
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
2014-06-19 12:24:00 +02:00
|
|
|
unsigned n_found = 0;
|
2018-03-14 09:46:34 +01:00
|
|
|
bool verb_is_info;
|
2014-06-19 12:24:00 +02:00
|
|
|
int r;
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
verb_is_info = (argc >= 1 && streq(argv[0], "info"));
|
|
|
|
|
|
|
|
r = acquire_journal(&j, argv + 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
2014-06-19 12:24:00 +02:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2018-07-08 00:00:39 +02:00
|
|
|
/* "info" without pattern implies "-1" */
|
|
|
|
if (arg_one || (verb_is_info && argc == 1)) {
|
2014-06-19 12:24:00 +02:00
|
|
|
r = focus(j);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
return print_entry(j, 0, verb_is_info);
|
2014-06-19 12:24:00 +02:00
|
|
|
} else {
|
2017-02-24 20:29:40 +01:00
|
|
|
if (arg_since != USEC_INFINITY && !arg_reverse)
|
|
|
|
r = sd_journal_seek_realtime_usec(j, arg_since);
|
|
|
|
else if (arg_until != USEC_INFINITY && arg_reverse)
|
|
|
|
r = sd_journal_seek_realtime_usec(j, arg_until);
|
|
|
|
else if (arg_reverse)
|
|
|
|
r = sd_journal_seek_tail(j);
|
|
|
|
else
|
|
|
|
r = sd_journal_seek_head(j);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to seek to date: %m");
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (!arg_reverse)
|
|
|
|
r = sd_journal_next(j);
|
|
|
|
else
|
|
|
|
r = sd_journal_previous(j);
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to iterate through journal: %m");
|
|
|
|
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (arg_until != USEC_INFINITY && !arg_reverse) {
|
|
|
|
usec_t usec;
|
|
|
|
|
|
|
|
r = sd_journal_get_realtime_usec(j, &usec);
|
2017-02-13 14:55:25 +01:00
|
|
|
if (r < 0)
|
2017-02-24 20:29:40 +01:00
|
|
|
return log_error_errno(r, "Failed to determine timestamp: %m");
|
|
|
|
if (usec > arg_until)
|
|
|
|
continue;
|
2017-02-13 14:55:25 +01:00
|
|
|
}
|
2017-02-24 20:29:40 +01:00
|
|
|
|
|
|
|
if (arg_since != USEC_INFINITY && arg_reverse) {
|
|
|
|
usec_t usec;
|
|
|
|
|
|
|
|
r = sd_journal_get_realtime_usec(j, &usec);
|
2017-02-13 14:55:25 +01:00
|
|
|
if (r < 0)
|
2017-02-24 20:29:40 +01:00
|
|
|
return log_error_errno(r, "Failed to determine timestamp: %m");
|
|
|
|
if (usec < arg_since)
|
|
|
|
continue;
|
2017-02-13 14:55:25 +01:00
|
|
|
}
|
2017-02-24 20:29:40 +01:00
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
r = print_entry(j, n_found++, verb_is_info);
|
2017-02-24 20:29:40 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-09-27 10:52:10 +02:00
|
|
|
}
|
2014-06-19 12:24:00 +02:00
|
|
|
|
|
|
|
if (!arg_field && n_found <= 0) {
|
2017-02-27 00:07:39 +01:00
|
|
|
if (!arg_quiet)
|
|
|
|
log_notice("No coredumps found.");
|
2014-06-19 12:24:00 +02:00
|
|
|
return -ESRCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-27 00:32:42 +02:00
|
|
|
static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp) {
|
2014-06-26 05:38:49 +02:00
|
|
|
const char *data;
|
|
|
|
_cleanup_free_ char *filename = NULL;
|
|
|
|
size_t len;
|
2016-09-27 00:32:42 +02:00
|
|
|
int r, fd;
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
_cleanup_close_ int fdt = -1;
|
|
|
|
char *temp = NULL;
|
2012-10-27 01:19:47 +02:00
|
|
|
|
2016-09-27 00:32:42 +02:00
|
|
|
assert(!(file && path)); /* At most one can be specified */
|
|
|
|
assert(!!path == !!unlink_temp); /* Those must be specified together */
|
2016-09-27 01:19:01 +02:00
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
/* Look for a coredump on disk first. */
|
2014-06-26 05:38:49 +02:00
|
|
|
r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
|
2016-09-27 00:32:42 +02:00
|
|
|
if (r == 0)
|
2014-06-26 05:38:49 +02:00
|
|
|
retrieve(data, len, "COREDUMP_FILENAME", &filename);
|
2016-09-27 00:32:42 +02:00
|
|
|
else {
|
|
|
|
if (r != -ENOENT)
|
|
|
|
return log_error_errno(r, "Failed to retrieve COREDUMP_FILENAME field: %m");
|
|
|
|
/* Check that we can have a COREDUMP field. We still haven't set a high
|
|
|
|
* data threshold, so we'll get a few kilobytes at most.
|
|
|
|
*/
|
|
|
|
|
|
|
|
r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
return log_error_errno(r, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).");
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
|
|
|
|
}
|
2012-11-21 00:28:00 +01:00
|
|
|
|
2016-09-27 00:10:04 +02:00
|
|
|
if (filename) {
|
|
|
|
if (access(filename, R_OK) < 0)
|
|
|
|
return log_error_errno(errno, "File \"%s\" is not readable: %m", filename);
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2016-09-27 00:10:04 +02:00
|
|
|
if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) {
|
2018-03-22 16:53:26 +01:00
|
|
|
*path = TAKE_PTR(filename);
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2016-09-27 00:10:04 +02:00
|
|
|
return 0;
|
|
|
|
}
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
}
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2016-09-27 00:32:42 +02:00
|
|
|
if (path) {
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
const char *vt;
|
2016-07-26 17:23:28 +02:00
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
/* Create a temporary file to write the uncompressed core to. */
|
2016-07-26 17:23:28 +02:00
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
r = var_tmp_dir(&vt);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to acquire temporary directory path: %m");
|
2014-06-26 05:38:49 +02:00
|
|
|
|
2016-10-23 17:43:27 +02:00
|
|
|
temp = strjoin(vt, "/coredump-XXXXXX");
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
if (!temp)
|
|
|
|
return log_oom();
|
2014-06-26 05:38:49 +02:00
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
fdt = mkostemp_safe(temp);
|
|
|
|
if (fdt < 0)
|
|
|
|
return log_error_errno(fdt, "Failed to create temporary file: %m");
|
|
|
|
log_debug("Created temporary file %s", temp);
|
2014-06-26 05:38:49 +02:00
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
fd = fdt;
|
2016-09-27 00:32:42 +02:00
|
|
|
} else {
|
|
|
|
/* If neither path or file are specified, we will write to stdout. Let's now check
|
|
|
|
* if stdout is connected to a tty. We checked that the file exists, or that the
|
|
|
|
* core might be stored in the journal. In this second case, if we found the entry,
|
|
|
|
* in all likelyhood we will be able to access the COREDUMP= field. In either case,
|
|
|
|
* we stop before doing any "real" work, i.e. before starting decompression or
|
|
|
|
* reading from the file or creating temporary files.
|
|
|
|
*/
|
|
|
|
if (!file) {
|
|
|
|
if (on_tty())
|
2018-11-21 08:23:20 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
|
|
|
|
"Refusing to dump core to tty"
|
2016-09-27 00:32:42 +02:00
|
|
|
" (use shell redirection or specify --output).");
|
|
|
|
file = stdout;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = fileno(file);
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (filename) {
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_XZ || HAVE_LZ4
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
_cleanup_close_ int fdf;
|
2014-06-26 05:38:49 +02:00
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
fdf = open(filename, O_RDONLY | O_CLOEXEC);
|
|
|
|
if (fdf < 0) {
|
|
|
|
r = log_error_errno(errno, "Failed to open %s: %m", filename);
|
2014-06-26 10:31:23 +02:00
|
|
|
goto error;
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = decompress_stream(filename, fdf, fd, -1);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to decompress %s: %m", filename);
|
2014-06-26 05:38:49 +02:00
|
|
|
goto error;
|
|
|
|
}
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
#else
|
|
|
|
log_error("Cannot decompress file. Compiled without compression support.");
|
|
|
|
r = -EOPNOTSUPP;
|
|
|
|
goto error;
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
ssize_t sz;
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2016-09-27 00:32:42 +02:00
|
|
|
/* We want full data, nothing truncated. */
|
|
|
|
sd_journal_set_data_threshold(j, 0);
|
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
|
|
|
|
if (r < 0)
|
2016-09-27 00:32:42 +02:00
|
|
|
return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
|
|
|
|
assert(len >= 9);
|
|
|
|
data += 9;
|
|
|
|
len -= 9;
|
|
|
|
|
2016-09-27 00:10:04 +02:00
|
|
|
sz = write(fd, data, len);
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
if (sz < 0) {
|
2016-09-27 00:10:04 +02:00
|
|
|
r = log_error_errno(errno, "Failed to write output: %m");
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
goto error;
|
2014-06-18 23:05:15 +02:00
|
|
|
}
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
if (sz != (ssize_t) len) {
|
2016-09-27 00:10:04 +02:00
|
|
|
log_error("Short write to output.");
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
r = -EIO;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2014-06-18 23:05:15 +02:00
|
|
|
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
if (temp) {
|
|
|
|
*path = temp;
|
|
|
|
*unlink_temp = true;
|
|
|
|
}
|
|
|
|
return 0;
|
2014-06-26 05:38:49 +02:00
|
|
|
|
|
|
|
error:
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
if (temp) {
|
2019-03-27 14:36:36 +01:00
|
|
|
(void) unlink(temp);
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
log_debug("Removed temporary file %s", temp);
|
2014-06-26 05:38:49 +02:00
|
|
|
}
|
coredump: remove Storage=both option
Back when external storage was initially added in 34c10968cb, this mode of
storage was added. This could have made some sense back when XZ compression was
used, and an uncompressed core on disk could be used as short-lived cache file
which does require costly decompression. But now fast LZ4 compression is used
(by default) both internally and externally, so we have duplicated storage,
using the same compression and same default maximum core size in both cases,
but with different expiration lifetimes. Even the uncompressed-external,
compressed-internal mode is not very useful: for small files, decompression
with LZ4 is fast enough not to matter, and for large files, decompression is
still relatively fast, but the disk-usage penalty is very big.
An additional problem with the two modes of storage is that it complicates
the code and makes it much harder to return a useful error message to the user
if we cannot find the core file, since if we cannot find the file we have to
check the internal storage first.
This patch drops "both" storage mode. Effectively this means that if somebody
configured coredump this way, they will get a warning about an unsupported
value for Storage, and the default of "external" will be used.
I'm pretty sure that this mode is very rarely used anyway.
2016-09-26 23:40:20 +02:00
|
|
|
return r;
|
2014-06-26 05:38:49 +02:00
|
|
|
}
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
static int dump_core(int argc, char **argv, void *userdata) {
|
|
|
|
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
2018-11-20 09:27:19 +01:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
2014-06-26 05:38:49 +02:00
|
|
|
int r;
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
if (arg_field) {
|
|
|
|
log_error("Option --field/-F only makes sense with list");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = acquire_journal(&j, argv + 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-06-26 05:38:49 +02:00
|
|
|
|
|
|
|
r = focus(j);
|
|
|
|
if (r < 0)
|
2012-10-27 01:19:47 +02:00
|
|
|
return r;
|
|
|
|
|
2018-11-20 09:27:19 +01:00
|
|
|
if (arg_output) {
|
|
|
|
f = fopen(arg_output, "we");
|
|
|
|
if (!f)
|
|
|
|
return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", arg_output);
|
|
|
|
}
|
|
|
|
|
|
|
|
print_info(f ? stdout : stderr, j, false);
|
2014-06-26 05:38:49 +02:00
|
|
|
|
2018-11-20 09:27:19 +01:00
|
|
|
r = save_core(j, f, NULL, NULL);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
2016-09-27 00:32:42 +02:00
|
|
|
return r;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
r = sd_journal_previous(j);
|
2017-02-27 00:07:39 +01:00
|
|
|
if (r > 0 && !arg_quiet)
|
|
|
|
log_notice("More than one entry matches, ignoring rest.");
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-18 21:32:17 +02:00
|
|
|
static int run_debug(int argc, char **argv, void *userdata) {
|
2018-03-14 09:46:34 +01:00
|
|
|
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
2014-06-26 23:16:24 +02:00
|
|
|
_cleanup_free_ char *exe = NULL, *path = NULL;
|
2014-06-26 05:38:49 +02:00
|
|
|
bool unlink_path = false;
|
2018-04-18 21:32:17 +02:00
|
|
|
const char *data, *fork_name;
|
2012-10-27 01:19:47 +02:00
|
|
|
size_t len;
|
|
|
|
pid_t pid;
|
|
|
|
int r;
|
|
|
|
|
2018-04-18 21:32:17 +02:00
|
|
|
if (!arg_debugger) {
|
|
|
|
char *env_debugger;
|
|
|
|
|
|
|
|
env_debugger = getenv("SYSTEMD_DEBUGGER");
|
|
|
|
if (env_debugger)
|
|
|
|
arg_debugger = env_debugger;
|
|
|
|
else
|
|
|
|
arg_debugger = "gdb";
|
|
|
|
}
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
if (arg_field) {
|
|
|
|
log_error("Option --field/-F only makes sense with list");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = acquire_journal(&j, argv + 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2012-10-27 01:19:47 +02:00
|
|
|
|
|
|
|
r = focus(j);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2014-06-18 23:34:59 +02:00
|
|
|
print_info(stdout, j, false);
|
|
|
|
fputs("\n", stdout);
|
2012-10-27 01:19:47 +02:00
|
|
|
|
|
|
|
r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to retrieve COREDUMP_EXE field: %m");
|
2012-10-27 01:19:47 +02:00
|
|
|
|
2017-12-14 19:02:29 +01:00
|
|
|
assert(len > STRLEN("COREDUMP_EXE="));
|
|
|
|
data += STRLEN("COREDUMP_EXE=");
|
|
|
|
len -= STRLEN("COREDUMP_EXE=");
|
2012-10-27 01:19:47 +02:00
|
|
|
|
|
|
|
exe = strndup(data, len);
|
|
|
|
if (!exe)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
if (endswith(exe, " (deleted)")) {
|
|
|
|
log_error("Binary already deleted.");
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2014-06-18 23:05:15 +02:00
|
|
|
if (!path_is_absolute(exe)) {
|
|
|
|
log_error("Binary is not an absolute path.");
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2016-09-27 00:32:42 +02:00
|
|
|
r = save_core(j, NULL, &path, &unlink_path);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
2016-09-27 00:32:42 +02:00
|
|
|
return r;
|
2012-10-27 01:19:47 +02:00
|
|
|
|
2016-12-17 15:49:17 +01:00
|
|
|
/* Don't interfere with gdb and its handling of SIGINT. */
|
|
|
|
(void) ignore_signals(SIGINT, -1);
|
|
|
|
|
2018-04-18 21:32:17 +02:00
|
|
|
fork_name = strjoina("(", arg_debugger, ")");
|
|
|
|
|
2018-11-26 16:11:45 +01:00
|
|
|
r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
|
2017-12-27 21:49:19 +01:00
|
|
|
if (r < 0)
|
2012-10-27 01:19:47 +02:00
|
|
|
goto finish;
|
2017-12-22 13:08:14 +01:00
|
|
|
if (r == 0) {
|
2018-04-18 21:32:17 +02:00
|
|
|
execlp(arg_debugger, arg_debugger, exe, "-c", path, NULL);
|
2018-02-22 00:35:00 +01:00
|
|
|
log_open();
|
2018-04-18 21:32:17 +02:00
|
|
|
log_error_errno(errno, "Failed to invoke %s: %m", arg_debugger);
|
2017-12-22 13:24:40 +01:00
|
|
|
_exit(EXIT_FAILURE);
|
2012-10-27 01:19:47 +02:00
|
|
|
}
|
|
|
|
|
2018-04-18 21:32:17 +02:00
|
|
|
r = wait_for_terminate_and_check(arg_debugger, pid, WAIT_LOG_ABNORMAL);
|
2012-10-27 01:19:47 +02:00
|
|
|
|
|
|
|
finish:
|
2016-12-17 15:49:17 +01:00
|
|
|
(void) default_signals(SIGINT, -1);
|
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
if (unlink_path) {
|
|
|
|
log_debug("Removed temporary file %s", path);
|
2019-03-27 14:36:36 +01:00
|
|
|
(void) unlink(path);
|
2014-06-26 05:38:49 +02:00
|
|
|
}
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2012-10-27 01:19:47 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-02-21 11:08:35 +01:00
|
|
|
static int check_units_active(void) {
|
2018-11-20 09:54:31 +01:00
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
2017-02-21 11:08:35 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
int c = 0, r;
|
2017-02-25 23:14:00 +01:00
|
|
|
const char *id, *state, *substate;
|
2017-02-21 11:08:35 +01:00
|
|
|
|
2017-02-27 00:07:39 +01:00
|
|
|
if (arg_quiet)
|
|
|
|
return false;
|
|
|
|
|
2017-02-21 11:08:35 +01:00
|
|
|
r = sd_bus_default_system(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to acquire bus: %m");
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
|
|
bus,
|
|
|
|
&m,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
|
|
|
"ListUnitsByPatterns");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append_strv(m, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_append_strv(m, STRV_MAKE("systemd-coredump@*.service"));
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
2017-03-01 16:00:47 +01:00
|
|
|
r = sd_bus_call(bus, m, SHORT_BUS_CALL_TIMEOUT_USEC, &error, &reply);
|
2017-02-21 11:08:35 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to check if any systemd-coredump@.service units are running: %s",
|
|
|
|
bus_error_message(&error, r));
|
|
|
|
|
|
|
|
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
while ((r = sd_bus_message_read(
|
|
|
|
reply, "(ssssssouso)",
|
2017-02-25 23:14:00 +01:00
|
|
|
&id, NULL, NULL, &state, &substate,
|
|
|
|
NULL, NULL, NULL, NULL, NULL)) > 0) {
|
2017-03-01 03:47:45 +01:00
|
|
|
bool found = !STR_IN_SET(state, "inactive", "dead", "failed");
|
2017-02-25 23:14:00 +01:00
|
|
|
log_debug("Unit %s is %s/%s, %scounting it.", id, state, substate, found ? "" : "not ");
|
|
|
|
c += found;
|
|
|
|
}
|
2017-02-21 11:08:35 +01:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
static int coredumpctl_main(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
static const Verb verbs[] = {
|
2018-04-18 21:32:17 +02:00
|
|
|
{ "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, dump_list },
|
|
|
|
{ "info", VERB_ANY, VERB_ANY, 0, dump_list },
|
|
|
|
{ "dump", VERB_ANY, VERB_ANY, 0, dump_core },
|
|
|
|
{ "debug", VERB_ANY, VERB_ANY, 0, run_debug },
|
|
|
|
{ "gdb", VERB_ANY, VERB_ANY, 0, run_debug },
|
2018-03-14 09:46:34 +01:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
return dispatch_verb(argc, argv, verbs, NULL);
|
|
|
|
}
|
|
|
|
|
2018-11-20 09:50:07 +01:00
|
|
|
static int run(int argc, char *argv[]) {
|
2018-03-14 09:46:34 +01:00
|
|
|
int r, units_active;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2012-11-12 20:16:07 +01:00
|
|
|
setlocale(LC_ALL, "");
|
2012-10-19 12:29:46 +02:00
|
|
|
log_parse_environment();
|
|
|
|
log_open();
|
|
|
|
|
2018-10-01 17:44:46 +02:00
|
|
|
/* The journal merging logic potentially needs a lot of fds. */
|
|
|
|
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
|
|
|
|
|
2016-11-06 17:29:31 +01:00
|
|
|
r = parse_argv(argc, argv);
|
2018-03-14 09:46:34 +01:00
|
|
|
if (r <= 0)
|
2018-11-20 09:50:07 +01:00
|
|
|
return r;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2015-01-05 00:52:47 +01:00
|
|
|
sigbus_install();
|
|
|
|
|
2017-02-21 11:08:35 +01:00
|
|
|
units_active = check_units_active(); /* error is treated the same as 0 */
|
|
|
|
|
2018-03-14 09:46:34 +01:00
|
|
|
r = coredumpctl_main(argc, argv);
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2017-02-21 11:08:35 +01:00
|
|
|
if (units_active > 0)
|
|
|
|
printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n",
|
|
|
|
ansi_highlight_red(),
|
|
|
|
units_active, units_active == 1 ? "unit is running" : "units are running",
|
|
|
|
ansi_normal());
|
2018-11-20 09:50:07 +01:00
|
|
|
return r;
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|
2018-11-20 09:50:07 +01:00
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
|