chiark / gitweb /
remove unused includes
[elogind.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 = -ENOTSUP;
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 }