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