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