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