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