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 int 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 char buf[FORMAT_TIMESTAMP_MAX];
245 SD_JOURNAL_FOREACH_DATA(j, d, l) {
246 retrieve(d, l, "COREDUMP_PID", &pid);
247 retrieve(d, l, "COREDUMP_PID", &pid);
248 retrieve(d, l, "COREDUMP_UID", &uid);
249 retrieve(d, l, "COREDUMP_GID", &gid);
250 retrieve(d, l, "COREDUMP_SIGNAL", &sgnl);
251 retrieve(d, l, "COREDUMP_EXE", &exe);
253 retrieve(d, l, "COREDUMP_COMM", &exe);
255 retrieve(d, l, "COREDUMP_CMDLINE", &exe);
258 if (!pid && !uid && !gid && !sgnl && !exe) {
259 log_warning("Empty coredump log entry");
263 r = sd_journal_get_realtime_usec(j, &t);
265 log_error("Failed to get realtime timestamp: %s", strerror(-r));
269 format_timestamp(buf, sizeof(buf), t);
272 fprintf(file, "%-*s %*s %*s %*s %*s %s\n",
273 FORMAT_TIMESTAMP_MAX-1, "TIME",
280 fprintf(file, "%*s %*s %*s %*s %*s %s\n",
281 FORMAT_TIMESTAMP_MAX-1, buf,
291 static int dump_list(sd_journal *j) {
296 SD_JOURNAL_FOREACH(j)
297 print_entry(stdout, j, found++);
300 log_notice("No coredumps found");
307 static int dump_core(sd_journal* j) {
314 r = sd_journal_seek_tail(j);
316 r = sd_journal_previous(j);
318 log_error("Failed to search journal: %s", strerror(-r));
323 log_error("No match found");
327 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
329 log_error("retrieve COREDUMP field: %s", strerror(-r));
333 print_entry(output ? stdout : stderr, j, false);
335 if (on_tty() && !output) {
336 log_error("Refusing to dump core to tty");
342 ret = fwrite(data+9, len-9, 1, output ? output : stdout);
344 log_error("dumping coredump: %m (%zu)", ret);
348 r = sd_journal_previous(j);
350 log_warning("More than one entry matches, ignoring rest.\n");
355 int main(int argc, char *argv[]) {
356 sd_journal *j = NULL;
361 log_parse_environment();
364 matches = new_matches();
368 if (parse_argv(argc, argv))
371 if (arg_action == ACTION_NONE)
374 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
376 log_error("Failed to open journal: %s", strerror(-r));
380 SET_FOREACH(match, matches, it) {
381 r = sd_journal_add_match(j, match, strlen(match));
383 log_error("Failed to add match '%s': %s",
384 match, strerror(-r));
400 assert_not_reached("Shouldn't be here");
407 set_free_free(matches);
414 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;