]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredumpctl.c
bus: stop using EDEADLOCK
[thirdparty/systemd.git] / src / journal / coredumpctl.c
CommitLineData
5de0409e
ZJS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Zbigniew Jędrzejewski-Szmek
7
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.
12
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.
17
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/>.
20***/
21
a9cdc94f 22#include <locale.h>
5de0409e
ZJS
23#include <stdio.h>
24#include <string.h>
25#include <getopt.h>
ada45c78
LP
26#include <fcntl.h>
27#include <unistd.h>
5de0409e 28
2cf4172a 29#include "sd-journal.h"
5de0409e
ZJS
30#include "build.h"
31#include "set.h"
32#include "util.h"
33#include "log.h"
34#include "path-util.h"
35#include "pager.h"
763c7aa2 36#include "macro.h"
dfb33a97 37#include "journal-internal.h"
9fe13294 38#include "compress.h"
2cf4172a 39#include "sigbus.h"
5de0409e
ZJS
40
41static enum {
42 ACTION_NONE,
e15758cc 43 ACTION_INFO,
5de0409e
ZJS
44 ACTION_LIST,
45 ACTION_DUMP,
ada45c78 46 ACTION_GDB,
5de0409e 47} arg_action = ACTION_LIST;
e15758cc 48static const char* arg_field = NULL;
ccc40358 49static int arg_no_pager = false;
9a340880 50static int arg_no_legend = false;
0c51aada 51static int arg_one = false;
3774cf57 52static FILE* arg_output = NULL;
5de0409e
ZJS
53
54static Set *new_matches(void) {
55 Set *set;
56 char *tmp;
57 int r;
58
d5099efc 59 set = set_new(NULL);
5de0409e
ZJS
60 if (!set) {
61 log_oom();
62 return NULL;
63 }
64
65 tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
66 if (!tmp) {
67 log_oom();
4a207bb2 68 set_free(set);
5de0409e
ZJS
69 return NULL;
70 }
71
ef42202a 72 r = set_consume(set, tmp);
5de0409e 73 if (r < 0) {
da927ba9 74 log_error_errno(r, "failed to add to set: %m");
4a207bb2 75 set_free(set);
5de0409e
ZJS
76 return NULL;
77 }
78
79 return set;
80}
81
5de0409e
ZJS
82static int add_match(Set *set, const char *match) {
83 int r = -ENOMEM;
84 unsigned pid;
85 const char* prefix;
86 char *pattern = NULL;
7fd1b19b 87 _cleanup_free_ char *p = NULL;
5de0409e
ZJS
88
89 if (strchr(match, '='))
90 prefix = "";
91 else if (strchr(match, '/')) {
92 p = path_make_absolute_cwd(match);
93 if (!p)
94 goto fail;
95
96 match = p;
97 prefix = "COREDUMP_EXE=";
98 }
99 else if (safe_atou(match, &pid) == 0)
100 prefix = "COREDUMP_PID=";
101 else
102 prefix = "COREDUMP_COMM=";
103
104 pattern = strjoin(prefix, match, NULL);
105 if (!pattern)
106 goto fail;
107
ef42202a 108 log_debug("Adding pattern: %s", pattern);
f7a5bb28 109 r = set_consume(set, pattern);
5de0409e 110 if (r < 0) {
da927ba9 111 log_error_errno(r, "Failed to add pattern: %m");
5de0409e
ZJS
112 goto fail;
113 }
5de0409e
ZJS
114
115 return 0;
116fail:
23bbb0de 117 return log_error_errno(r, "Failed to add match: %m");
5de0409e
ZJS
118}
119
601185b4
ZJS
120static void help(void) {
121 printf("%s [OPTIONS...]\n\n"
122 "List or retrieve coredumps from the journal.\n\n"
123 "Flags:\n"
124 " -h --help Show this help\n"
125 " --version Print version string\n"
126 " --no-pager Do not pipe output into a pager\n"
127 " --no-legend Do not print the column headers.\n"
128 " -1 Show information about most recent entry only\n"
129 " -F --field=FIELD List all values a certain field takes\n"
130 " -o --output=FILE Write output to FILE\n\n"
131
132 "Commands:\n"
133 " list [MATCHES...] List available coredumps (default)\n"
134 " info [MATCHES...] Show detailed information about one or more coredumps\n"
135 " dump [MATCHES...] Print first matching coredump to stdout\n"
136 " gdb [MATCHES...] Start gdb for the first matching coredump\n"
137 , program_invocation_short_name);
138}
139
763c7aa2 140static int parse_argv(int argc, char *argv[], Set *matches) {
5de0409e
ZJS
141 enum {
142 ARG_VERSION = 0x100,
143 ARG_NO_PAGER,
9a340880 144 ARG_NO_LEGEND,
5de0409e
ZJS
145 };
146
147 int r, c;
148
149 static const struct option options[] = {
57ce4bd4
ZJS
150 { "help", no_argument, NULL, 'h' },
151 { "version" , no_argument, NULL, ARG_VERSION },
152 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
9a340880 153 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
57ce4bd4 154 { "output", required_argument, NULL, 'o' },
4f76ae1b 155 { "field", required_argument, NULL, 'F' },
eb9da376 156 {}
5de0409e
ZJS
157 };
158
159 assert(argc >= 0);
160 assert(argv);
161
0c51aada 162 while ((c = getopt_long(argc, argv, "ho:F:1", options, NULL)) >= 0)
5de0409e 163 switch(c) {
eb9da376 164
5de0409e 165 case 'h':
5de0409e 166 arg_action = ACTION_NONE;
601185b4
ZJS
167 help();
168 return 0;
5de0409e
ZJS
169
170 case ARG_VERSION:
eb9da376 171 arg_action = ACTION_NONE;
5de0409e 172 puts(PACKAGE_STRING);
5de0409e 173 puts(SYSTEMD_FEATURES);
5de0409e
ZJS
174 return 0;
175
176 case ARG_NO_PAGER:
177 arg_no_pager = true;
178 break;
179
9a340880
ZJS
180 case ARG_NO_LEGEND:
181 arg_no_legend = true;
182 break;
183
5de0409e 184 case 'o':
3774cf57 185 if (arg_output) {
5de0409e
ZJS
186 log_error("cannot set output more than once");
187 return -EINVAL;
188 }
189
3774cf57
LP
190 arg_output = fopen(optarg, "we");
191 if (!arg_output)
4a62c710 192 return log_error_errno(errno, "writing to '%s': %m", optarg);
5de0409e
ZJS
193
194 break;
57ce4bd4 195
4f76ae1b 196 case 'F':
a276ae74 197 if (arg_field) {
4f76ae1b
ZJS
198 log_error("cannot use --field/-F more than once");
199 return -EINVAL;
200 }
a276ae74 201 arg_field = optarg;
4f76ae1b
ZJS
202 break;
203
0c51aada
LP
204 case '1':
205 arg_one = true;
206 break;
207
57ce4bd4
ZJS
208 case '?':
209 return -EINVAL;
210
5de0409e 211 default:
eb9da376 212 assert_not_reached("Unhandled option");
5de0409e
ZJS
213 }
214
215 if (optind < argc) {
216 const char *cmd = argv[optind++];
f168c273 217 if (streq(cmd, "list"))
5de0409e
ZJS
218 arg_action = ACTION_LIST;
219 else if (streq(cmd, "dump"))
220 arg_action = ACTION_DUMP;
ada45c78
LP
221 else if (streq(cmd, "gdb"))
222 arg_action = ACTION_GDB;
e15758cc
LP
223 else if (streq(cmd, "info"))
224 arg_action = ACTION_INFO;
5de0409e
ZJS
225 else {
226 log_error("Unknown action '%s'", cmd);
227 return -EINVAL;
228 }
229 }
230
a276ae74 231 if (arg_field && arg_action != ACTION_LIST) {
4f76ae1b
ZJS
232 log_error("Option --field/-F only makes sense with list");
233 return -EINVAL;
234 }
235
5de0409e
ZJS
236 while (optind < argc) {
237 r = add_match(matches, argv[optind]);
238 if (r != 0)
239 return r;
240 optind++;
241 }
242
243 return 0;
244}
245
8bc8ab83
LP
246static int retrieve(const void *data,
247 size_t len,
248 const char *name,
a276ae74 249 char **var) {
5de0409e 250
4f76ae1b 251 size_t ident;
a276ae74 252 char *v;
8bc8ab83 253
4f76ae1b 254 ident = strlen(name) + 1; /* name + "=" */
8bc8ab83 255
4f76ae1b 256 if (len < ident)
8bc8ab83 257 return 0;
5de0409e 258
4f76ae1b 259 if (memcmp(data, name, ident - 1) != 0)
8bc8ab83
LP
260 return 0;
261
4f76ae1b 262 if (((const char*) data)[ident - 1] != '=')
8bc8ab83 263 return 0;
5de0409e 264
a276ae74
LP
265 v = strndup((const char*)data + ident, len - ident);
266 if (!v)
5de0409e
ZJS
267 return log_oom();
268
a276ae74
LP
269 free(*var);
270 *var = v;
271
5de0409e
ZJS
272 return 0;
273}
274
4f76ae1b 275static void print_field(FILE* file, sd_journal *j) {
a276ae74 276 _cleanup_free_ char *value = NULL;
4f76ae1b
ZJS
277 const void *d;
278 size_t l;
279
e15758cc
LP
280 assert(file);
281 assert(j);
282
a276ae74 283 assert(arg_field);
4f76ae1b
ZJS
284
285 SD_JOURNAL_FOREACH_DATA(j, d, l)
a276ae74
LP
286 retrieve(d, l, arg_field, &value);
287
4f76ae1b
ZJS
288 if (value)
289 fprintf(file, "%s\n", value);
290}
291
e15758cc 292static int print_list(FILE* file, sd_journal *j, int had_legend) {
a276ae74 293 _cleanup_free_ char
5de0409e 294 *pid = NULL, *uid = NULL, *gid = NULL,
9fe13294
ZJS
295 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
296 *filename = NULL;
8bc8ab83
LP
297 const void *d;
298 size_t l;
684341b0
LP
299 usec_t t;
300 char buf[FORMAT_TIMESTAMP_MAX];
301 int r;
9fe13294 302 bool present;
8bc8ab83 303
e15758cc
LP
304 assert(file);
305 assert(j);
306
8bc8ab83 307 SD_JOURNAL_FOREACH_DATA(j, d, l) {
8bc8ab83
LP
308 retrieve(d, l, "COREDUMP_PID", &pid);
309 retrieve(d, l, "COREDUMP_UID", &uid);
310 retrieve(d, l, "COREDUMP_GID", &gid);
311 retrieve(d, l, "COREDUMP_SIGNAL", &sgnl);
312 retrieve(d, l, "COREDUMP_EXE", &exe);
a276ae74
LP
313 retrieve(d, l, "COREDUMP_COMM", &comm);
314 retrieve(d, l, "COREDUMP_CMDLINE", &cmdline);
9fe13294 315 retrieve(d, l, "COREDUMP_FILENAME", &filename);
8bc8ab83 316 }
5de0409e 317
9fe13294 318 if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) {
684341b0
LP
319 log_warning("Empty coredump log entry");
320 return -EINVAL;
321 }
322
323 r = sd_journal_get_realtime_usec(j, &t);
23bbb0de
MS
324 if (r < 0)
325 return log_error_errno(r, "Failed to get realtime timestamp: %m");
5de0409e 326
684341b0 327 format_timestamp(buf, sizeof(buf), t);
9fe13294 328 present = filename && access(filename, F_OK) == 0;
684341b0 329
9a340880 330 if (!had_legend && !arg_no_legend)
9fe13294 331 fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n",
c3f84106 332 FORMAT_TIMESTAMP_WIDTH, "TIME",
5de0409e
ZJS
333 6, "PID",
334 5, "UID",
335 5, "GID",
684341b0 336 3, "SIG",
9fe13294 337 1, "PRESENT",
684341b0 338 "EXE");
5de0409e 339
9fe13294 340 fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n",
c3f84106 341 FORMAT_TIMESTAMP_WIDTH, buf,
a276ae74
LP
342 6, strna(pid),
343 5, strna(uid),
344 5, strna(gid),
345 3, strna(sgnl),
9fe13294 346 1, present ? "*" : "",
a276ae74 347 strna(exe ?: (comm ?: cmdline)));
684341b0
LP
348
349 return 0;
5de0409e
ZJS
350}
351
e15758cc
LP
352static int print_info(FILE *file, sd_journal *j, bool need_space) {
353 _cleanup_free_ char
354 *pid = NULL, *uid = NULL, *gid = NULL,
355 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
356 *unit = NULL, *user_unit = NULL, *session = NULL,
a035f819 357 *boot_id = NULL, *machine_id = NULL, *hostname = NULL,
9fe13294
ZJS
358 *slice = NULL, *cgroup = NULL, *owner_uid = NULL,
359 *message = NULL, *timestamp = NULL, *filename = NULL;
e15758cc
LP
360 const void *d;
361 size_t l;
4b8cbe9a 362 int r;
e15758cc
LP
363
364 assert(file);
365 assert(j);
366
367 SD_JOURNAL_FOREACH_DATA(j, d, l) {
368 retrieve(d, l, "COREDUMP_PID", &pid);
369 retrieve(d, l, "COREDUMP_UID", &uid);
370 retrieve(d, l, "COREDUMP_GID", &gid);
371 retrieve(d, l, "COREDUMP_SIGNAL", &sgnl);
372 retrieve(d, l, "COREDUMP_EXE", &exe);
373 retrieve(d, l, "COREDUMP_COMM", &comm);
374 retrieve(d, l, "COREDUMP_CMDLINE", &cmdline);
375 retrieve(d, l, "COREDUMP_UNIT", &unit);
376 retrieve(d, l, "COREDUMP_USER_UNIT", &user_unit);
377 retrieve(d, l, "COREDUMP_SESSION", &session);
a035f819
LP
378 retrieve(d, l, "COREDUMP_OWNER_UID", &owner_uid);
379 retrieve(d, l, "COREDUMP_SLICE", &slice);
380 retrieve(d, l, "COREDUMP_CGROUP", &cgroup);
4b8cbe9a 381 retrieve(d, l, "COREDUMP_TIMESTAMP", &timestamp);
9fe13294 382 retrieve(d, l, "COREDUMP_FILENAME", &filename);
e15758cc
LP
383 retrieve(d, l, "_BOOT_ID", &boot_id);
384 retrieve(d, l, "_MACHINE_ID", &machine_id);
385 retrieve(d, l, "_HOSTNAME", &hostname);
8d4e028f 386 retrieve(d, l, "MESSAGE", &message);
e15758cc
LP
387 }
388
389 if (need_space)
390 fputs("\n", file);
391
81cef14f
LP
392 if (comm)
393 fprintf(file,
394 " PID: %s%s%s (%s)\n",
395 ansi_highlight(), strna(pid), ansi_highlight_off(), comm);
396 else
397 fprintf(file,
398 " PID: %s%s%s\n",
399 ansi_highlight(), strna(pid), ansi_highlight_off());
a035f819
LP
400
401 if (uid) {
402 uid_t n;
403
404 if (parse_uid(uid, &n) >= 0) {
405 _cleanup_free_ char *u = NULL;
406
407 u = uid_to_name(n);
408 fprintf(file,
409 " UID: %s (%s)\n",
410 uid, u);
411 } else {
412 fprintf(file,
413 " UID: %s\n",
414 uid);
415 }
416 }
417
418 if (gid) {
419 gid_t n;
420
421 if (parse_gid(gid, &n) >= 0) {
422 _cleanup_free_ char *g = NULL;
423
424 g = gid_to_name(n);
425 fprintf(file,
426 " GID: %s (%s)\n",
427 gid, g);
428 } else {
429 fprintf(file,
430 " GID: %s\n",
431 gid);
432 }
433 }
e15758cc
LP
434
435 if (sgnl) {
436 int sig;
437
438 if (safe_atoi(sgnl, &sig) >= 0)
439 fprintf(file, " Signal: %s (%s)\n", sgnl, signal_to_string(sig));
440 else
441 fprintf(file, " Signal: %s\n", sgnl);
442 }
443
4b8cbe9a
LP
444 if (timestamp) {
445 usec_t u;
446
447 r = safe_atou64(timestamp, &u);
448 if (r >= 0) {
449 char absolute[FORMAT_TIMESTAMP_MAX], relative[FORMAT_TIMESPAN_MAX];
450
451 fprintf(file,
452 " Timestamp: %s (%s)\n",
453 format_timestamp(absolute, sizeof(absolute), u),
454 format_timestamp_relative(relative, sizeof(relative), u));
455
456 } else
457 fprintf(file, " Timestamp: %s\n", timestamp);
458 }
459
e15758cc
LP
460 if (cmdline)
461 fprintf(file, " Command Line: %s\n", cmdline);
81cef14f
LP
462 if (exe)
463 fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_highlight_off());
a035f819
LP
464 if (cgroup)
465 fprintf(file, " Control Group: %s\n", cgroup);
e15758cc
LP
466 if (unit)
467 fprintf(file, " Unit: %s\n", unit);
468 if (user_unit)
469 fprintf(file, " User Unit: %s\n", unit);
a035f819
LP
470 if (slice)
471 fprintf(file, " Slice: %s\n", slice);
e15758cc
LP
472 if (session)
473 fprintf(file, " Session: %s\n", session);
a035f819
LP
474 if (owner_uid) {
475 uid_t n;
476
477 if (parse_uid(owner_uid, &n) >= 0) {
478 _cleanup_free_ char *u = NULL;
479
480 u = uid_to_name(n);
481 fprintf(file,
482 " Owner UID: %s (%s)\n",
483 owner_uid, u);
484 } else {
485 fprintf(file,
486 " Owner UID: %s\n",
487 owner_uid);
488 }
489 }
e15758cc
LP
490 if (boot_id)
491 fprintf(file, " Boot ID: %s\n", boot_id);
492 if (machine_id)
493 fprintf(file, " Machine ID: %s\n", machine_id);
494 if (hostname)
495 fprintf(file, " Hostname: %s\n", hostname);
496
9fe13294
ZJS
497 if (filename && access(filename, F_OK) == 0)
498 fprintf(file, " Coredump: %s\n", filename);
e15758cc 499
8d4e028f
LP
500 if (message) {
501 _cleanup_free_ char *m = NULL;
502
503 m = strreplace(message, "\n", "\n ");
504
505 fprintf(file, " Message: %s\n", strstrip(m ?: message));
506 }
507
e15758cc
LP
508 return 0;
509}
510
ada45c78 511static int focus(sd_journal *j) {
5de0409e
ZJS
512 int r;
513
5de0409e
ZJS
514 r = sd_journal_seek_tail(j);
515 if (r == 0)
516 r = sd_journal_previous(j);
23bbb0de
MS
517 if (r < 0)
518 return log_error_errno(r, "Failed to search journal: %m");
8bc8ab83 519 if (r == 0) {
0c51aada 520 log_error("No match found.");
8bc8ab83
LP
521 return -ESRCH;
522 }
ada45c78
LP
523 return r;
524}
5de0409e 525
0c51aada
LP
526static void print_entry(sd_journal *j, unsigned n_found) {
527 assert(j);
528
529 if (arg_action == ACTION_INFO)
530 print_info(stdout, j, n_found);
531 else if (arg_field)
532 print_field(stdout, j);
533 else
534 print_list(stdout, j, n_found);
535}
536
537static int dump_list(sd_journal *j) {
538 unsigned n_found = 0;
539 int r;
540
541 assert(j);
542
543 /* The coredumps are likely to compressed, and for just
544 * listing them we don't need to decompress them, so let's
545 * pick a fairly low data threshold here */
546 sd_journal_set_data_threshold(j, 4096);
547
548 if (arg_one) {
549 r = focus(j);
550 if (r < 0)
551 return r;
552
553 print_entry(j, 0);
554 } else {
555 SD_JOURNAL_FOREACH(j)
556 print_entry(j, n_found++);
557
558 if (!arg_field && n_found <= 0) {
559 log_notice("No coredumps found.");
560 return -ESRCH;
561 }
562 }
563
564 return 0;
565}
566
9fe13294
ZJS
567static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
568 const char *data;
569 _cleanup_free_ char *filename = NULL;
570 size_t len;
ada45c78
LP
571 int r;
572
9fe13294
ZJS
573 assert((fd >= 0) != !!path);
574 assert(!!path == !!unlink_temp);
ada45c78 575
9fe13294
ZJS
576 /* Prefer uncompressed file to journal (probably cached) to
577 * compressed file (probably uncached). */
578 r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
579 if (r < 0 && r != -ENOENT)
da927ba9 580 log_warning_errno(r, "Failed to retrieve COREDUMP_FILENAME: %m");
9fe13294
ZJS
581 else if (r == 0)
582 retrieve(data, len, "COREDUMP_FILENAME", &filename);
93b73b06 583
9fe13294 584 if (filename && access(filename, R_OK) < 0) {
31cda3d1
ZJS
585 log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
586 "File %s is not readable: %m", filename);
9fe13294
ZJS
587 free(filename);
588 filename = NULL;
5de0409e
ZJS
589 }
590
d89c8fdf 591 if (filename && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) {
d0c8806d
TA
592 if (path) {
593 *path = filename;
594 filename = NULL;
595 }
a276ae74 596
9fe13294
ZJS
597 return 0;
598 } else {
599 _cleanup_close_ int fdt = -1;
600 char *temp = NULL;
a276ae74 601
a276ae74 602 if (fd < 0) {
9fe13294
ZJS
603 temp = strdup("/var/tmp/coredump-XXXXXX");
604 if (!temp)
605 return log_oom();
606
607 fdt = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
4a62c710
MS
608 if (fdt < 0)
609 return log_error_errno(errno, "Failed to create temporary file: %m");
9fe13294
ZJS
610 log_debug("Created temporary file %s", temp);
611
612 fd = fdt;
613 }
614
615 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
616 if (r == 0) {
617 ssize_t sz;
618
619 assert(len >= 9);
620 data += 9;
621 len -= 9;
622
623 sz = write(fdt, data, len);
624 if (sz < 0) {
56f64d95 625 log_error_errno(errno, "Failed to write temporary file: %m");
9fe13294
ZJS
626 r = -errno;
627 goto error;
628 }
629 if (sz != (ssize_t) len) {
630 log_error("Short write to temporary file.");
631 r = -EIO;
632 goto error;
633 }
634 } else if (filename) {
d89c8fdf 635#if defined(HAVE_XZ) || defined(HAVE_LZ4)
9fe13294
ZJS
636 _cleanup_close_ int fdf;
637
638 fdf = open(filename, O_RDONLY | O_CLOEXEC);
639 if (fdf < 0) {
56f64d95 640 log_error_errno(errno, "Failed to open %s: %m", filename);
9fe13294
ZJS
641 r = -errno;
642 goto error;
643 }
644
d89c8fdf 645 r = decompress_stream(filename, fdf, fd, -1);
9fe13294 646 if (r < 0) {
da927ba9 647 log_error_errno(r, "Failed to decompress %s: %m", filename);
9fe13294
ZJS
648 goto error;
649 }
2fb8159f 650#else
d89c8fdf 651 log_error("Cannot decompress file. Compiled without compression support.");
2fb8159f
DM
652 r = -ENOTSUP;
653 goto error;
654#endif
9fe13294
ZJS
655 } else {
656 if (r == -ENOENT)
31cda3d1 657 log_error("Cannot retrieve coredump from journal nor disk.");
a276ae74 658 else
da927ba9 659 log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
9fe13294
ZJS
660 goto error;
661 }
a276ae74 662
9fe13294
ZJS
663 if (temp) {
664 *path = temp;
665 *unlink_temp = true;
a276ae74
LP
666 }
667
9fe13294
ZJS
668 return 0;
669
670error:
671 if (temp) {
672 unlink(temp);
673 log_debug("Removed temporary file %s", temp);
a276ae74 674 }
9fe13294
ZJS
675 return r;
676 }
677}
a276ae74 678
9fe13294
ZJS
679static int dump_core(sd_journal* j) {
680 int r;
681
682 assert(j);
683
684 r = focus(j);
685 if (r < 0)
ada45c78 686 return r;
ada45c78 687
3774cf57 688 print_info(arg_output ? stdout : stderr, j, false);
9fe13294 689
3774cf57 690 if (on_tty() && !arg_output) {
9fe13294
ZJS
691 log_error("Refusing to dump core to tty.");
692 return -ENOTTY;
693 }
694
3774cf57 695 r = save_core(j, arg_output ? fileno(arg_output) : STDOUT_FILENO, NULL, NULL);
23bbb0de
MS
696 if (r < 0)
697 return log_error_errno(r, "Coredump retrieval failed: %m");
5de0409e
ZJS
698
699 r = sd_journal_previous(j);
700 if (r >= 0)
9f6445e3 701 log_warning("More than one entry matches, ignoring rest.");
5de0409e
ZJS
702
703 return 0;
704}
705
ada45c78 706static int run_gdb(sd_journal *j) {
de8f6e54 707 _cleanup_free_ char *exe = NULL, *path = NULL;
9fe13294
ZJS
708 bool unlink_path = false;
709 const char *data;
a276ae74 710 siginfo_t st;
ada45c78 711 size_t len;
ada45c78 712 pid_t pid;
ada45c78 713 int r;
ada45c78
LP
714
715 assert(j);
716
717 r = focus(j);
718 if (r < 0)
719 return r;
720
e15758cc
LP
721 print_info(stdout, j, false);
722 fputs("\n", stdout);
ada45c78
LP
723
724 r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len);
23bbb0de
MS
725 if (r < 0)
726 return log_error_errno(r, "Failed to retrieve COREDUMP_EXE field: %m");
ada45c78 727
9fe13294
ZJS
728 assert(len > strlen("COREDUMP_EXE="));
729 data += strlen("COREDUMP_EXE=");
730 len -= strlen("COREDUMP_EXE=");
ada45c78
LP
731
732 exe = strndup(data, len);
733 if (!exe)
734 return log_oom();
735
736 if (endswith(exe, " (deleted)")) {
737 log_error("Binary already deleted.");
738 return -ENOENT;
739 }
740
a276ae74
LP
741 if (!path_is_absolute(exe)) {
742 log_error("Binary is not an absolute path.");
743 return -ENOENT;
744 }
745
9fe13294 746 r = save_core(j, -1, &path, &unlink_path);
23bbb0de
MS
747 if (r < 0)
748 return log_error_errno(r, "Failed to retrieve core: %m");
ada45c78
LP
749
750 pid = fork();
751 if (pid < 0) {
56f64d95 752 log_error_errno(errno, "Failed to fork(): %m");
ada45c78
LP
753 r = -errno;
754 goto finish;
755 }
756 if (pid == 0) {
757 execlp("gdb", "gdb", exe, path, NULL);
a276ae74 758
56f64d95 759 log_error_errno(errno, "Failed to invoke gdb: %m");
ada45c78
LP
760 _exit(1);
761 }
762
763 r = wait_for_terminate(pid, &st);
764 if (r < 0) {
56f64d95 765 log_error_errno(errno, "Failed to wait for gdb: %m");
ada45c78
LP
766 goto finish;
767 }
768
769 r = st.si_code == CLD_EXITED ? st.si_status : 255;
770
771finish:
9fe13294
ZJS
772 if (unlink_path) {
773 log_debug("Removed temporary file %s", path);
774 unlink(path);
775 }
a276ae74 776
ada45c78
LP
777 return r;
778}
779
5de0409e 780int main(int argc, char *argv[]) {
7fd1b19b 781 _cleanup_journal_close_ sd_journal*j = NULL;
5de0409e
ZJS
782 const char* match;
783 Iterator it;
784 int r = 0;
7fd1b19b 785 _cleanup_set_free_free_ Set *matches = NULL;
5de0409e 786
a9cdc94f 787 setlocale(LC_ALL, "");
5de0409e
ZJS
788 log_parse_environment();
789 log_open();
790
791 matches = new_matches();
2fb7a5ce
ZJS
792 if (!matches) {
793 r = -ENOMEM;
5de0409e 794 goto end;
2fb7a5ce 795 }
5de0409e 796
763c7aa2 797 r = parse_argv(argc, argv, matches);
2fb7a5ce 798 if (r < 0)
5de0409e
ZJS
799 goto end;
800
801 if (arg_action == ACTION_NONE)
802 goto end;
803
2cf4172a
LP
804 sigbus_install();
805
5de0409e
ZJS
806 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
807 if (r < 0) {
da927ba9 808 log_error_errno(r, "Failed to open journal: %m");
5de0409e
ZJS
809 goto end;
810 }
811
9fe13294
ZJS
812 /* We want full data, nothing truncated. */
813 sd_journal_set_data_threshold(j, 0);
814
5de0409e 815 SET_FOREACH(match, matches, it) {
5de0409e
ZJS
816 r = sd_journal_add_match(j, match, strlen(match));
817 if (r != 0) {
c33b3297
MS
818 log_error_errno(r, "Failed to add match '%s': %m",
819 match);
5de0409e
ZJS
820 goto end;
821 }
822 }
823
553d2243 824 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
6c17bf04
ZJS
825 _cleanup_free_ char *filter;
826
827 filter = journal_make_match_string(j);
828 log_debug("Journal filter: %s", filter);
829 }
830
5de0409e 831 switch(arg_action) {
ada45c78 832
5de0409e 833 case ACTION_LIST:
e15758cc 834 case ACTION_INFO:
5de0409e 835 if (!arg_no_pager)
1b12a7b5 836 pager_open(false);
5de0409e
ZJS
837
838 r = dump_list(j);
839 break;
ada45c78 840
5de0409e
ZJS
841 case ACTION_DUMP:
842 r = dump_core(j);
843 break;
ada45c78
LP
844
845 case ACTION_GDB:
846 r = run_gdb(j);
847 break;
848
849 default:
5de0409e
ZJS
850 assert_not_reached("Shouldn't be here");
851 }
852
853end:
5de0409e
ZJS
854 pager_close();
855
3774cf57
LP
856 if (arg_output)
857 fclose(arg_output);
5de0409e 858
ada45c78 859 return r >= 0 ? r : EXIT_FAILURE;
5de0409e 860}