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