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