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