2 This file is part of systemd.
4 Copyright 2012 Zbigniew Jędrzejewski-Szmek
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.
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.
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/>.
28 #include "sd-journal.h"
29 #include "sd-messages.h"
31 #include "alloc-util.h"
32 #include "bus-error.h"
38 #include "journal-internal.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "process-util.h"
46 #include "signal-util.h"
47 #include "string-util.h"
49 #include "terminal-util.h"
50 #include "user-util.h"
59 } arg_action
= ACTION_LIST
;
60 static const char* arg_field
= NULL
;
61 static const char *arg_directory
= NULL
;
62 static bool arg_no_pager
= false;
63 static int arg_no_legend
= false;
64 static int arg_one
= false;
65 static FILE* arg_output
= NULL
;
66 static bool arg_reverse
= false;
67 static char** arg_matches
= NULL
;
69 static int add_match(sd_journal
*j
, const char *match
) {
70 _cleanup_free_
char *p
= NULL
;
76 if (strchr(match
, '='))
78 else if (strchr(match
, '/')) {
79 r
= path_make_absolute_cwd(match
, &p
);
81 return log_error_errno(r
, "path_make_absolute_cwd(\"%s\"): %m", match
);
84 prefix
= "COREDUMP_EXE=";
85 } else if (parse_pid(match
, &pid
) >= 0)
86 prefix
= "COREDUMP_PID=";
88 prefix
= "COREDUMP_COMM=";
90 pattern
= strjoin(prefix
, match
);
94 log_debug("Adding match: %s", pattern
);
95 r
= sd_journal_add_match(j
, pattern
, 0);
97 return log_error_errno(r
, "Failed to add match \"%s\": %m", match
);
101 static int add_matches(sd_journal
*j
) {
105 r
= sd_journal_add_match(j
, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR
, 0);
107 return log_error_errno(r
, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR
);
109 r
= sd_journal_add_match(j
, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR
, 0);
111 return log_error_errno(r
, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR
);
113 STRV_FOREACH(match
, arg_matches
) {
114 r
= add_match(j
, *match
);
122 static void help(void) {
123 printf("%s [OPTIONS...]\n\n"
124 "List or retrieve coredumps from the journal.\n\n"
126 " -h --help Show this help\n"
127 " --version Print version string\n"
128 " --no-pager Do not pipe output into a pager\n"
129 " --no-legend Do not print the column headers.\n"
130 " -1 Show information about most recent entry only\n"
131 " -r --reverse Show the newest entries first\n"
132 " -F --field=FIELD List all values a certain field takes\n"
133 " -o --output=FILE Write output to FILE\n"
134 " -D --directory=DIR Use journal files from directory\n\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
);
144 static int parse_argv(int argc
, char *argv
[]) {
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 { "reverse", no_argument
, NULL
, 'r' },
168 while ((c
= getopt_long(argc
, argv
, "ho:F:1D:r", options
, NULL
)) >= 0)
172 arg_action
= ACTION_NONE
;
177 arg_action
= ACTION_NONE
;
185 arg_no_legend
= true;
190 log_error("cannot set output more than once");
194 arg_output
= fopen(optarg
, "we");
196 return log_error_errno(errno
, "writing to '%s': %m", optarg
);
202 log_error("cannot use --field/-F more than once");
213 arg_directory
= optarg
;
224 assert_not_reached("Unhandled option");
228 const char *cmd
= argv
[optind
++];
229 if (streq(cmd
, "list"))
230 arg_action
= ACTION_LIST
;
231 else if (streq(cmd
, "dump"))
232 arg_action
= ACTION_DUMP
;
233 else if (streq(cmd
, "gdb"))
234 arg_action
= ACTION_GDB
;
235 else if (streq(cmd
, "info"))
236 arg_action
= ACTION_INFO
;
238 log_error("Unknown action '%s'", cmd
);
243 if (arg_field
&& arg_action
!= ACTION_LIST
) {
244 log_error("Option --field/-F only makes sense with list");
249 arg_matches
= argv
+ optind
;
254 static int retrieve(const void *data
,
262 ident
= strlen(name
) + 1; /* name + "=" */
267 if (memcmp(data
, name
, ident
- 1) != 0)
270 if (((const char*) data
)[ident
- 1] != '=')
273 v
= strndup((const char*)data
+ ident
, len
- ident
);
283 static int print_field(FILE* file
, sd_journal
*j
) {
292 /* A (user-specified) field may appear more than once for a given entry.
293 * We will print all of the occurences.
294 * This is different below for fields that systemd-coredump uses,
295 * because they cannot meaningfully appear more than once.
297 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
298 _cleanup_free_
char *value
= NULL
;
301 r
= retrieve(d
, l
, arg_field
, &value
);
305 fprintf(file
, "%s\n", value
);
311 #define RETRIEVE(d, l, name, arg) \
313 int _r = retrieve(d, l, name, &arg); \
320 static int print_list(FILE* file
, sd_journal
*j
, int had_legend
) {
322 *mid
= NULL
, *pid
= NULL
, *uid
= NULL
, *gid
= NULL
,
323 *sgnl
= NULL
, *exe
= NULL
, *comm
= NULL
, *cmdline
= NULL
,
324 *filename
= NULL
, *coredump
= NULL
;
328 char buf
[FORMAT_TIMESTAMP_MAX
];
331 bool normal_coredump
;
336 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
337 RETRIEVE(d
, l
, "MESSAGE_ID", mid
);
338 RETRIEVE(d
, l
, "COREDUMP_PID", pid
);
339 RETRIEVE(d
, l
, "COREDUMP_UID", uid
);
340 RETRIEVE(d
, l
, "COREDUMP_GID", gid
);
341 RETRIEVE(d
, l
, "COREDUMP_SIGNAL", sgnl
);
342 RETRIEVE(d
, l
, "COREDUMP_EXE", exe
);
343 RETRIEVE(d
, l
, "COREDUMP_COMM", comm
);
344 RETRIEVE(d
, l
, "COREDUMP_CMDLINE", cmdline
);
345 RETRIEVE(d
, l
, "COREDUMP_FILENAME", filename
);
346 RETRIEVE(d
, l
, "COREDUMP", coredump
);
349 if (!pid
&& !uid
&& !gid
&& !sgnl
&& !exe
&& !comm
&& !cmdline
&& !filename
) {
350 log_warning("Empty coredump log entry");
354 r
= sd_journal_get_realtime_usec(j
, &t
);
356 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
358 format_timestamp(buf
, sizeof(buf
), t
);
360 if (!had_legend
&& !arg_no_legend
)
361 fprintf(file
, "%-*s %*s %*s %*s %*s %*s %s\n",
362 FORMAT_TIMESTAMP_WIDTH
, "TIME",
370 normal_coredump
= streq_ptr(mid
, SD_MESSAGE_COREDUMP_STR
);
373 if (access(filename
, R_OK
) == 0)
375 else if (errno
== ENOENT
)
381 else if (normal_coredump
)
386 fprintf(file
, "%-*s %*s %*s %*s %*s %-*s %s\n",
387 FORMAT_TIMESTAMP_WIDTH
, buf
,
391 3, normal_coredump
? strna(sgnl
) : "-",
393 strna(exe
?: (comm
?: cmdline
)));
398 static int print_info(FILE *file
, sd_journal
*j
, bool need_space
) {
400 *mid
= NULL
, *pid
= NULL
, *uid
= NULL
, *gid
= NULL
,
401 *sgnl
= NULL
, *exe
= NULL
, *comm
= NULL
, *cmdline
= NULL
,
402 *unit
= NULL
, *user_unit
= NULL
, *session
= NULL
,
403 *boot_id
= NULL
, *machine_id
= NULL
, *hostname
= NULL
,
404 *slice
= NULL
, *cgroup
= NULL
, *owner_uid
= NULL
,
405 *message
= NULL
, *timestamp
= NULL
, *filename
= NULL
,
409 bool normal_coredump
;
415 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
416 RETRIEVE(d
, l
, "MESSAGE_ID", mid
);
417 RETRIEVE(d
, l
, "COREDUMP_PID", pid
);
418 RETRIEVE(d
, l
, "COREDUMP_UID", uid
);
419 RETRIEVE(d
, l
, "COREDUMP_GID", gid
);
420 RETRIEVE(d
, l
, "COREDUMP_SIGNAL", sgnl
);
421 RETRIEVE(d
, l
, "COREDUMP_EXE", exe
);
422 RETRIEVE(d
, l
, "COREDUMP_COMM", comm
);
423 RETRIEVE(d
, l
, "COREDUMP_CMDLINE", cmdline
);
424 RETRIEVE(d
, l
, "COREDUMP_UNIT", unit
);
425 RETRIEVE(d
, l
, "COREDUMP_USER_UNIT", user_unit
);
426 RETRIEVE(d
, l
, "COREDUMP_SESSION", session
);
427 RETRIEVE(d
, l
, "COREDUMP_OWNER_UID", owner_uid
);
428 RETRIEVE(d
, l
, "COREDUMP_SLICE", slice
);
429 RETRIEVE(d
, l
, "COREDUMP_CGROUP", cgroup
);
430 RETRIEVE(d
, l
, "COREDUMP_TIMESTAMP", timestamp
);
431 RETRIEVE(d
, l
, "COREDUMP_FILENAME", filename
);
432 RETRIEVE(d
, l
, "COREDUMP", coredump
);
433 RETRIEVE(d
, l
, "_BOOT_ID", boot_id
);
434 RETRIEVE(d
, l
, "_MACHINE_ID", machine_id
);
435 RETRIEVE(d
, l
, "_HOSTNAME", hostname
);
436 RETRIEVE(d
, l
, "MESSAGE", message
);
442 normal_coredump
= streq_ptr(mid
, SD_MESSAGE_COREDUMP_STR
);
446 " PID: %s%s%s (%s)\n",
447 ansi_highlight(), strna(pid
), ansi_normal(), comm
);
451 ansi_highlight(), strna(pid
), ansi_normal());
456 if (parse_uid(uid
, &n
) >= 0) {
457 _cleanup_free_
char *u
= NULL
;
473 if (parse_gid(gid
, &n
) >= 0) {
474 _cleanup_free_
char *g
= NULL
;
489 const char *name
= normal_coredump
? "Signal" : "Reason";
491 if (normal_coredump
&& safe_atoi(sgnl
, &sig
) >= 0)
492 fprintf(file
, " %s: %s (%s)\n", name
, sgnl
, signal_to_string(sig
));
494 fprintf(file
, " %s: %s\n", name
, sgnl
);
500 r
= safe_atou64(timestamp
, &u
);
502 char absolute
[FORMAT_TIMESTAMP_MAX
], relative
[FORMAT_TIMESPAN_MAX
];
505 " Timestamp: %s (%s)\n",
506 format_timestamp(absolute
, sizeof(absolute
), u
),
507 format_timestamp_relative(relative
, sizeof(relative
), u
));
510 fprintf(file
, " Timestamp: %s\n", timestamp
);
514 fprintf(file
, " Command Line: %s\n", cmdline
);
516 fprintf(file
, " Executable: %s%s%s\n", ansi_highlight(), exe
, ansi_normal());
518 fprintf(file
, " Control Group: %s\n", cgroup
);
520 fprintf(file
, " Unit: %s\n", unit
);
522 fprintf(file
, " User Unit: %s\n", user_unit
);
524 fprintf(file
, " Slice: %s\n", slice
);
526 fprintf(file
, " Session: %s\n", session
);
530 if (parse_uid(owner_uid
, &n
) >= 0) {
531 _cleanup_free_
char *u
= NULL
;
535 " Owner UID: %s (%s)\n",
544 fprintf(file
, " Boot ID: %s\n", boot_id
);
546 fprintf(file
, " Machine ID: %s\n", machine_id
);
548 fprintf(file
, " Hostname: %s\n", hostname
);
551 fprintf(file
, " Storage: %s%s\n", filename
,
552 access(filename
, R_OK
) < 0 ? " (inaccessible)" : "");
554 fprintf(file
, " Storage: journal\n");
556 fprintf(file
, " Storage: none\n");
559 _cleanup_free_
char *m
= NULL
;
561 m
= strreplace(message
, "\n", "\n ");
563 fprintf(file
, " Message: %s\n", strstrip(m
?: message
));
569 static int focus(sd_journal
*j
) {
572 r
= sd_journal_seek_tail(j
);
574 r
= sd_journal_previous(j
);
576 return log_error_errno(r
, "Failed to search journal: %m");
578 log_error("No match found.");
584 static int print_entry(sd_journal
*j
, unsigned n_found
) {
587 if (arg_action
== ACTION_INFO
)
588 return print_info(stdout
, j
, n_found
);
590 return print_field(stdout
, j
);
592 return print_list(stdout
, j
, n_found
);
595 static int dump_list(sd_journal
*j
) {
596 unsigned n_found
= 0;
601 /* The coredumps are likely to compressed, and for just
602 * listing them we don't need to decompress them, so let's
603 * pick a fairly low data threshold here */
604 sd_journal_set_data_threshold(j
, 4096);
611 return print_entry(j
, 0);
614 SD_JOURNAL_FOREACH(j
) {
615 r
= print_entry(j
, n_found
++);
620 SD_JOURNAL_FOREACH_BACKWARDS(j
) {
621 r
= print_entry(j
, n_found
++);
627 if (!arg_field
&& n_found
<= 0) {
628 log_notice("No coredumps found.");
636 static int save_core(sd_journal
*j
, FILE *file
, char **path
, bool *unlink_temp
) {
638 _cleanup_free_
char *filename
= NULL
;
641 _cleanup_close_
int fdt
= -1;
644 assert(!(file
&& path
)); /* At most one can be specified */
645 assert(!!path
== !!unlink_temp
); /* Those must be specified together */
647 /* Look for a coredump on disk first. */
648 r
= sd_journal_get_data(j
, "COREDUMP_FILENAME", (const void**) &data
, &len
);
650 retrieve(data
, len
, "COREDUMP_FILENAME", &filename
);
653 return log_error_errno(r
, "Failed to retrieve COREDUMP_FILENAME field: %m");
654 /* Check that we can have a COREDUMP field. We still haven't set a high
655 * data threshold, so we'll get a few kilobytes at most.
658 r
= sd_journal_get_data(j
, "COREDUMP", (const void**) &data
, &len
);
660 return log_error_errno(r
, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).");
662 return log_error_errno(r
, "Failed to retrieve COREDUMP field: %m");
666 if (access(filename
, R_OK
) < 0)
667 return log_error_errno(errno
, "File \"%s\" is not readable: %m", filename
);
669 if (path
&& !endswith(filename
, ".xz") && !endswith(filename
, ".lz4")) {
680 /* Create a temporary file to write the uncompressed core to. */
682 r
= var_tmp_dir(&vt
);
684 return log_error_errno(r
, "Failed to acquire temporary directory path: %m");
686 temp
= strjoin(vt
, "/coredump-XXXXXX");
690 fdt
= mkostemp_safe(temp
);
692 return log_error_errno(fdt
, "Failed to create temporary file: %m");
693 log_debug("Created temporary file %s", temp
);
697 /* If neither path or file are specified, we will write to stdout. Let's now check
698 * if stdout is connected to a tty. We checked that the file exists, or that the
699 * core might be stored in the journal. In this second case, if we found the entry,
700 * in all likelyhood we will be able to access the COREDUMP= field. In either case,
701 * we stop before doing any "real" work, i.e. before starting decompression or
702 * reading from the file or creating temporary files.
706 return log_error_errno(ENOTTY
, "Refusing to dump core to tty"
707 " (use shell redirection or specify --output).");
715 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
716 _cleanup_close_
int fdf
;
718 fdf
= open(filename
, O_RDONLY
| O_CLOEXEC
);
720 r
= log_error_errno(errno
, "Failed to open %s: %m", filename
);
724 r
= decompress_stream(filename
, fdf
, fd
, -1);
726 log_error_errno(r
, "Failed to decompress %s: %m", filename
);
730 log_error("Cannot decompress file. Compiled without compression support.");
737 /* We want full data, nothing truncated. */
738 sd_journal_set_data_threshold(j
, 0);
740 r
= sd_journal_get_data(j
, "COREDUMP", (const void**) &data
, &len
);
742 return log_error_errno(r
, "Failed to retrieve COREDUMP field: %m");
748 sz
= write(fd
, data
, len
);
750 r
= log_error_errno(errno
, "Failed to write output: %m");
753 if (sz
!= (ssize_t
) len
) {
754 log_error("Short write to output.");
769 log_debug("Removed temporary file %s", temp
);
774 static int dump_core(sd_journal
* j
) {
783 print_info(arg_output
? stdout
: stderr
, j
, false);
785 r
= save_core(j
, arg_output
, NULL
, NULL
);
789 r
= sd_journal_previous(j
);
791 log_warning("More than one entry matches, ignoring rest.");
796 static int run_gdb(sd_journal
*j
) {
797 _cleanup_free_
char *exe
= NULL
, *path
= NULL
;
798 bool unlink_path
= false;
811 print_info(stdout
, j
, false);
814 r
= sd_journal_get_data(j
, "COREDUMP_EXE", (const void**) &data
, &len
);
816 return log_error_errno(r
, "Failed to retrieve COREDUMP_EXE field: %m");
818 assert(len
> strlen("COREDUMP_EXE="));
819 data
+= strlen("COREDUMP_EXE=");
820 len
-= strlen("COREDUMP_EXE=");
822 exe
= strndup(data
, len
);
826 if (endswith(exe
, " (deleted)")) {
827 log_error("Binary already deleted.");
831 if (!path_is_absolute(exe
)) {
832 log_error("Binary is not an absolute path.");
836 r
= save_core(j
, NULL
, &path
, &unlink_path
);
840 /* Don't interfere with gdb and its handling of SIGINT. */
841 (void) ignore_signals(SIGINT
, -1);
845 r
= log_error_errno(errno
, "Failed to fork(): %m");
849 (void) reset_all_signal_handlers();
850 (void) reset_signal_mask();
852 execlp("gdb", "gdb", exe
, path
, NULL
);
854 log_error_errno(errno
, "Failed to invoke gdb: %m");
858 r
= wait_for_terminate(pid
, &st
);
860 log_error_errno(r
, "Failed to wait for gdb: %m");
864 r
= st
.si_code
== CLD_EXITED
? st
.si_status
: 255;
867 (void) default_signals(SIGINT
, -1);
870 log_debug("Removed temporary file %s", path
);
877 static int check_units_active(void) {
878 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
879 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
880 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
881 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
885 r
= sd_bus_default_system(&bus
);
887 return log_error_errno(r
, "Failed to acquire bus: %m");
889 r
= sd_bus_message_new_method_call(
892 "org.freedesktop.systemd1",
893 "/org/freedesktop/systemd1",
894 "org.freedesktop.systemd1.Manager",
895 "ListUnitsByPatterns");
897 return bus_log_create_error(r
);
899 r
= sd_bus_message_append_strv(m
, NULL
);
901 return bus_log_create_error(r
);
903 r
= sd_bus_message_append_strv(m
, STRV_MAKE("systemd-coredump@*.service"));
905 return bus_log_create_error(r
);
907 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
909 return log_error_errno(r
, "Failed to check if any systemd-coredump@.service units are running: %s",
910 bus_error_message(&error
, r
));
912 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "(ssssssouso)");
914 return bus_log_parse_error(r
);
916 while ((r
= sd_bus_message_read(
917 reply
, "(ssssssouso)",
918 NULL
, NULL
, NULL
, &state
, NULL
,
919 NULL
, NULL
, NULL
, NULL
, NULL
) > 0))
920 if (!STR_IN_SET(state
, "dead", "failed"))
924 return bus_log_parse_error(r
);
926 r
= sd_bus_message_exit_container(reply
);
928 return bus_log_parse_error(r
);
933 int main(int argc
, char *argv
[]) {
934 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
935 int r
= 0, units_active
;
937 setlocale(LC_ALL
, "");
938 log_parse_environment();
941 r
= parse_argv(argc
, argv
);
945 if (arg_action
== ACTION_NONE
)
951 r
= sd_journal_open_directory(&j
, arg_directory
, 0);
953 log_error_errno(r
, "Failed to open journals in directory: %s: %m", arg_directory
);
957 r
= sd_journal_open(&j
, SD_JOURNAL_LOCAL_ONLY
);
959 log_error_errno(r
, "Failed to open journal: %m");
968 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
969 _cleanup_free_
char *filter
;
971 filter
= journal_make_match_string(j
);
972 log_debug("Journal filter: %s", filter
);
975 units_active
= check_units_active(); /* error is treated the same as 0 */
981 pager_open(arg_no_pager
, false);
994 assert_not_reached("Shouldn't be here");
997 if (units_active
> 0)
998 printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n",
999 ansi_highlight_red(),
1000 units_active
, units_active
== 1 ? "unit is running" : "units are running",
1008 return r
>= 0 ? r
: EXIT_FAILURE
;