1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Zbigniew Jędrzejewski-Szmek
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "sd-journal.h"
30 #include "sd-messages.h"
32 #include "alloc-util.h"
33 #include "bus-error.h"
39 #include "journal-internal.h"
40 #include "journal-util.h"
44 #include "parse-util.h"
45 #include "path-util.h"
46 #include "process-util.h"
48 #include "signal-util.h"
49 #include "string-util.h"
51 #include "terminal-util.h"
52 #include "user-util.h"
55 #define SHORT_BUS_CALL_TIMEOUT_USEC (3 * USEC_PER_SEC)
57 static usec_t arg_since
= USEC_INFINITY
, arg_until
= USEC_INFINITY
;
65 } arg_action
= ACTION_LIST
;
66 static const char* arg_field
= NULL
;
67 static const char *arg_directory
= NULL
;
68 static bool arg_no_pager
= false;
69 static int arg_no_legend
= false;
70 static int arg_one
= false;
71 static FILE* arg_output
= NULL
;
72 static bool arg_reverse
= false;
73 static char** arg_matches
= NULL
;
74 static bool arg_quiet
= false;
76 static int add_match(sd_journal
*j
, const char *match
) {
77 _cleanup_free_
char *p
= NULL
;
83 if (strchr(match
, '='))
85 else if (strchr(match
, '/')) {
86 r
= path_make_absolute_cwd(match
, &p
);
88 return log_error_errno(r
, "path_make_absolute_cwd(\"%s\"): %m", match
);
91 prefix
= "COREDUMP_EXE=";
92 } else if (parse_pid(match
, &pid
) >= 0)
93 prefix
= "COREDUMP_PID=";
95 prefix
= "COREDUMP_COMM=";
97 pattern
= strjoin(prefix
, match
);
101 log_debug("Adding match: %s", pattern
);
102 r
= sd_journal_add_match(j
, pattern
, 0);
104 return log_error_errno(r
, "Failed to add match \"%s\": %m", match
);
108 static int add_matches(sd_journal
*j
) {
112 r
= sd_journal_add_match(j
, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR
, 0);
114 return log_error_errno(r
, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR
);
116 r
= sd_journal_add_match(j
, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR
, 0);
118 return log_error_errno(r
, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR
);
120 STRV_FOREACH(match
, arg_matches
) {
121 r
= add_match(j
, *match
);
129 static void help(void) {
130 printf("%s [OPTIONS...]\n\n"
131 "List or retrieve coredumps from the journal.\n\n"
133 " -h --help Show this help\n"
134 " --version Print version string\n"
135 " --no-pager Do not pipe output into a pager\n"
136 " --no-legend Do not print the column headers.\n"
137 " -1 Show information about most recent entry only\n"
138 " -S --since=DATE Only print coredumps since the date\n"
139 " -U --until=DATE Only print coredumps until the date\n"
140 " -r --reverse Show the newest entries first\n"
141 " -F --field=FIELD List all values a certain field takes\n"
142 " -o --output=FILE Write output to FILE\n"
143 " -D --directory=DIR Use journal files from directory\n\n"
144 " -q --quiet Do not show info messages and privilege warning\n"
146 " list [MATCHES...] List available coredumps (default)\n"
147 " info [MATCHES...] Show detailed information about one or more coredumps\n"
148 " dump [MATCHES...] Print first matching coredump to stdout\n"
149 " gdb [MATCHES...] Start gdb for the first matching coredump\n"
150 , program_invocation_short_name
);
153 static int parse_argv(int argc
, char *argv
[]) {
162 static const struct option options
[] = {
163 { "help", no_argument
, NULL
, 'h' },
164 { "version" , no_argument
, NULL
, ARG_VERSION
},
165 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
166 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
167 { "output", required_argument
, NULL
, 'o' },
168 { "field", required_argument
, NULL
, 'F' },
169 { "directory", required_argument
, NULL
, 'D' },
170 { "reverse", no_argument
, NULL
, 'r' },
171 { "since", required_argument
, NULL
, 'S' },
172 { "until", required_argument
, NULL
, 'U' },
173 { "quiet", no_argument
, NULL
, 'q' },
180 while ((c
= getopt_long(argc
, argv
, "ho:F:1D:rS:U:q", options
, NULL
)) >= 0)
183 arg_action
= ACTION_NONE
;
188 arg_action
= ACTION_NONE
;
196 arg_no_legend
= true;
201 log_error("cannot set output more than once");
205 arg_output
= fopen(optarg
, "we");
207 return log_error_errno(errno
, "writing to '%s': %m", optarg
);
212 r
= parse_timestamp(optarg
, &arg_since
);
214 return log_error_errno(r
, "Failed to parse timestamp: %s", optarg
);
218 r
= parse_timestamp(optarg
, &arg_until
);
220 return log_error_errno(r
, "Failed to parse timestamp: %s", optarg
);
225 log_error("cannot use --field/-F more than once");
236 arg_directory
= optarg
;
251 assert_not_reached("Unhandled option");
254 if (arg_since
!= USEC_INFINITY
&& arg_until
!= USEC_INFINITY
&&
255 arg_since
> arg_until
) {
256 log_error("--since= must be before --until=.");
261 const char *cmd
= argv
[optind
++];
262 if (streq(cmd
, "list"))
263 arg_action
= ACTION_LIST
;
264 else if (streq(cmd
, "dump"))
265 arg_action
= ACTION_DUMP
;
266 else if (streq(cmd
, "gdb"))
267 arg_action
= ACTION_GDB
;
268 else if (streq(cmd
, "info"))
269 arg_action
= ACTION_INFO
;
271 log_error("Unknown action '%s'", cmd
);
276 if (arg_field
&& arg_action
!= ACTION_LIST
) {
277 log_error("Option --field/-F only makes sense with list");
282 arg_matches
= argv
+ optind
;
287 static int retrieve(const void *data
,
295 ident
= strlen(name
) + 1; /* name + "=" */
300 if (memcmp(data
, name
, ident
- 1) != 0)
303 if (((const char*) data
)[ident
- 1] != '=')
306 v
= strndup((const char*)data
+ ident
, len
- ident
);
316 static int print_field(FILE* file
, sd_journal
*j
) {
325 /* A (user-specified) field may appear more than once for a given entry.
326 * We will print all of the occurences.
327 * This is different below for fields that systemd-coredump uses,
328 * because they cannot meaningfully appear more than once.
330 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
331 _cleanup_free_
char *value
= NULL
;
334 r
= retrieve(d
, l
, arg_field
, &value
);
338 fprintf(file
, "%s\n", value
);
344 #define RETRIEVE(d, l, name, arg) \
346 int _r = retrieve(d, l, name, &arg); \
353 static int print_list(FILE* file
, sd_journal
*j
, int had_legend
) {
355 *mid
= NULL
, *pid
= NULL
, *uid
= NULL
, *gid
= NULL
,
356 *sgnl
= NULL
, *exe
= NULL
, *comm
= NULL
, *cmdline
= NULL
,
357 *filename
= NULL
, *truncated
= NULL
, *coredump
= NULL
;
361 char buf
[FORMAT_TIMESTAMP_MAX
];
364 bool normal_coredump
;
369 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
370 RETRIEVE(d
, l
, "MESSAGE_ID", mid
);
371 RETRIEVE(d
, l
, "COREDUMP_PID", pid
);
372 RETRIEVE(d
, l
, "COREDUMP_UID", uid
);
373 RETRIEVE(d
, l
, "COREDUMP_GID", gid
);
374 RETRIEVE(d
, l
, "COREDUMP_SIGNAL", sgnl
);
375 RETRIEVE(d
, l
, "COREDUMP_EXE", exe
);
376 RETRIEVE(d
, l
, "COREDUMP_COMM", comm
);
377 RETRIEVE(d
, l
, "COREDUMP_CMDLINE", cmdline
);
378 RETRIEVE(d
, l
, "COREDUMP_FILENAME", filename
);
379 RETRIEVE(d
, l
, "COREDUMP_TRUNCATED", truncated
);
380 RETRIEVE(d
, l
, "COREDUMP", coredump
);
383 if (!pid
&& !uid
&& !gid
&& !sgnl
&& !exe
&& !comm
&& !cmdline
&& !filename
) {
384 log_warning("Empty coredump log entry");
388 r
= sd_journal_get_realtime_usec(j
, &t
);
390 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
392 format_timestamp(buf
, sizeof(buf
), t
);
394 if (!had_legend
&& !arg_no_legend
)
395 fprintf(file
, "%-*s %*s %*s %*s %*s %-*s %s\n",
396 FORMAT_TIMESTAMP_WIDTH
, "TIME",
404 normal_coredump
= streq_ptr(mid
, SD_MESSAGE_COREDUMP_STR
);
407 if (access(filename
, R_OK
) == 0)
409 else if (errno
== ENOENT
)
415 else if (normal_coredump
)
420 if (STR_IN_SET(present
, "present", "journal") && truncated
&& parse_boolean(truncated
) > 0)
421 present
= "truncated";
423 fprintf(file
, "%-*s %*s %*s %*s %*s %-*s %s\n",
424 FORMAT_TIMESTAMP_WIDTH
, buf
,
428 3, normal_coredump
? strna(sgnl
) : "-",
430 strna(exe
?: (comm
?: cmdline
)));
435 static int print_info(FILE *file
, sd_journal
*j
, bool need_space
) {
437 *mid
= NULL
, *pid
= NULL
, *uid
= NULL
, *gid
= NULL
,
438 *sgnl
= NULL
, *exe
= NULL
, *comm
= NULL
, *cmdline
= NULL
,
439 *unit
= NULL
, *user_unit
= NULL
, *session
= NULL
,
440 *boot_id
= NULL
, *machine_id
= NULL
, *hostname
= NULL
,
441 *slice
= NULL
, *cgroup
= NULL
, *owner_uid
= NULL
,
442 *message
= NULL
, *timestamp
= NULL
, *filename
= NULL
,
443 *truncated
= NULL
, *coredump
= NULL
;
446 bool normal_coredump
;
452 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
453 RETRIEVE(d
, l
, "MESSAGE_ID", mid
);
454 RETRIEVE(d
, l
, "COREDUMP_PID", pid
);
455 RETRIEVE(d
, l
, "COREDUMP_UID", uid
);
456 RETRIEVE(d
, l
, "COREDUMP_GID", gid
);
457 RETRIEVE(d
, l
, "COREDUMP_SIGNAL", sgnl
);
458 RETRIEVE(d
, l
, "COREDUMP_EXE", exe
);
459 RETRIEVE(d
, l
, "COREDUMP_COMM", comm
);
460 RETRIEVE(d
, l
, "COREDUMP_CMDLINE", cmdline
);
461 RETRIEVE(d
, l
, "COREDUMP_UNIT", unit
);
462 RETRIEVE(d
, l
, "COREDUMP_USER_UNIT", user_unit
);
463 RETRIEVE(d
, l
, "COREDUMP_SESSION", session
);
464 RETRIEVE(d
, l
, "COREDUMP_OWNER_UID", owner_uid
);
465 RETRIEVE(d
, l
, "COREDUMP_SLICE", slice
);
466 RETRIEVE(d
, l
, "COREDUMP_CGROUP", cgroup
);
467 RETRIEVE(d
, l
, "COREDUMP_TIMESTAMP", timestamp
);
468 RETRIEVE(d
, l
, "COREDUMP_FILENAME", filename
);
469 RETRIEVE(d
, l
, "COREDUMP_TRUNCATED", truncated
);
470 RETRIEVE(d
, l
, "COREDUMP", coredump
);
471 RETRIEVE(d
, l
, "_BOOT_ID", boot_id
);
472 RETRIEVE(d
, l
, "_MACHINE_ID", machine_id
);
473 RETRIEVE(d
, l
, "_HOSTNAME", hostname
);
474 RETRIEVE(d
, l
, "MESSAGE", message
);
480 normal_coredump
= streq_ptr(mid
, SD_MESSAGE_COREDUMP_STR
);
484 " PID: %s%s%s (%s)\n",
485 ansi_highlight(), strna(pid
), ansi_normal(), comm
);
489 ansi_highlight(), strna(pid
), ansi_normal());
494 if (parse_uid(uid
, &n
) >= 0) {
495 _cleanup_free_
char *u
= NULL
;
511 if (parse_gid(gid
, &n
) >= 0) {
512 _cleanup_free_
char *g
= NULL
;
527 const char *name
= normal_coredump
? "Signal" : "Reason";
529 if (normal_coredump
&& safe_atoi(sgnl
, &sig
) >= 0)
530 fprintf(file
, " %s: %s (%s)\n", name
, sgnl
, signal_to_string(sig
));
532 fprintf(file
, " %s: %s\n", name
, sgnl
);
538 r
= safe_atou64(timestamp
, &u
);
540 char absolute
[FORMAT_TIMESTAMP_MAX
], relative
[FORMAT_TIMESPAN_MAX
];
543 " Timestamp: %s (%s)\n",
544 format_timestamp(absolute
, sizeof(absolute
), u
),
545 format_timestamp_relative(relative
, sizeof(relative
), u
));
548 fprintf(file
, " Timestamp: %s\n", timestamp
);
552 fprintf(file
, " Command Line: %s\n", cmdline
);
554 fprintf(file
, " Executable: %s%s%s\n", ansi_highlight(), exe
, ansi_normal());
556 fprintf(file
, " Control Group: %s\n", cgroup
);
558 fprintf(file
, " Unit: %s\n", unit
);
560 fprintf(file
, " User Unit: %s\n", user_unit
);
562 fprintf(file
, " Slice: %s\n", slice
);
564 fprintf(file
, " Session: %s\n", session
);
568 if (parse_uid(owner_uid
, &n
) >= 0) {
569 _cleanup_free_
char *u
= NULL
;
573 " Owner UID: %s (%s)\n",
582 fprintf(file
, " Boot ID: %s\n", boot_id
);
584 fprintf(file
, " Machine ID: %s\n", machine_id
);
586 fprintf(file
, " Hostname: %s\n", hostname
);
591 inacc
= access(filename
, R_OK
) < 0;
592 trunc
= truncated
&& parse_boolean(truncated
) > 0;
595 fprintf(file
, " Storage: %s%s (%s%s%s)%s\n",
596 ansi_highlight_red(),
598 inacc
? "inaccessible" : "",
599 inacc
&& trunc
? ", " : "",
600 trunc
? "truncated" : "",
603 fprintf(file
, " Storage: %s\n", filename
);
607 fprintf(file
, " Storage: journal\n");
609 fprintf(file
, " Storage: none\n");
612 _cleanup_free_
char *m
= NULL
;
614 m
= strreplace(message
, "\n", "\n ");
616 fprintf(file
, " Message: %s\n", strstrip(m
?: message
));
622 static int focus(sd_journal
*j
) {
625 r
= sd_journal_seek_tail(j
);
627 r
= sd_journal_previous(j
);
629 return log_error_errno(r
, "Failed to search journal: %m");
631 log_error("No match found.");
637 static int print_entry(sd_journal
*j
, unsigned n_found
) {
640 if (arg_action
== ACTION_INFO
)
641 return print_info(stdout
, j
, n_found
);
643 return print_field(stdout
, j
);
645 return print_list(stdout
, j
, n_found
);
648 static int dump_list(sd_journal
*j
) {
649 unsigned n_found
= 0;
654 /* The coredumps are likely to compressed, and for just
655 * listing them we don't need to decompress them, so let's
656 * pick a fairly low data threshold here */
657 sd_journal_set_data_threshold(j
, 4096);
664 return print_entry(j
, 0);
666 if (arg_since
!= USEC_INFINITY
&& !arg_reverse
)
667 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
668 else if (arg_until
!= USEC_INFINITY
&& arg_reverse
)
669 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
670 else if (arg_reverse
)
671 r
= sd_journal_seek_tail(j
);
673 r
= sd_journal_seek_head(j
);
675 return log_error_errno(r
, "Failed to seek to date: %m");
679 r
= sd_journal_next(j
);
681 r
= sd_journal_previous(j
);
684 return log_error_errno(r
, "Failed to iterate through journal: %m");
689 if (arg_until
!= USEC_INFINITY
&& !arg_reverse
) {
692 r
= sd_journal_get_realtime_usec(j
, &usec
);
694 return log_error_errno(r
, "Failed to determine timestamp: %m");
695 if (usec
> arg_until
)
699 if (arg_since
!= USEC_INFINITY
&& arg_reverse
) {
702 r
= sd_journal_get_realtime_usec(j
, &usec
);
704 return log_error_errno(r
, "Failed to determine timestamp: %m");
705 if (usec
< arg_since
)
709 r
= print_entry(j
, n_found
++);
714 if (!arg_field
&& n_found
<= 0) {
716 log_notice("No coredumps found.");
724 static int save_core(sd_journal
*j
, FILE *file
, char **path
, bool *unlink_temp
) {
726 _cleanup_free_
char *filename
= NULL
;
729 _cleanup_close_
int fdt
= -1;
732 assert(!(file
&& path
)); /* At most one can be specified */
733 assert(!!path
== !!unlink_temp
); /* Those must be specified together */
735 /* Look for a coredump on disk first. */
736 r
= sd_journal_get_data(j
, "COREDUMP_FILENAME", (const void**) &data
, &len
);
738 retrieve(data
, len
, "COREDUMP_FILENAME", &filename
);
741 return log_error_errno(r
, "Failed to retrieve COREDUMP_FILENAME field: %m");
742 /* Check that we can have a COREDUMP field. We still haven't set a high
743 * data threshold, so we'll get a few kilobytes at most.
746 r
= sd_journal_get_data(j
, "COREDUMP", (const void**) &data
, &len
);
748 return log_error_errno(r
, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).");
750 return log_error_errno(r
, "Failed to retrieve COREDUMP field: %m");
754 if (access(filename
, R_OK
) < 0)
755 return log_error_errno(errno
, "File \"%s\" is not readable: %m", filename
);
757 if (path
&& !endswith(filename
, ".xz") && !endswith(filename
, ".lz4")) {
768 /* Create a temporary file to write the uncompressed core to. */
770 r
= var_tmp_dir(&vt
);
772 return log_error_errno(r
, "Failed to acquire temporary directory path: %m");
774 temp
= strjoin(vt
, "/coredump-XXXXXX");
778 fdt
= mkostemp_safe(temp
);
780 return log_error_errno(fdt
, "Failed to create temporary file: %m");
781 log_debug("Created temporary file %s", temp
);
785 /* If neither path or file are specified, we will write to stdout. Let's now check
786 * if stdout is connected to a tty. We checked that the file exists, or that the
787 * core might be stored in the journal. In this second case, if we found the entry,
788 * in all likelyhood we will be able to access the COREDUMP= field. In either case,
789 * we stop before doing any "real" work, i.e. before starting decompression or
790 * reading from the file or creating temporary files.
794 return log_error_errno(ENOTTY
, "Refusing to dump core to tty"
795 " (use shell redirection or specify --output).");
803 #if HAVE_XZ || HAVE_LZ4
804 _cleanup_close_
int fdf
;
806 fdf
= open(filename
, O_RDONLY
| O_CLOEXEC
);
808 r
= log_error_errno(errno
, "Failed to open %s: %m", filename
);
812 r
= decompress_stream(filename
, fdf
, fd
, -1);
814 log_error_errno(r
, "Failed to decompress %s: %m", filename
);
818 log_error("Cannot decompress file. Compiled without compression support.");
825 /* We want full data, nothing truncated. */
826 sd_journal_set_data_threshold(j
, 0);
828 r
= sd_journal_get_data(j
, "COREDUMP", (const void**) &data
, &len
);
830 return log_error_errno(r
, "Failed to retrieve COREDUMP field: %m");
836 sz
= write(fd
, data
, len
);
838 r
= log_error_errno(errno
, "Failed to write output: %m");
841 if (sz
!= (ssize_t
) len
) {
842 log_error("Short write to output.");
857 log_debug("Removed temporary file %s", temp
);
862 static int dump_core(sd_journal
* j
) {
871 print_info(arg_output
? stdout
: stderr
, j
, false);
873 r
= save_core(j
, arg_output
, NULL
, NULL
);
877 r
= sd_journal_previous(j
);
878 if (r
> 0 && !arg_quiet
)
879 log_notice("More than one entry matches, ignoring rest.");
884 static int run_gdb(sd_journal
*j
) {
885 _cleanup_free_
char *exe
= NULL
, *path
= NULL
;
886 bool unlink_path
= false;
899 print_info(stdout
, j
, false);
902 r
= sd_journal_get_data(j
, "COREDUMP_EXE", (const void**) &data
, &len
);
904 return log_error_errno(r
, "Failed to retrieve COREDUMP_EXE field: %m");
906 assert(len
> STRLEN("COREDUMP_EXE="));
907 data
+= STRLEN("COREDUMP_EXE=");
908 len
-= STRLEN("COREDUMP_EXE=");
910 exe
= strndup(data
, len
);
914 if (endswith(exe
, " (deleted)")) {
915 log_error("Binary already deleted.");
919 if (!path_is_absolute(exe
)) {
920 log_error("Binary is not an absolute path.");
924 r
= save_core(j
, NULL
, &path
, &unlink_path
);
928 /* Don't interfere with gdb and its handling of SIGINT. */
929 (void) ignore_signals(SIGINT
, -1);
931 r
= safe_fork("(gdb)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
|FORK_CLOSE_ALL_FDS
|FORK_LOG
, &pid
);
935 execlp("gdb", "gdb", exe
, path
, NULL
);
936 log_error_errno(errno
, "Failed to invoke gdb: %m");
940 r
= wait_for_terminate(pid
, &st
);
942 log_error_errno(r
, "Failed to wait for gdb: %m");
946 r
= st
.si_code
== CLD_EXITED
? st
.si_status
: 255;
949 (void) default_signals(SIGINT
, -1);
952 log_debug("Removed temporary file %s", path
);
959 static int check_units_active(void) {
960 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
961 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
962 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
963 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
965 const char *id
, *state
, *substate
;
970 r
= sd_bus_default_system(&bus
);
972 return log_error_errno(r
, "Failed to acquire bus: %m");
974 r
= sd_bus_message_new_method_call(
977 "org.freedesktop.systemd1",
978 "/org/freedesktop/systemd1",
979 "org.freedesktop.systemd1.Manager",
980 "ListUnitsByPatterns");
982 return bus_log_create_error(r
);
984 r
= sd_bus_message_append_strv(m
, NULL
);
986 return bus_log_create_error(r
);
988 r
= sd_bus_message_append_strv(m
, STRV_MAKE("systemd-coredump@*.service"));
990 return bus_log_create_error(r
);
992 r
= sd_bus_call(bus
, m
, SHORT_BUS_CALL_TIMEOUT_USEC
, &error
, &reply
);
994 return log_error_errno(r
, "Failed to check if any systemd-coredump@.service units are running: %s",
995 bus_error_message(&error
, r
));
997 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "(ssssssouso)");
999 return bus_log_parse_error(r
);
1001 while ((r
= sd_bus_message_read(
1002 reply
, "(ssssssouso)",
1003 &id
, NULL
, NULL
, &state
, &substate
,
1004 NULL
, NULL
, NULL
, NULL
, NULL
)) > 0) {
1005 bool found
= !STR_IN_SET(state
, "inactive", "dead", "failed");
1006 log_debug("Unit %s is %s/%s, %scounting it.", id
, state
, substate
, found
? "" : "not ");
1010 return bus_log_parse_error(r
);
1012 r
= sd_bus_message_exit_container(reply
);
1014 return bus_log_parse_error(r
);
1019 int main(int argc
, char *argv
[]) {
1020 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1021 int r
= 0, units_active
;
1023 setlocale(LC_ALL
, "");
1024 log_parse_environment();
1027 r
= parse_argv(argc
, argv
);
1031 if (arg_action
== ACTION_NONE
)
1036 if (arg_directory
) {
1037 r
= sd_journal_open_directory(&j
, arg_directory
, 0);
1039 log_error_errno(r
, "Failed to open journals in directory: %s: %m", arg_directory
);
1043 r
= sd_journal_open(&j
, SD_JOURNAL_LOCAL_ONLY
);
1045 log_error_errno(r
, "Failed to open journal: %m");
1050 r
= journal_access_check_and_warn(j
, arg_quiet
);
1058 if (DEBUG_LOGGING
) {
1059 _cleanup_free_
char *filter
;
1061 filter
= journal_make_match_string(j
);
1062 log_debug("Journal filter: %s", filter
);
1065 units_active
= check_units_active(); /* error is treated the same as 0 */
1067 switch(arg_action
) {
1071 pager_open(arg_no_pager
, false);
1084 assert_not_reached("Shouldn't be here");
1087 if (units_active
> 0)
1088 printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n",
1089 ansi_highlight_red(),
1090 units_active
, units_active
== 1 ? "unit is running" : "units are running",
1098 return r
>= 0 ? r
: EXIT_FAILURE
;