1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <systemd/sd-journal.h>
32 #include "path-util.h"
39 } arg_action = ACTION_LIST;
41 static Set *matches = NULL;
42 static FILE* output = NULL;
44 static int arg_no_pager = false;
46 static Set *new_matches(void) {
51 set = set_new(trivial_hash_func, trivial_compare_func);
57 tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
64 r = set_put(set, tmp);
66 log_error("failed to add to set: %s", strerror(-r));
75 static int help(void) {
76 printf("%s [OPTIONS...] [MATCHES...]\n\n"
77 "List or retrieve coredumps from the journal.\n\n"
79 " -o --output=FILE Write output to FILE\n"
80 " --no-pager Do not pipe output into a pager\n"
83 " -h --help Show this help\n"
84 " --version Print version string\n"
85 " list List available coredumps\n"
86 " dump PID Print coredump to stdout\n"
87 " dump PATH Print coredump to stdout\n"
88 , program_invocation_short_name);
93 static int add_match(Set *set, const char *match) {
98 char _cleanup_free_ *p = NULL;
100 if (strchr(match, '='))
102 else if (strchr(match, '/')) {
103 p = path_make_absolute_cwd(match);
108 prefix = "COREDUMP_EXE=";
110 else if (safe_atou(match, &pid) == 0)
111 prefix = "COREDUMP_PID=";
113 prefix = "COREDUMP_COMM=";
115 pattern = strjoin(prefix, match, NULL);
119 r = set_put(set, pattern);
121 log_error("failed to add pattern '%s': %s",
122 pattern, strerror(-r));
125 log_debug("Added pattern: %s", pattern);
130 log_error("failed to add match: %s", strerror(-r));
134 static int parse_argv(int argc, char *argv[]) {
142 static const struct option options[] = {
143 { "help", no_argument, NULL, 'h' },
144 { "version" , no_argument, NULL, ARG_VERSION },
145 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
146 { "output", required_argument, NULL, 'o' },
152 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
156 arg_action = ACTION_NONE;
160 puts(PACKAGE_STRING);
162 puts(SYSTEMD_FEATURES);
163 arg_action = ACTION_NONE;
172 log_error("cannot set output more than once");
176 output = fopen(optarg, "we");
178 log_error("writing to '%s': %m", optarg);
184 log_error("Unknown option code %c", c);
189 const char *cmd = argv[optind++];
190 if(streq(cmd, "list"))
191 arg_action = ACTION_LIST;
192 else if (streq(cmd, "dump"))
193 arg_action = ACTION_DUMP;
195 log_error("Unknown action '%s'", cmd);
200 while (optind < argc) {
201 r = add_match(matches, argv[optind]);
210 static int retrieve(const void *data,
217 field = strlen(name) + 1; /* name + "=" */
222 if (memcmp(data, name, field - 1) != 0)
225 if (((const char*) data)[field - 1] != '=')
228 *var = strndup((const char*)data + field, len - field);
235 static void print_entry(FILE* file, sd_journal *j, int had_header) {
236 const char _cleanup_free_
237 *pid = NULL, *uid = NULL, *gid = NULL,
238 *sgnl = NULL, *exe = NULL;
242 SD_JOURNAL_FOREACH_DATA(j, d, l) {
243 retrieve(d, l, "COREDUMP_PID", &pid);
244 retrieve(d, l, "COREDUMP_PID", &pid);
245 retrieve(d, l, "COREDUMP_UID", &uid);
246 retrieve(d, l, "COREDUMP_GID", &gid);
247 retrieve(d, l, "COREDUMP_SIGNAL", &sgnl);
248 retrieve(d, l, "COREDUMP_EXE", &exe);
250 retrieve(d, l, "COREDUMP_COMM", &exe);
252 retrieve(d, l, "COREDUMP_CMDLINE", &exe);
255 if (!pid && !uid && !gid && !sgnl && !exe) {
256 log_warning("empty coredump log entry");
261 fprintf(file, "%*s %*s %*s %*s %s\n",
268 fprintf(file, "%*s %*s %*s %*s %s\n",
276 static int dump_list(sd_journal *j) {
281 SD_JOURNAL_FOREACH(j)
282 print_entry(stdout, j, found++);
285 log_error("no coredumps found");
292 static int dump_core(sd_journal* j) {
299 r = sd_journal_seek_tail(j);
301 r = sd_journal_previous(j);
303 log_error("Failed to search journal: %s", strerror(-r));
308 log_error("No match found");
312 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
314 log_error("retrieve COREDUMP field: %s", strerror(-r));
318 print_entry(output ? stdout : stderr, j, false);
320 if (on_tty() && !output) {
321 log_error("Refusing to dump core to tty");
327 ret = fwrite(data+9, len-9, 1, output ? output : stdout);
329 log_error("dumping coredump: %m (%zu)", ret);
333 r = sd_journal_previous(j);
335 log_warning("More than one entry matches, ignoring rest.\n");
340 int main(int argc, char *argv[]) {
341 sd_journal *j = NULL;
346 log_parse_environment();
349 matches = new_matches();
353 if (parse_argv(argc, argv))
356 if (arg_action == ACTION_NONE)
359 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
361 log_error("Failed to open journal: %s", strerror(-r));
365 SET_FOREACH(match, matches, it) {
366 r = sd_journal_add_match(j, match, strlen(match));
368 log_error("Failed to add match '%s': %s",
369 match, strerror(-r));
385 assert_not_reached("Shouldn't be here");
392 set_free_free(matches);
399 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;