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