]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/coredumpctl.c
journal: add LZ4 as optional compressor
[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_put(set, pattern);
135 if (r < 0) {
136 log_error("Failed to add pattern '%s': %s",
137 pattern, strerror(-r));
138 free(pattern);
139 goto fail;
140 }
141
142 return 0;
143 fail:
144 log_error("Failed to add match: %s", strerror(-r));
145 return r;
146 }
147
148 static int parse_argv(int argc, char *argv[], Set *matches) {
149 enum {
150 ARG_VERSION = 0x100,
151 ARG_NO_PAGER,
152 ARG_NO_LEGEND,
153 };
154
155 int r, c;
156
157 static const struct option options[] = {
158 { "help", no_argument, NULL, 'h' },
159 { "version" , no_argument, NULL, ARG_VERSION },
160 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
161 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
162 { "output", required_argument, NULL, 'o' },
163 { "field", required_argument, NULL, 'F' },
164 {}
165 };
166
167 assert(argc >= 0);
168 assert(argv);
169
170 while ((c = getopt_long(argc, argv, "ho:F:1", options, NULL)) >= 0)
171 switch(c) {
172
173 case 'h':
174 arg_action = ACTION_NONE;
175 return help();
176
177 case ARG_VERSION:
178 arg_action = ACTION_NONE;
179 puts(PACKAGE_STRING);
180 puts(SYSTEMD_FEATURES);
181 return 0;
182
183 case ARG_NO_PAGER:
184 arg_no_pager = true;
185 break;
186
187 case ARG_NO_LEGEND:
188 arg_no_legend = true;
189 break;
190
191 case 'o':
192 if (output) {
193 log_error("cannot set output more than once");
194 return -EINVAL;
195 }
196
197 output = fopen(optarg, "we");
198 if (!output) {
199 log_error("writing to '%s': %m", optarg);
200 return -errno;
201 }
202
203 break;
204
205 case 'F':
206 if (arg_field) {
207 log_error("cannot use --field/-F more than once");
208 return -EINVAL;
209 }
210 arg_field = optarg;
211 break;
212
213 case '1':
214 arg_one = true;
215 break;
216
217 case '?':
218 return -EINVAL;
219
220 default:
221 assert_not_reached("Unhandled option");
222 }
223
224 if (optind < argc) {
225 const char *cmd = argv[optind++];
226 if (streq(cmd, "list"))
227 arg_action = ACTION_LIST;
228 else if (streq(cmd, "dump"))
229 arg_action = ACTION_DUMP;
230 else if (streq(cmd, "gdb"))
231 arg_action = ACTION_GDB;
232 else if (streq(cmd, "info"))
233 arg_action = ACTION_INFO;
234 else {
235 log_error("Unknown action '%s'", cmd);
236 return -EINVAL;
237 }
238 }
239
240 if (arg_field && arg_action != ACTION_LIST) {
241 log_error("Option --field/-F only makes sense with list");
242 return -EINVAL;
243 }
244
245 while (optind < argc) {
246 r = add_match(matches, argv[optind]);
247 if (r != 0)
248 return r;
249 optind++;
250 }
251
252 return 0;
253 }
254
255 static int retrieve(const void *data,
256 size_t len,
257 const char *name,
258 char **var) {
259
260 size_t ident;
261 char *v;
262
263 ident = strlen(name) + 1; /* name + "=" */
264
265 if (len < ident)
266 return 0;
267
268 if (memcmp(data, name, ident - 1) != 0)
269 return 0;
270
271 if (((const char*) data)[ident - 1] != '=')
272 return 0;
273
274 v = strndup((const char*)data + ident, len - ident);
275 if (!v)
276 return log_oom();
277
278 free(*var);
279 *var = v;
280
281 return 0;
282 }
283
284 static void print_field(FILE* file, sd_journal *j) {
285 _cleanup_free_ char *value = NULL;
286 const void *d;
287 size_t l;
288
289 assert(file);
290 assert(j);
291
292 assert(arg_field);
293
294 SD_JOURNAL_FOREACH_DATA(j, d, l)
295 retrieve(d, l, arg_field, &value);
296
297 if (value)
298 fprintf(file, "%s\n", value);
299 }
300
301 static int print_list(FILE* file, sd_journal *j, int had_legend) {
302 _cleanup_free_ char
303 *pid = NULL, *uid = NULL, *gid = NULL,
304 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
305 *filename = NULL;
306 const void *d;
307 size_t l;
308 usec_t t;
309 char buf[FORMAT_TIMESTAMP_MAX];
310 int r;
311 bool present;
312
313 assert(file);
314 assert(j);
315
316 SD_JOURNAL_FOREACH_DATA(j, d, l) {
317 retrieve(d, l, "COREDUMP_PID", &pid);
318 retrieve(d, l, "COREDUMP_UID", &uid);
319 retrieve(d, l, "COREDUMP_GID", &gid);
320 retrieve(d, l, "COREDUMP_SIGNAL", &sgnl);
321 retrieve(d, l, "COREDUMP_EXE", &exe);
322 retrieve(d, l, "COREDUMP_COMM", &comm);
323 retrieve(d, l, "COREDUMP_CMDLINE", &cmdline);
324 retrieve(d, l, "COREDUMP_FILENAME", &filename);
325 }
326
327 if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) {
328 log_warning("Empty coredump log entry");
329 return -EINVAL;
330 }
331
332 r = sd_journal_get_realtime_usec(j, &t);
333 if (r < 0) {
334 log_error("Failed to get realtime timestamp: %s", strerror(-r));
335 return r;
336 }
337
338 format_timestamp(buf, sizeof(buf), t);
339 present = filename && access(filename, F_OK) == 0;
340
341 if (!had_legend && !arg_no_legend)
342 fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n",
343 FORMAT_TIMESTAMP_WIDTH, "TIME",
344 6, "PID",
345 5, "UID",
346 5, "GID",
347 3, "SIG",
348 1, "PRESENT",
349 "EXE");
350
351 fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n",
352 FORMAT_TIMESTAMP_WIDTH, buf,
353 6, strna(pid),
354 5, strna(uid),
355 5, strna(gid),
356 3, strna(sgnl),
357 1, present ? "*" : "",
358 strna(exe ?: (comm ?: cmdline)));
359
360 return 0;
361 }
362
363 static int print_info(FILE *file, sd_journal *j, bool need_space) {
364 _cleanup_free_ char
365 *pid = NULL, *uid = NULL, *gid = NULL,
366 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
367 *unit = NULL, *user_unit = NULL, *session = NULL,
368 *boot_id = NULL, *machine_id = NULL, *hostname = NULL,
369 *slice = NULL, *cgroup = NULL, *owner_uid = NULL,
370 *message = NULL, *timestamp = NULL, *filename = NULL;
371 const void *d;
372 size_t l;
373 int r;
374
375 assert(file);
376 assert(j);
377
378 SD_JOURNAL_FOREACH_DATA(j, d, l) {
379 retrieve(d, l, "COREDUMP_PID", &pid);
380 retrieve(d, l, "COREDUMP_UID", &uid);
381 retrieve(d, l, "COREDUMP_GID", &gid);
382 retrieve(d, l, "COREDUMP_SIGNAL", &sgnl);
383 retrieve(d, l, "COREDUMP_EXE", &exe);
384 retrieve(d, l, "COREDUMP_COMM", &comm);
385 retrieve(d, l, "COREDUMP_CMDLINE", &cmdline);
386 retrieve(d, l, "COREDUMP_UNIT", &unit);
387 retrieve(d, l, "COREDUMP_USER_UNIT", &user_unit);
388 retrieve(d, l, "COREDUMP_SESSION", &session);
389 retrieve(d, l, "COREDUMP_OWNER_UID", &owner_uid);
390 retrieve(d, l, "COREDUMP_SLICE", &slice);
391 retrieve(d, l, "COREDUMP_CGROUP", &cgroup);
392 retrieve(d, l, "COREDUMP_TIMESTAMP", &timestamp);
393 retrieve(d, l, "COREDUMP_FILENAME", &filename);
394 retrieve(d, l, "_BOOT_ID", &boot_id);
395 retrieve(d, l, "_MACHINE_ID", &machine_id);
396 retrieve(d, l, "_HOSTNAME", &hostname);
397 retrieve(d, l, "MESSAGE", &message);
398 }
399
400 if (need_space)
401 fputs("\n", file);
402
403 if (comm)
404 fprintf(file,
405 " PID: %s%s%s (%s)\n",
406 ansi_highlight(), strna(pid), ansi_highlight_off(), comm);
407 else
408 fprintf(file,
409 " PID: %s%s%s\n",
410 ansi_highlight(), strna(pid), ansi_highlight_off());
411
412 if (uid) {
413 uid_t n;
414
415 if (parse_uid(uid, &n) >= 0) {
416 _cleanup_free_ char *u = NULL;
417
418 u = uid_to_name(n);
419 fprintf(file,
420 " UID: %s (%s)\n",
421 uid, u);
422 } else {
423 fprintf(file,
424 " UID: %s\n",
425 uid);
426 }
427 }
428
429 if (gid) {
430 gid_t n;
431
432 if (parse_gid(gid, &n) >= 0) {
433 _cleanup_free_ char *g = NULL;
434
435 g = gid_to_name(n);
436 fprintf(file,
437 " GID: %s (%s)\n",
438 gid, g);
439 } else {
440 fprintf(file,
441 " GID: %s\n",
442 gid);
443 }
444 }
445
446 if (sgnl) {
447 int sig;
448
449 if (safe_atoi(sgnl, &sig) >= 0)
450 fprintf(file, " Signal: %s (%s)\n", sgnl, signal_to_string(sig));
451 else
452 fprintf(file, " Signal: %s\n", sgnl);
453 }
454
455 if (timestamp) {
456 usec_t u;
457
458 r = safe_atou64(timestamp, &u);
459 if (r >= 0) {
460 char absolute[FORMAT_TIMESTAMP_MAX], relative[FORMAT_TIMESPAN_MAX];
461
462 fprintf(file,
463 " Timestamp: %s (%s)\n",
464 format_timestamp(absolute, sizeof(absolute), u),
465 format_timestamp_relative(relative, sizeof(relative), u));
466
467 } else
468 fprintf(file, " Timestamp: %s\n", timestamp);
469 }
470
471 if (cmdline)
472 fprintf(file, " Command Line: %s\n", cmdline);
473 if (exe)
474 fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_highlight_off());
475 if (cgroup)
476 fprintf(file, " Control Group: %s\n", cgroup);
477 if (unit)
478 fprintf(file, " Unit: %s\n", unit);
479 if (user_unit)
480 fprintf(file, " User Unit: %s\n", unit);
481 if (slice)
482 fprintf(file, " Slice: %s\n", slice);
483 if (session)
484 fprintf(file, " Session: %s\n", session);
485 if (owner_uid) {
486 uid_t n;
487
488 if (parse_uid(owner_uid, &n) >= 0) {
489 _cleanup_free_ char *u = NULL;
490
491 u = uid_to_name(n);
492 fprintf(file,
493 " Owner UID: %s (%s)\n",
494 owner_uid, u);
495 } else {
496 fprintf(file,
497 " Owner UID: %s\n",
498 owner_uid);
499 }
500 }
501 if (boot_id)
502 fprintf(file, " Boot ID: %s\n", boot_id);
503 if (machine_id)
504 fprintf(file, " Machine ID: %s\n", machine_id);
505 if (hostname)
506 fprintf(file, " Hostname: %s\n", hostname);
507
508 if (filename && access(filename, F_OK) == 0)
509 fprintf(file, " Coredump: %s\n", filename);
510
511 if (message) {
512 _cleanup_free_ char *m = NULL;
513
514 m = strreplace(message, "\n", "\n ");
515
516 fprintf(file, " Message: %s\n", strstrip(m ?: message));
517 }
518
519 return 0;
520 }
521
522 static int focus(sd_journal *j) {
523 int r;
524
525 r = sd_journal_seek_tail(j);
526 if (r == 0)
527 r = sd_journal_previous(j);
528 if (r < 0) {
529 log_error("Failed to search journal: %s", strerror(-r));
530 return r;
531 }
532 if (r == 0) {
533 log_error("No match found.");
534 return -ESRCH;
535 }
536 return r;
537 }
538
539 static void print_entry(sd_journal *j, unsigned n_found) {
540 assert(j);
541
542 if (arg_action == ACTION_INFO)
543 print_info(stdout, j, n_found);
544 else if (arg_field)
545 print_field(stdout, j);
546 else
547 print_list(stdout, j, n_found);
548 }
549
550 static int dump_list(sd_journal *j) {
551 unsigned n_found = 0;
552 int r;
553
554 assert(j);
555
556 /* The coredumps are likely to compressed, and for just
557 * listing them we don't need to decompress them, so let's
558 * pick a fairly low data threshold here */
559 sd_journal_set_data_threshold(j, 4096);
560
561 if (arg_one) {
562 r = focus(j);
563 if (r < 0)
564 return r;
565
566 print_entry(j, 0);
567 } else {
568 SD_JOURNAL_FOREACH(j)
569 print_entry(j, n_found++);
570
571 if (!arg_field && n_found <= 0) {
572 log_notice("No coredumps found.");
573 return -ESRCH;
574 }
575 }
576
577 return 0;
578 }
579
580 static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
581 const char *data;
582 _cleanup_free_ char *filename = NULL;
583 size_t len;
584 int r;
585
586 assert((fd >= 0) != !!path);
587 assert(!!path == !!unlink_temp);
588
589 /* Prefer uncompressed file to journal (probably cached) to
590 * compressed file (probably uncached). */
591 r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
592 if (r < 0 && r != -ENOENT)
593 log_warning("Failed to retrieve COREDUMP_FILENAME: %s", strerror(-r));
594 else if (r == 0)
595 retrieve(data, len, "COREDUMP_FILENAME", &filename);
596
597 if (filename && access(filename, R_OK) < 0) {
598 log_debug("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("Coredump neither in journal file nor stored externally on 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 }