]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/coredump/coredumpctl.c
Merge pull request #2589 from keszybz/resolve-tool-2
[thirdparty/systemd.git] / src / coredump / coredumpctl.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2012 Zbigniew Jędrzejewski-Szmek
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <locale.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "sd-journal.h"
28
29 #include "alloc-util.h"
30 #include "compress.h"
31 #include "fd-util.h"
32 #include "fileio.h"
33 #include "journal-internal.h"
34 #include "log.h"
35 #include "macro.h"
36 #include "pager.h"
37 #include "parse-util.h"
38 #include "path-util.h"
39 #include "process-util.h"
40 #include "set.h"
41 #include "sigbus.h"
42 #include "signal-util.h"
43 #include "string-util.h"
44 #include "terminal-util.h"
45 #include "user-util.h"
46 #include "util.h"
47
48 static enum {
49 ACTION_NONE,
50 ACTION_INFO,
51 ACTION_LIST,
52 ACTION_DUMP,
53 ACTION_GDB,
54 } arg_action = ACTION_LIST;
55 static const char* arg_field = NULL;
56 static const char *arg_directory = NULL;
57 static int arg_no_pager = false;
58 static int arg_no_legend = false;
59 static int arg_one = false;
60 static FILE* arg_output = NULL;
61
62 static Set *new_matches(void) {
63 Set *set;
64 char *tmp;
65 int r;
66
67 set = set_new(NULL);
68 if (!set) {
69 log_oom();
70 return NULL;
71 }
72
73 tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
74 if (!tmp) {
75 log_oom();
76 set_free(set);
77 return NULL;
78 }
79
80 r = set_consume(set, tmp);
81 if (r < 0) {
82 log_error_errno(r, "failed to add to set: %m");
83 set_free(set);
84 return NULL;
85 }
86
87 return set;
88 }
89
90 static int add_match(Set *set, const char *match) {
91 _cleanup_free_ char *p = NULL;
92 char *pattern = NULL;
93 const char* prefix;
94 pid_t pid;
95 int r;
96
97 if (strchr(match, '='))
98 prefix = "";
99 else if (strchr(match, '/')) {
100 r = path_make_absolute_cwd(match, &p);
101 if (r < 0)
102 goto fail;
103 match = p;
104 prefix = "COREDUMP_EXE=";
105 } else if (parse_pid(match, &pid) >= 0)
106 prefix = "COREDUMP_PID=";
107 else
108 prefix = "COREDUMP_COMM=";
109
110 pattern = strjoin(prefix, match, NULL);
111 if (!pattern) {
112 r = -ENOMEM;
113 goto fail;
114 }
115
116 log_debug("Adding pattern: %s", pattern);
117 r = set_consume(set, pattern);
118 if (r < 0)
119 goto fail;
120
121 return 0;
122 fail:
123 return log_error_errno(r, "Failed to add match: %m");
124 }
125
126 static void help(void) {
127 printf("%s [OPTIONS...]\n\n"
128 "List or retrieve coredumps from the journal.\n\n"
129 "Flags:\n"
130 " -h --help Show this help\n"
131 " --version Print version string\n"
132 " --no-pager Do not pipe output into a pager\n"
133 " --no-legend Do not print the column headers.\n"
134 " -1 Show information about most recent entry only\n"
135 " -F --field=FIELD List all values a certain field takes\n"
136 " -o --output=FILE Write output to FILE\n\n"
137 " -D --directory=DIR Use journal files from directory\n\n"
138
139 "Commands:\n"
140 " list [MATCHES...] List available coredumps (default)\n"
141 " info [MATCHES...] Show detailed information about one or more coredumps\n"
142 " dump [MATCHES...] Print first matching coredump to stdout\n"
143 " gdb [MATCHES...] Start gdb for the first matching coredump\n"
144 , program_invocation_short_name);
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 { "directory", required_argument, NULL, 'D' },
164 {}
165 };
166
167 assert(argc >= 0);
168 assert(argv);
169
170 while ((c = getopt_long(argc, argv, "ho:F:1D:", options, NULL)) >= 0)
171 switch(c) {
172
173 case 'h':
174 arg_action = ACTION_NONE;
175 help();
176 return 0;
177
178 case ARG_VERSION:
179 arg_action = ACTION_NONE;
180 return version();
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 (arg_output) {
192 log_error("cannot set output more than once");
193 return -EINVAL;
194 }
195
196 arg_output = fopen(optarg, "we");
197 if (!arg_output)
198 return log_error_errno(errno, "writing to '%s': %m", optarg);
199
200 break;
201
202 case 'F':
203 if (arg_field) {
204 log_error("cannot use --field/-F more than once");
205 return -EINVAL;
206 }
207 arg_field = optarg;
208 break;
209
210 case '1':
211 arg_one = true;
212 break;
213
214 case 'D':
215 arg_directory = optarg;
216 break;
217
218 case '?':
219 return -EINVAL;
220
221 default:
222 assert_not_reached("Unhandled option");
223 }
224
225 if (optind < argc) {
226 const char *cmd = argv[optind++];
227 if (streq(cmd, "list"))
228 arg_action = ACTION_LIST;
229 else if (streq(cmd, "dump"))
230 arg_action = ACTION_DUMP;
231 else if (streq(cmd, "gdb"))
232 arg_action = ACTION_GDB;
233 else if (streq(cmd, "info"))
234 arg_action = ACTION_INFO;
235 else {
236 log_error("Unknown action '%s'", cmd);
237 return -EINVAL;
238 }
239 }
240
241 if (arg_field && arg_action != ACTION_LIST) {
242 log_error("Option --field/-F only makes sense with list");
243 return -EINVAL;
244 }
245
246 while (optind < argc) {
247 r = add_match(matches, argv[optind]);
248 if (r != 0)
249 return r;
250 optind++;
251 }
252
253 return 0;
254 }
255
256 static int retrieve(const void *data,
257 size_t len,
258 const char *name,
259 char **var) {
260
261 size_t ident;
262 char *v;
263
264 ident = strlen(name) + 1; /* name + "=" */
265
266 if (len < ident)
267 return 0;
268
269 if (memcmp(data, name, ident - 1) != 0)
270 return 0;
271
272 if (((const char*) data)[ident - 1] != '=')
273 return 0;
274
275 v = strndup((const char*)data + ident, len - ident);
276 if (!v)
277 return log_oom();
278
279 free(*var);
280 *var = v;
281
282 return 0;
283 }
284
285 static void print_field(FILE* file, sd_journal *j) {
286 _cleanup_free_ char *value = NULL;
287 const void *d;
288 size_t l;
289
290 assert(file);
291 assert(j);
292
293 assert(arg_field);
294
295 SD_JOURNAL_FOREACH_DATA(j, d, l)
296 retrieve(d, l, arg_field, &value);
297
298 if (value)
299 fprintf(file, "%s\n", value);
300 }
301
302 static int print_list(FILE* file, sd_journal *j, int had_legend) {
303 _cleanup_free_ char
304 *pid = NULL, *uid = NULL, *gid = NULL,
305 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
306 *filename = NULL;
307 const void *d;
308 size_t l;
309 usec_t t;
310 char buf[FORMAT_TIMESTAMP_MAX];
311 int r;
312 bool present;
313
314 assert(file);
315 assert(j);
316
317 SD_JOURNAL_FOREACH_DATA(j, d, l) {
318 retrieve(d, l, "COREDUMP_PID", &pid);
319 retrieve(d, l, "COREDUMP_UID", &uid);
320 retrieve(d, l, "COREDUMP_GID", &gid);
321 retrieve(d, l, "COREDUMP_SIGNAL", &sgnl);
322 retrieve(d, l, "COREDUMP_EXE", &exe);
323 retrieve(d, l, "COREDUMP_COMM", &comm);
324 retrieve(d, l, "COREDUMP_CMDLINE", &cmdline);
325 retrieve(d, l, "COREDUMP_FILENAME", &filename);
326 }
327
328 if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) {
329 log_warning("Empty coredump log entry");
330 return -EINVAL;
331 }
332
333 r = sd_journal_get_realtime_usec(j, &t);
334 if (r < 0)
335 return log_error_errno(r, "Failed to get realtime timestamp: %m");
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_normal(), comm);
406 else
407 fprintf(file,
408 " PID: %s%s%s\n",
409 ansi_highlight(), strna(pid), ansi_normal());
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_normal());
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 return log_error_errno(r, "Failed to search journal: %m");
529 if (r == 0) {
530 log_error("No match found.");
531 return -ESRCH;
532 }
533 return r;
534 }
535
536 static void print_entry(sd_journal *j, unsigned n_found) {
537 assert(j);
538
539 if (arg_action == ACTION_INFO)
540 print_info(stdout, j, n_found);
541 else if (arg_field)
542 print_field(stdout, j);
543 else
544 print_list(stdout, j, n_found);
545 }
546
547 static int dump_list(sd_journal *j) {
548 unsigned n_found = 0;
549 int r;
550
551 assert(j);
552
553 /* The coredumps are likely to compressed, and for just
554 * listing them we don't need to decompress them, so let's
555 * pick a fairly low data threshold here */
556 sd_journal_set_data_threshold(j, 4096);
557
558 if (arg_one) {
559 r = focus(j);
560 if (r < 0)
561 return r;
562
563 print_entry(j, 0);
564 } else {
565 SD_JOURNAL_FOREACH(j)
566 print_entry(j, n_found++);
567
568 if (!arg_field && n_found <= 0) {
569 log_notice("No coredumps found.");
570 return -ESRCH;
571 }
572 }
573
574 return 0;
575 }
576
577 static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
578 const char *data;
579 _cleanup_free_ char *filename = NULL;
580 size_t len;
581 int r;
582
583 assert((fd >= 0) != !!path);
584 assert(!!path == !!unlink_temp);
585
586 /* Prefer uncompressed file to journal (probably cached) to
587 * compressed file (probably uncached). */
588 r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
589 if (r < 0 && r != -ENOENT)
590 log_warning_errno(r, "Failed to retrieve COREDUMP_FILENAME: %m");
591 else if (r == 0)
592 retrieve(data, len, "COREDUMP_FILENAME", &filename);
593
594 if (filename && access(filename, R_OK) < 0) {
595 log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
596 "File %s is not readable: %m", filename);
597 filename = mfree(filename);
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 return log_error_errno(fdt, "Failed to create temporary file: %m");
619 log_debug("Created temporary file %s", temp);
620
621 fd = fdt;
622 }
623
624 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
625 if (r == 0) {
626 ssize_t sz;
627
628 assert(len >= 9);
629 data += 9;
630 len -= 9;
631
632 sz = write(fdt, data, len);
633 if (sz < 0) {
634 r = log_error_errno(errno,
635 "Failed to write temporary file: %m");
636 goto error;
637 }
638 if (sz != (ssize_t) len) {
639 log_error("Short write to temporary file.");
640 r = -EIO;
641 goto error;
642 }
643 } else if (filename) {
644 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
645 _cleanup_close_ int fdf;
646
647 fdf = open(filename, O_RDONLY | O_CLOEXEC);
648 if (fdf < 0) {
649 r = log_error_errno(errno,
650 "Failed to open %s: %m",
651 filename);
652 goto error;
653 }
654
655 r = decompress_stream(filename, fdf, fd, -1);
656 if (r < 0) {
657 log_error_errno(r, "Failed to decompress %s: %m", filename);
658 goto error;
659 }
660 #else
661 log_error("Cannot decompress file. Compiled without compression support.");
662 r = -EOPNOTSUPP;
663 goto error;
664 #endif
665 } else {
666 if (r == -ENOENT)
667 log_error("Cannot retrieve coredump from journal nor disk.");
668 else
669 log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
670 goto error;
671 }
672
673 if (temp) {
674 *path = temp;
675 *unlink_temp = true;
676 }
677
678 return 0;
679
680 error:
681 if (temp) {
682 unlink(temp);
683 log_debug("Removed temporary file %s", temp);
684 }
685 return r;
686 }
687 }
688
689 static int dump_core(sd_journal* j) {
690 int r;
691
692 assert(j);
693
694 r = focus(j);
695 if (r < 0)
696 return r;
697
698 print_info(arg_output ? stdout : stderr, j, false);
699
700 if (on_tty() && !arg_output) {
701 log_error("Refusing to dump core to tty.");
702 return -ENOTTY;
703 }
704
705 r = save_core(j, arg_output ? fileno(arg_output) : STDOUT_FILENO, NULL, NULL);
706 if (r < 0)
707 return log_error_errno(r, "Coredump retrieval failed: %m");
708
709 r = sd_journal_previous(j);
710 if (r >= 0)
711 log_warning("More than one entry matches, ignoring rest.");
712
713 return 0;
714 }
715
716 static int run_gdb(sd_journal *j) {
717 _cleanup_free_ char *exe = NULL, *path = NULL;
718 bool unlink_path = false;
719 const char *data;
720 siginfo_t st;
721 size_t len;
722 pid_t pid;
723 int r;
724
725 assert(j);
726
727 r = focus(j);
728 if (r < 0)
729 return r;
730
731 print_info(stdout, j, false);
732 fputs("\n", stdout);
733
734 r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len);
735 if (r < 0)
736 return log_error_errno(r, "Failed to retrieve COREDUMP_EXE field: %m");
737
738 assert(len > strlen("COREDUMP_EXE="));
739 data += strlen("COREDUMP_EXE=");
740 len -= strlen("COREDUMP_EXE=");
741
742 exe = strndup(data, len);
743 if (!exe)
744 return log_oom();
745
746 if (endswith(exe, " (deleted)")) {
747 log_error("Binary already deleted.");
748 return -ENOENT;
749 }
750
751 if (!path_is_absolute(exe)) {
752 log_error("Binary is not an absolute path.");
753 return -ENOENT;
754 }
755
756 r = save_core(j, -1, &path, &unlink_path);
757 if (r < 0)
758 return log_error_errno(r, "Failed to retrieve core: %m");
759
760 pid = fork();
761 if (pid < 0) {
762 r = log_error_errno(errno, "Failed to fork(): %m");
763 goto finish;
764 }
765 if (pid == 0) {
766 (void) reset_all_signal_handlers();
767 (void) reset_signal_mask();
768
769 execlp("gdb", "gdb", exe, path, NULL);
770
771 log_error_errno(errno, "Failed to invoke gdb: %m");
772 _exit(1);
773 }
774
775 r = wait_for_terminate(pid, &st);
776 if (r < 0) {
777 log_error_errno(r, "Failed to wait for gdb: %m");
778 goto finish;
779 }
780
781 r = st.si_code == CLD_EXITED ? st.si_status : 255;
782
783 finish:
784 if (unlink_path) {
785 log_debug("Removed temporary file %s", path);
786 unlink(path);
787 }
788
789 return r;
790 }
791
792 int main(int argc, char *argv[]) {
793 _cleanup_(sd_journal_closep) sd_journal*j = NULL;
794 const char* match;
795 Iterator it;
796 int r = 0;
797 _cleanup_set_free_free_ Set *matches = NULL;
798
799 setlocale(LC_ALL, "");
800 log_parse_environment();
801 log_open();
802
803 matches = new_matches();
804 if (!matches) {
805 r = -ENOMEM;
806 goto end;
807 }
808
809 r = parse_argv(argc, argv, matches);
810 if (r < 0)
811 goto end;
812
813 if (arg_action == ACTION_NONE)
814 goto end;
815
816 sigbus_install();
817
818 if (arg_directory) {
819 r = sd_journal_open_directory(&j, arg_directory, 0);
820 if (r < 0) {
821 log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory);
822 goto end;
823 }
824 } else {
825 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
826 if (r < 0) {
827 log_error_errno(r, "Failed to open journal: %m");
828 goto end;
829 }
830 }
831
832 /* We want full data, nothing truncated. */
833 sd_journal_set_data_threshold(j, 0);
834
835 SET_FOREACH(match, matches, it) {
836 r = sd_journal_add_match(j, match, strlen(match));
837 if (r != 0) {
838 log_error_errno(r, "Failed to add match '%s': %m",
839 match);
840 goto end;
841 }
842 }
843
844 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
845 _cleanup_free_ char *filter;
846
847 filter = journal_make_match_string(j);
848 log_debug("Journal filter: %s", filter);
849 }
850
851 switch(arg_action) {
852
853 case ACTION_LIST:
854 case ACTION_INFO:
855 if (!arg_no_pager)
856 pager_open(false);
857
858 r = dump_list(j);
859 break;
860
861 case ACTION_DUMP:
862 r = dump_core(j);
863 break;
864
865 case ACTION_GDB:
866 r = run_gdb(j);
867 break;
868
869 default:
870 assert_not_reached("Shouldn't be here");
871 }
872
873 end:
874 pager_close();
875
876 if (arg_output)
877 fclose(arg_output);
878
879 return r >= 0 ? r : EXIT_FAILURE;
880 }