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