2012-10-19 12:29:46 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2012 Zbigniew Jędrzejewski-Szmek
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
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
|
|
|
|
2015-01-05 00:52:47 +01:00
|
|
|
#include "sd-journal.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "compress.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-26 18:05:03 +01:00
|
|
|
#include "fileio.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"
|
2012-10-19 12:29:46 +02:00
|
|
|
#include "log.h"
|
2013-03-18 04:36:25 +01:00
|
|
|
#include "macro.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"
|
2015-04-10 19:10:00 +02:00
|
|
|
#include "process-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "set.h"
|
|
|
|
#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"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "terminal-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"
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
static enum {
|
|
|
|
ACTION_NONE,
|
2014-06-18 23:34:59 +02:00
|
|
|
ACTION_INFO,
|
2012-10-19 12:29:46 +02:00
|
|
|
ACTION_LIST,
|
|
|
|
ACTION_DUMP,
|
2012-10-27 01:19:47 +02:00
|
|
|
ACTION_GDB,
|
2012-10-19 12:29:46 +02:00
|
|
|
} arg_action = ACTION_LIST;
|
2014-06-18 23:34:59 +02:00
|
|
|
static const char* arg_field = NULL;
|
2015-08-25 10:36:49 +02:00
|
|
|
static const char *arg_directory = NULL;
|
2016-02-19 19:25:13 +01:00
|
|
|
static bool arg_no_pager = false;
|
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;
|
2015-01-05 01:08:51 +01:00
|
|
|
static FILE* arg_output = NULL;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
static Set *new_matches(void) {
|
|
|
|
Set *set;
|
|
|
|
char *tmp;
|
|
|
|
int r;
|
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
set = set_new(NULL);
|
2012-10-19 12:29:46 +02:00
|
|
|
if (!set) {
|
|
|
|
log_oom();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
|
|
|
|
if (!tmp) {
|
|
|
|
log_oom();
|
2012-10-26 14:11:37 +02:00
|
|
|
set_free(set);
|
2012-10-19 12:29:46 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-04-23 05:12:15 +02:00
|
|
|
r = set_consume(set, tmp);
|
2012-10-19 12:29:46 +02:00
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "failed to add to set: %m");
|
2012-10-26 14:11:37 +02:00
|
|
|
set_free(set);
|
2012-10-19 12:29:46 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return set;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int add_match(Set *set, const char *match) {
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2015-10-22 19:28:31 +02:00
|
|
|
char *pattern = NULL;
|
|
|
|
const char* prefix;
|
|
|
|
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)
|
2012-10-19 12:29:46 +02:00
|
|
|
goto fail;
|
|
|
|
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=";
|
|
|
|
|
|
|
|
pattern = strjoin(prefix, match, NULL);
|
2015-10-22 19:28:31 +02:00
|
|
|
if (!pattern) {
|
|
|
|
r = -ENOMEM;
|
2012-10-19 12:29:46 +02:00
|
|
|
goto fail;
|
2015-10-22 19:28:31 +02:00
|
|
|
}
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2013-04-23 05:12:15 +02:00
|
|
|
log_debug("Adding pattern: %s", pattern);
|
2014-07-18 20:01:13 +02:00
|
|
|
r = set_consume(set, pattern);
|
2015-10-22 19:28:31 +02:00
|
|
|
if (r < 0)
|
2012-10-19 12:29:46 +02:00
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
fail:
|
2014-11-28 18:23:20 +01:00
|
|
|
return log_error_errno(r, "Failed to add match: %m");
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|
|
|
|
|
2014-08-02 17:12:21 +02:00
|
|
|
static void help(void) {
|
|
|
|
printf("%s [OPTIONS...]\n\n"
|
|
|
|
"List or retrieve coredumps from the journal.\n\n"
|
|
|
|
"Flags:\n"
|
|
|
|
" -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"
|
|
|
|
" -1 Show information about most recent entry only\n"
|
|
|
|
" -F --field=FIELD List all values a certain field takes\n"
|
|
|
|
" -o --output=FILE Write output to FILE\n\n"
|
2015-08-25 10:36:49 +02:00
|
|
|
" -D --directory=DIR Use journal files from directory\n\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"
|
|
|
|
" gdb [MATCHES...] Start gdb for the first matching coredump\n"
|
|
|
|
, program_invocation_short_name);
|
|
|
|
}
|
|
|
|
|
2013-03-18 04:36:25 +01:00
|
|
|
static int parse_argv(int argc, char *argv[], Set *matches) {
|
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,
|
2012-10-19 12:29:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
int r, c;
|
|
|
|
|
|
|
|
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 },
|
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' },
|
2013-11-06 18:28:39 +01:00
|
|
|
{}
|
2012-10-19 12:29:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
assert(argv);
|
|
|
|
|
2015-08-25 10:36:49 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "ho:F:1D:", options, NULL)) >= 0)
|
2012-10-19 12:29:46 +02:00
|
|
|
switch(c) {
|
2013-11-06 18:28:39 +01:00
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
case 'h':
|
|
|
|
arg_action = ACTION_NONE;
|
2014-08-02 17:12:21 +02:00
|
|
|
help();
|
|
|
|
return 0;
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
case ARG_VERSION:
|
2013-11-06 18:28:39 +01:00
|
|
|
arg_action = ACTION_NONE;
|
2015-09-23 03:01:06 +02:00
|
|
|
return version();
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
case ARG_NO_PAGER:
|
|
|
|
arg_no_pager = true;
|
|
|
|
break;
|
|
|
|
|
2012-10-30 09:45:19 +01:00
|
|
|
case ARG_NO_LEGEND:
|
|
|
|
arg_no_legend = true;
|
|
|
|
break;
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
case 'o':
|
2015-01-05 01:08:51 +01:00
|
|
|
if (arg_output) {
|
2012-10-19 12:29:46 +02:00
|
|
|
log_error("cannot set output more than once");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-01-05 01:08:51 +01:00
|
|
|
arg_output = fopen(optarg, "we");
|
|
|
|
if (!arg_output)
|
2014-11-28 19:57:32 +01:00
|
|
|
return log_error_errno(errno, "writing to '%s': %m", optarg);
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
break;
|
2012-10-30 09:35:53 +01:00
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
case 'F':
|
2014-06-18 23:05:15 +02:00
|
|
|
if (arg_field) {
|
2012-10-30 11:15:24 +01:00
|
|
|
log_error("cannot use --field/-F more than once");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
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;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (optind < argc) {
|
|
|
|
const char *cmd = argv[optind++];
|
2013-12-03 22:27:45 +01:00
|
|
|
if (streq(cmd, "list"))
|
2012-10-19 12:29:46 +02:00
|
|
|
arg_action = ACTION_LIST;
|
|
|
|
else if (streq(cmd, "dump"))
|
|
|
|
arg_action = ACTION_DUMP;
|
2012-10-27 01:19:47 +02:00
|
|
|
else if (streq(cmd, "gdb"))
|
|
|
|
arg_action = ACTION_GDB;
|
2014-06-18 23:34:59 +02:00
|
|
|
else if (streq(cmd, "info"))
|
|
|
|
arg_action = ACTION_INFO;
|
2012-10-19 12:29:46 +02:00
|
|
|
else {
|
|
|
|
log_error("Unknown action '%s'", cmd);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-18 23:05:15 +02:00
|
|
|
if (arg_field && arg_action != ACTION_LIST) {
|
2012-10-30 11:15:24 +01:00
|
|
|
log_error("Option --field/-F only makes sense with list");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
while (optind < argc) {
|
|
|
|
r = add_match(matches, argv[optind]);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
optind++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
static void print_field(FILE* file, sd_journal *j) {
|
2014-06-18 23:05:15 +02:00
|
|
|
_cleanup_free_ char *value = NULL;
|
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
|
|
|
|
|
|
|
SD_JOURNAL_FOREACH_DATA(j, d, l)
|
2014-06-18 23:05:15 +02:00
|
|
|
retrieve(d, l, arg_field, &value);
|
|
|
|
|
2012-10-30 11:15:24 +01:00
|
|
|
if (value)
|
|
|
|
fprintf(file, "%s\n", value);
|
|
|
|
}
|
|
|
|
|
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
|
2012-10-19 12:29:46 +02:00
|
|
|
*pid = NULL, *uid = NULL, *gid = NULL,
|
2014-06-26 05:38:49 +02:00
|
|
|
*sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
|
|
|
|
*filename = 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;
|
2014-06-26 05:38:49 +02:00
|
|
|
bool present;
|
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) {
|
|
|
|
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);
|
2014-06-18 23:05:15 +02:00
|
|
|
retrieve(d, l, "COREDUMP_COMM", &comm);
|
|
|
|
retrieve(d, l, "COREDUMP_CMDLINE", &cmdline);
|
2014-06-26 05:38:49 +02:00
|
|
|
retrieve(d, l, "COREDUMP_FILENAME", &filename);
|
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);
|
2014-06-26 05:38:49 +02:00
|
|
|
present = filename && access(filename, F_OK) == 0;
|
2012-10-26 20:34:39 +02:00
|
|
|
|
2012-10-30 09:45:19 +01:00
|
|
|
if (!had_legend && !arg_no_legend)
|
2014-06-26 05:38:49 +02: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",
|
2014-06-26 05:38:49 +02:00
|
|
|
1, "PRESENT",
|
2012-10-26 20:34:39 +02:00
|
|
|
"EXE");
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2014-06-26 05:38:49 +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),
|
|
|
|
3, strna(sgnl),
|
2014-06-26 05:38:49 +02:00
|
|
|
1, 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
|
|
|
|
*pid = NULL, *uid = NULL, *gid = NULL,
|
|
|
|
*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,
|
|
|
|
*message = NULL, *timestamp = NULL, *filename = NULL;
|
2014-06-18 23:34:59 +02:00
|
|
|
const void *d;
|
|
|
|
size_t l;
|
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) {
|
|
|
|
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);
|
2014-06-18 23:55:36 +02:00
|
|
|
retrieve(d, l, "COREDUMP_OWNER_UID", &owner_uid);
|
|
|
|
retrieve(d, l, "COREDUMP_SLICE", &slice);
|
|
|
|
retrieve(d, l, "COREDUMP_CGROUP", &cgroup);
|
2014-06-23 15:51:09 +02:00
|
|
|
retrieve(d, l, "COREDUMP_TIMESTAMP", ×tamp);
|
2014-06-26 05:38:49 +02:00
|
|
|
retrieve(d, l, "COREDUMP_FILENAME", &filename);
|
2014-06-18 23:34:59 +02:00
|
|
|
retrieve(d, l, "_BOOT_ID", &boot_id);
|
|
|
|
retrieve(d, l, "_MACHINE_ID", &machine_id);
|
|
|
|
retrieve(d, l, "_HOSTNAME", &hostname);
|
2014-06-19 12:07:12 +02:00
|
|
|
retrieve(d, l, "MESSAGE", &message);
|
2014-06-18 23:34:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (need_space)
|
|
|
|
fputs("\n", file);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (safe_atoi(sgnl, &sig) >= 0)
|
|
|
|
fprintf(file, " Signal: %s (%s)\n", sgnl, signal_to_string(sig));
|
|
|
|
else
|
|
|
|
fprintf(file, " Signal: %s\n", sgnl);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
if (filename && access(filename, F_OK) == 0)
|
|
|
|
fprintf(file, " Coredump: %s\n", filename);
|
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");
|
2012-10-26 20:25:10 +02:00
|
|
|
if (r == 0) {
|
2014-06-19 12:24:00 +02:00
|
|
|
log_error("No match found.");
|
2012-10-26 20:25:10 +02:00
|
|
|
return -ESRCH;
|
|
|
|
}
|
2012-10-27 01:19:47 +02:00
|
|
|
return r;
|
|
|
|
}
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2014-06-19 12:24:00 +02:00
|
|
|
static void print_entry(sd_journal *j, unsigned n_found) {
|
|
|
|
assert(j);
|
|
|
|
|
|
|
|
if (arg_action == ACTION_INFO)
|
|
|
|
print_info(stdout, j, n_found);
|
|
|
|
else if (arg_field)
|
|
|
|
print_field(stdout, j);
|
|
|
|
else
|
|
|
|
print_list(stdout, j, n_found);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_list(sd_journal *j) {
|
|
|
|
unsigned n_found = 0;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(j);
|
|
|
|
|
|
|
|
/* The coredumps are likely to compressed, and for just
|
|
|
|
* listing them we don't need to decompress them, so let's
|
|
|
|
* pick a fairly low data threshold here */
|
|
|
|
sd_journal_set_data_threshold(j, 4096);
|
|
|
|
|
|
|
|
if (arg_one) {
|
|
|
|
r = focus(j);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
print_entry(j, 0);
|
|
|
|
} else {
|
|
|
|
SD_JOURNAL_FOREACH(j)
|
|
|
|
print_entry(j, n_found++);
|
|
|
|
|
|
|
|
if (!arg_field && n_found <= 0) {
|
|
|
|
log_notice("No coredumps found.");
|
|
|
|
return -ESRCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
|
|
|
|
const char *data;
|
|
|
|
_cleanup_free_ char *filename = NULL;
|
|
|
|
size_t len;
|
2012-10-27 01:19:47 +02:00
|
|
|
int r;
|
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
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
assert((fd >= 0) != !!path);
|
|
|
|
assert(!!path == !!unlink_temp);
|
2012-10-27 01:19:47 +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);
|
|
|
|
if (r < 0 && r != -ENOENT)
|
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 log_error_errno(r, "Failed to retrieve COREDUMP_FILENAME: %m");
|
2014-06-26 05:38:49 +02:00
|
|
|
else if (r == 0)
|
|
|
|
retrieve(data, len, "COREDUMP_FILENAME", &filename);
|
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")) {
|
2014-06-27 00:17:22 +02:00
|
|
|
*path = filename;
|
|
|
|
filename = NULL;
|
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
|
|
|
|
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 (fd < 0) {
|
|
|
|
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
|
|
|
|
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
|
|
|
temp = strjoin(vt, "/coredump-XXXXXX", NULL);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filename) {
|
2014-07-04 04:42:22 +02:00
|
|
|
#if defined(HAVE_XZ) || defined(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
|
|
|
|
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)
|
|
|
|
return log_error_errno(r,
|
|
|
|
r == -ENOENT ? "Core file was not saved for this entry." :
|
|
|
|
"Failed to retrieve COREDUMP field: %m");
|
|
|
|
|
|
|
|
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) {
|
|
|
|
unlink(temp);
|
|
|
|
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
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
static int dump_core(sd_journal* j) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(j);
|
|
|
|
|
|
|
|
r = focus(j);
|
|
|
|
if (r < 0)
|
2012-10-27 01:19:47 +02:00
|
|
|
return r;
|
|
|
|
|
2015-01-05 01:08:51 +01:00
|
|
|
print_info(arg_output ? stdout : stderr, j, false);
|
2014-06-26 05:38:49 +02:00
|
|
|
|
2015-01-05 01:08:51 +01:00
|
|
|
if (on_tty() && !arg_output) {
|
2014-06-26 05:38:49 +02:00
|
|
|
log_error("Refusing to dump core to tty.");
|
|
|
|
return -ENOTTY;
|
|
|
|
}
|
|
|
|
|
2015-01-05 01:08:51 +01:00
|
|
|
r = save_core(j, arg_output ? fileno(arg_output) : STDOUT_FILENO, NULL, NULL);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Coredump retrieval failed: %m");
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
r = sd_journal_previous(j);
|
2016-09-27 00:40:55 +02:00
|
|
|
if (r > 0)
|
2013-12-24 16:39:37 +01:00
|
|
|
log_warning("More than one entry matches, ignoring rest.");
|
2012-10-19 12:29:46 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-27 01:19:47 +02:00
|
|
|
static int run_gdb(sd_journal *j) {
|
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;
|
|
|
|
const char *data;
|
2014-06-18 23:05:15 +02:00
|
|
|
siginfo_t st;
|
2012-10-27 01:19:47 +02:00
|
|
|
size_t len;
|
|
|
|
pid_t pid;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(j);
|
|
|
|
|
|
|
|
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
|
|
|
|
2014-06-26 05:38:49 +02: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;
|
|
|
|
}
|
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
r = save_core(j, -1, &path, &unlink_path);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to retrieve core: %m");
|
2012-10-27 01:19:47 +02:00
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
2015-09-08 19:30:45 +02:00
|
|
|
r = log_error_errno(errno, "Failed to fork(): %m");
|
2012-10-27 01:19:47 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
if (pid == 0) {
|
2015-05-31 23:55:55 +02:00
|
|
|
(void) reset_all_signal_handlers();
|
|
|
|
(void) reset_signal_mask();
|
|
|
|
|
2012-10-27 01:19:47 +02:00
|
|
|
execlp("gdb", "gdb", exe, path, NULL);
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2014-11-28 19:29:59 +01:00
|
|
|
log_error_errno(errno, "Failed to invoke gdb: %m");
|
2012-10-27 01:19:47 +02:00
|
|
|
_exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = wait_for_terminate(pid, &st);
|
|
|
|
if (r < 0) {
|
2015-11-05 13:44:06 +01:00
|
|
|
log_error_errno(r, "Failed to wait for gdb: %m");
|
2012-10-27 01:19:47 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = st.si_code == CLD_EXITED ? st.si_status : 255;
|
|
|
|
|
|
|
|
finish:
|
2014-06-26 05:38:49 +02:00
|
|
|
if (unlink_path) {
|
|
|
|
log_debug("Removed temporary file %s", path);
|
|
|
|
unlink(path);
|
|
|
|
}
|
2014-06-18 23:05:15 +02:00
|
|
|
|
2012-10-27 01:19:47 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
int main(int argc, char *argv[]) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_journal_closep) sd_journal*j = NULL;
|
2012-10-19 12:29:46 +02:00
|
|
|
const char* match;
|
|
|
|
Iterator it;
|
|
|
|
int r = 0;
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_set_free_free_ Set *matches = NULL;
|
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();
|
|
|
|
|
|
|
|
matches = new_matches();
|
2012-10-30 09:44:32 +01:00
|
|
|
if (!matches) {
|
|
|
|
r = -ENOMEM;
|
2012-10-19 12:29:46 +02:00
|
|
|
goto end;
|
2012-10-30 09:44:32 +01:00
|
|
|
}
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2013-03-18 04:36:25 +01:00
|
|
|
r = parse_argv(argc, argv, matches);
|
2012-10-30 09:44:32 +01:00
|
|
|
if (r < 0)
|
2012-10-19 12:29:46 +02:00
|
|
|
goto end;
|
|
|
|
|
|
|
|
if (arg_action == ACTION_NONE)
|
|
|
|
goto end;
|
|
|
|
|
2015-01-05 00:52:47 +01:00
|
|
|
sigbus_install();
|
|
|
|
|
2015-08-25 10:36:49 +02:00
|
|
|
if (arg_directory) {
|
|
|
|
r = sd_journal_open_directory(&j, arg_directory, 0);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to open journal: %m");
|
|
|
|
goto end;
|
|
|
|
}
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|
|
|
|
|
2014-06-26 05:38:49 +02:00
|
|
|
/* We want full data, nothing truncated. */
|
|
|
|
sd_journal_set_data_threshold(j, 0);
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
SET_FOREACH(match, matches, it) {
|
|
|
|
r = sd_journal_add_match(j, match, strlen(match));
|
|
|
|
if (r != 0) {
|
2014-11-28 17:09:20 +01:00
|
|
|
log_error_errno(r, "Failed to add match '%s': %m",
|
|
|
|
match);
|
2012-10-19 12:29:46 +02:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-06 06:29:40 +01:00
|
|
|
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
|
2013-08-02 13:58:26 +02:00
|
|
|
_cleanup_free_ char *filter;
|
|
|
|
|
|
|
|
filter = journal_make_match_string(j);
|
|
|
|
log_debug("Journal filter: %s", filter);
|
|
|
|
}
|
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
switch(arg_action) {
|
2012-10-27 01:19:47 +02:00
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
case ACTION_LIST:
|
2014-06-18 23:34:59 +02:00
|
|
|
case ACTION_INFO:
|
2016-02-19 19:25:13 +01:00
|
|
|
pager_open(arg_no_pager, false);
|
2012-10-19 12:29:46 +02:00
|
|
|
r = dump_list(j);
|
|
|
|
break;
|
2012-10-27 01:19:47 +02:00
|
|
|
|
2012-10-19 12:29:46 +02:00
|
|
|
case ACTION_DUMP:
|
|
|
|
r = dump_core(j);
|
|
|
|
break;
|
2012-10-27 01:19:47 +02:00
|
|
|
|
|
|
|
case ACTION_GDB:
|
|
|
|
r = run_gdb(j);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2012-10-19 12:29:46 +02:00
|
|
|
assert_not_reached("Shouldn't be here");
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
pager_close();
|
|
|
|
|
2015-01-05 01:08:51 +01:00
|
|
|
if (arg_output)
|
|
|
|
fclose(arg_output);
|
2012-10-19 12:29:46 +02:00
|
|
|
|
2012-10-27 01:19:47 +02:00
|
|
|
return r >= 0 ? r : EXIT_FAILURE;
|
2012-10-19 12:29:46 +02:00
|
|
|
}
|