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;
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(sd_journal *j, const char *name, const char **var) {
215 r = sd_journal_get_data(j, name, &data, &len);
217 log_warning("Failed to retrieve %s", name);
221 field = strlen(name) + 1; // name + "="
222 assert(len >= field);
224 *var = strndup((const char*)data + field, len - field);
231 static void print_entry(FILE* file, sd_journal *j, int had_header) {
232 const char _cleanup_free_
233 *pid = NULL, *uid = NULL, *gid = NULL,
234 *sgnl = NULL, *exe = NULL;
236 retrieve(j, "COREDUMP_PID", &pid);
237 retrieve(j, "COREDUMP_UID", &uid);
238 retrieve(j, "COREDUMP_GID", &gid);
239 retrieve(j, "COREDUMP_SIGNAL", &sgnl);
240 retrieve(j, "COREDUMP_EXE", &exe);
242 retrieve(j, "COREDUMP_COMM", &exe);
244 retrieve(j, "COREDUMP_CMDLINE", &exe);
246 if (!pid && !uid && !gid && !sgnl && !exe) {
247 log_warning("empty coredump log entry");
252 fprintf(file, "%*s %*s %*s %*s %s\n",
259 fprintf(file, "%*s %*s %*s %*s %s\n",
267 static int dump_list(sd_journal *j) {
272 SD_JOURNAL_FOREACH(j)
273 print_entry(stdout, j, found++);
276 log_error("no coredumps found");
283 static int dump_core(sd_journal* j) {
290 r = sd_journal_seek_tail(j);
292 r = sd_journal_previous(j);
294 log_error("Failed to search journal: %s", strerror(-r));
299 log_error("No match found");
303 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
305 log_error("retrieve COREDUMP field: %s", strerror(-r));
309 print_entry(output ? stdout : stderr, j, false);
311 if (on_tty() && !output) {
312 log_error("Refusing to dump core to tty");
318 ret = fwrite(data+9, len-9, 1, output ? output : stdout);
320 log_error("dumping coredump: %m (%zu)", ret);
324 r = sd_journal_previous(j);
326 log_warning("More than one entry matches, ignoring rest.\n");
331 int main(int argc, char *argv[]) {
332 sd_journal *j = NULL;
337 log_parse_environment();
340 matches = new_matches();
344 if (parse_argv(argc, argv))
347 if (arg_action == ACTION_NONE)
350 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
352 log_error("Failed to open journal: %s", strerror(-r));
356 SET_FOREACH(match, matches, it) {
357 log_info("Matching: %s", match);
359 r = sd_journal_add_match(j, match, strlen(match));
361 log_error("Failed to add match '%s': %s",
362 match, strerror(-r));
378 assert_not_reached("Shouldn't be here");
385 set_free_free(matches);
392 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;