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
= strjoina(prefix
, match
);
98 log_debug("Adding match: %s", pattern
);
99 r
= sd_journal_add_match(j
, pattern
, 0);
101 return log_error_errno(r
, "Failed to add match \"%s\": %m", match
);
105 static int add_matches(sd_journal
*j
) {
109 r
= sd_journal_add_match(j
, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR
, 0);
111 return log_error_errno(r
, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR
);
113 r
= sd_journal_add_match(j
, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR
, 0);
115 return log_error_errno(r
, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR
);
117 STRV_FOREACH(match
, arg_matches
) {
118 r
= add_match(j
, *match
);
126 static void help(void) {
127 printf("%s [OPTIONS...]\n\n"
128 "List or retrieve coredumps from the journal.\n\n"
130 " -h --help Show this help\n"
131 " --version Print version string\n"
132 " --no-pager Do not pipe output into a pager\n"
133 " --no-legend Do not print the column headers.\n"
134 " -1 Show information about most recent entry only\n"
135 " -S --since=DATE Only print coredumps since the date\n"
136 " -U --until=DATE Only print coredumps until the date\n"
137 " -r --reverse Show the newest entries first\n"
138 " -F --field=FIELD List all values a certain field takes\n"
139 " -o --output=FILE Write output to FILE\n"
140 " -D --directory=DIR Use journal files from directory\n\n"
141 " -q --quiet Do not show info messages and privilege warning\n"
143 " list [MATCHES...] List available coredumps (default)\n"
144 " info [MATCHES...] Show detailed information about one or more coredumps\n"
145 " dump [MATCHES...] Print first matching coredump to stdout\n"
146 " gdb [MATCHES...] Start gdb for the first matching coredump\n"
147 , program_invocation_short_name
);
150 static int parse_argv(int argc
, char *argv
[]) {
159 static const struct option options
[] = {
160 { "help", no_argument
, NULL
, 'h' },
161 { "version" , no_argument
, NULL
, ARG_VERSION
},
162 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
163 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
164 { "output", required_argument
, NULL
, 'o' },
165 { "field", required_argument
, NULL
, 'F' },
166 { "directory", required_argument
, NULL
, 'D' },
167 { "reverse", no_argument
, NULL
, 'r' },
168 { "since", required_argument
, NULL
, 'S' },
169 { "until", required_argument
, NULL
, 'U' },
170 { "quiet", no_argument
, NULL
, 'q' },
177 while ((c
= getopt_long(argc
, argv
, "ho:F:1D:rS:U:q", options
, NULL
)) >= 0)
180 arg_action
= ACTION_NONE
;
185 arg_action
= ACTION_NONE
;
193 arg_no_legend
= true;
198 log_error("cannot set output more than once");
202 arg_output
= fopen(optarg
, "we");
204 return log_error_errno(errno
, "writing to '%s': %m", optarg
);
209 r
= parse_timestamp(optarg
, &arg_since
);
211 return log_error_errno(r
, "Failed to parse timestamp: %s", optarg
);
215 r
= parse_timestamp(optarg
, &arg_until
);
217 return log_error_errno(r
, "Failed to parse timestamp: %s", optarg
);
222 log_error("cannot use --field/-F more than once");
233 arg_directory
= optarg
;
248 assert_not_reached("Unhandled option");
251 if (arg_since
!= USEC_INFINITY
&& arg_until
!= USEC_INFINITY
&&
252 arg_since
> arg_until
) {
253 log_error("--since= must be before --until=.");
258 const char *cmd
= argv
[optind
++];
259 if (streq(cmd
, "list"))
260 arg_action
= ACTION_LIST
;
261 else if (streq(cmd
, "dump"))
262 arg_action
= ACTION_DUMP
;
263 else if (streq(cmd
, "gdb"))
264 arg_action
= ACTION_GDB
;
265 else if (streq(cmd
, "info"))
266 arg_action
= ACTION_INFO
;
268 log_error("Unknown action '%s'", cmd
);
273 if (arg_field
&& arg_action
!= ACTION_LIST
) {
274 log_error("Option --field/-F only makes sense with list");
279 arg_matches
= argv
+ optind
;
284 static int retrieve(const void *data
,
292 ident
= strlen(name
) + 1; /* name + "=" */
297 if (memcmp(data
, name
, ident
- 1) != 0)
300 if (((const char*) data
)[ident
- 1] != '=')
303 v
= strndup((const char*)data
+ ident
, len
- ident
);
313 static int print_field(FILE* file
, sd_journal
*j
) {
322 /* A (user-specified) field may appear more than once for a given entry.
323 * We will print all of the occurences.
324 * This is different below for fields that systemd-coredump uses,
325 * because they cannot meaningfully appear more than once.
327 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
328 _cleanup_free_
char *value
= NULL
;
331 r
= retrieve(d
, l
, arg_field
, &value
);
335 fprintf(file
, "%s\n", value
);
341 #define RETRIEVE(d, l, name, arg) \
343 int _r = retrieve(d, l, name, &arg); \
350 static int print_list(FILE* file
, sd_journal
*j
, int had_legend
) {
352 *mid
= NULL
, *pid
= NULL
, *uid
= NULL
, *gid
= NULL
,
353 *sgnl
= NULL
, *exe
= NULL
, *comm
= NULL
, *cmdline
= NULL
,
354 *filename
= NULL
, *truncated
= NULL
, *coredump
= NULL
;
358 char buf
[FORMAT_TIMESTAMP_MAX
];
361 bool normal_coredump
;
366 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
367 RETRIEVE(d
, l
, "MESSAGE_ID", mid
);
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_FILENAME", filename
);
376 RETRIEVE(d
, l
, "COREDUMP_TRUNCATED", truncated
);
377 RETRIEVE(d
, l
, "COREDUMP", coredump
);
380 if (!pid
&& !uid
&& !gid
&& !sgnl
&& !exe
&& !comm
&& !cmdline
&& !filename
) {
381 log_warning("Empty coredump log entry");
385 r
= sd_journal_get_realtime_usec(j
, &t
);
387 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
389 format_timestamp(buf
, sizeof(buf
), t
);
391 if (!had_legend
&& !arg_no_legend
)
392 fprintf(file
, "%-*s %*s %*s %*s %*s %-*s %s\n",
393 FORMAT_TIMESTAMP_WIDTH
, "TIME",
401 normal_coredump
= streq_ptr(mid
, SD_MESSAGE_COREDUMP_STR
);
404 if (access(filename
, R_OK
) == 0)
406 else if (errno
== ENOENT
)
412 else if (normal_coredump
)
417 if (STR_IN_SET(present
, "present", "journal") && truncated
&& parse_boolean(truncated
) > 0)
418 present
= "truncated";
420 fprintf(file
, "%-*s %*s %*s %*s %*s %-*s %s\n",
421 FORMAT_TIMESTAMP_WIDTH
, buf
,
425 3, normal_coredump
? strna(sgnl
) : "-",
427 strna(exe
?: (comm
?: cmdline
)));
432 static int print_info(FILE *file
, sd_journal
*j
, bool need_space
) {
434 *mid
= NULL
, *pid
= NULL
, *uid
= NULL
, *gid
= NULL
,
435 *sgnl
= NULL
, *exe
= NULL
, *comm
= NULL
, *cmdline
= NULL
,
436 *unit
= NULL
, *user_unit
= NULL
, *session
= NULL
,
437 *boot_id
= NULL
, *machine_id
= NULL
, *hostname
= NULL
,
438 *slice
= NULL
, *cgroup
= NULL
, *owner_uid
= NULL
,
439 *message
= NULL
, *timestamp
= NULL
, *filename
= NULL
,
440 *truncated
= NULL
, *coredump
= NULL
;
443 bool normal_coredump
;
449 SD_JOURNAL_FOREACH_DATA(j
, d
, l
) {
450 RETRIEVE(d
, l
, "MESSAGE_ID", mid
);
451 RETRIEVE(d
, l
, "COREDUMP_PID", pid
);
452 RETRIEVE(d
, l
, "COREDUMP_UID", uid
);
453 RETRIEVE(d
, l
, "COREDUMP_GID", gid
);
454 RETRIEVE(d
, l
, "COREDUMP_SIGNAL", sgnl
);
455 RETRIEVE(d
, l
, "COREDUMP_EXE", exe
);
456 RETRIEVE(d
, l
, "COREDUMP_COMM", comm
);
457 RETRIEVE(d
, l
, "COREDUMP_CMDLINE", cmdline
);
458 RETRIEVE(d
, l
, "COREDUMP_UNIT", unit
);
459 RETRIEVE(d
, l
, "COREDUMP_USER_UNIT", user_unit
);
460 RETRIEVE(d
, l
, "COREDUMP_SESSION", session
);
461 RETRIEVE(d
, l
, "COREDUMP_OWNER_UID", owner_uid
);
462 RETRIEVE(d
, l
, "COREDUMP_SLICE", slice
);
463 RETRIEVE(d
, l
, "COREDUMP_CGROUP", cgroup
);
464 RETRIEVE(d
, l
, "COREDUMP_TIMESTAMP", timestamp
);
465 RETRIEVE(d
, l
, "COREDUMP_FILENAME", filename
);
466 RETRIEVE(d
, l
, "COREDUMP_TRUNCATED", truncated
);
467 RETRIEVE(d
, l
, "COREDUMP", coredump
);
468 RETRIEVE(d
, l
, "_BOOT_ID", boot_id
);
469 RETRIEVE(d
, l
, "_MACHINE_ID", machine_id
);
470 RETRIEVE(d
, l
, "_HOSTNAME", hostname
);
471 RETRIEVE(d
, l
, "MESSAGE", message
);
477 normal_coredump
= streq_ptr(mid
, SD_MESSAGE_COREDUMP_STR
);
481 " PID: %s%s%s (%s)\n",
482 ansi_highlight(), strna(pid
), ansi_normal(), comm
);
486 ansi_highlight(), strna(pid
), ansi_normal());
491 if (parse_uid(uid
, &n
) >= 0) {
492 _cleanup_free_
char *u
= NULL
;
508 if (parse_gid(gid
, &n
) >= 0) {
509 _cleanup_free_
char *g
= NULL
;
524 const char *name
= normal_coredump
? "Signal" : "Reason";
526 if (normal_coredump
&& safe_atoi(sgnl
, &sig
) >= 0)
527 fprintf(file
, " %s: %s (%s)\n", name
, sgnl
, signal_to_string(sig
));
529 fprintf(file
, " %s: %s\n", name
, sgnl
);
535 r
= safe_atou64(timestamp
, &u
);
537 char absolute
[FORMAT_TIMESTAMP_MAX
], relative
[FORMAT_TIMESPAN_MAX
];
540 " Timestamp: %s (%s)\n",
541 format_timestamp(absolute
, sizeof(absolute
), u
),
542 format_timestamp_relative(relative
, sizeof(relative
), u
));
545 fprintf(file
, " Timestamp: %s\n", timestamp
);
549 fprintf(file
, " Command Line: %s\n", cmdline
);
551 fprintf(file
, " Executable: %s%s%s\n", ansi_highlight(), exe
, ansi_normal());
553 fprintf(file
, " Control Group: %s\n", cgroup
);
555 fprintf(file
, " Unit: %s\n", unit
);
557 fprintf(file
, " User Unit: %s\n", user_unit
);
559 fprintf(file
, " Slice: %s\n", slice
);
561 fprintf(file
, " Session: %s\n", session
);
565 if (parse_uid(owner_uid
, &n
) >= 0) {
566 _cleanup_free_
char *u
= NULL
;
570 " Owner UID: %s (%s)\n",
579 fprintf(file
, " Boot ID: %s\n", boot_id
);
581 fprintf(file
, " Machine ID: %s\n", machine_id
);
583 fprintf(file
, " Hostname: %s\n", hostname
);
588 inacc
= access(filename
, R_OK
) < 0;
589 trunc
= truncated
&& parse_boolean(truncated
) > 0;
592 fprintf(file
, " Storage: %s%s (%s%s%s)%s\n",
593 ansi_highlight_red(),
595 inacc
? "inaccessible" : "",
596 inacc
&& trunc
? ", " : "",
597 trunc
? "truncated" : "",
600 fprintf(file
, " Storage: %s\n", filename
);
604 fprintf(file
, " Storage: journal\n");
606 fprintf(file
, " Storage: none\n");
609 _cleanup_free_
char *m
= NULL
;
611 m
= strreplace(message
, "\n", "\n ");
613 fprintf(file
, " Message: %s\n", strstrip(m
?: message
));
619 static int focus(sd_journal
*j
) {
622 r
= sd_journal_seek_tail(j
);
624 r
= sd_journal_previous(j
);
626 return log_error_errno(r
, "Failed to search journal: %m");
628 log_error("No match found.");
634 static int print_entry(sd_journal
*j
, unsigned n_found
) {
637 if (arg_action
== ACTION_INFO
)
638 return print_info(stdout
, j
, n_found
);
640 return print_field(stdout
, j
);
642 return print_list(stdout
, j
, n_found
);
645 static int dump_list(sd_journal
*j
) {
646 unsigned n_found
= 0;
651 /* The coredumps are likely to compressed, and for just
652 * listing them we don't need to decompress them, so let's
653 * pick a fairly low data threshold here */
654 sd_journal_set_data_threshold(j
, 4096);
661 return print_entry(j
, 0);
663 if (arg_since
!= USEC_INFINITY
&& !arg_reverse
)
664 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
665 else if (arg_until
!= USEC_INFINITY
&& arg_reverse
)
666 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
667 else if (arg_reverse
)
668 r
= sd_journal_seek_tail(j
);
670 r
= sd_journal_seek_head(j
);
672 return log_error_errno(r
, "Failed to seek to date: %m");
676 r
= sd_journal_next(j
);
678 r
= sd_journal_previous(j
);
681 return log_error_errno(r
, "Failed to iterate through journal: %m");
686 if (arg_until
!= USEC_INFINITY
&& !arg_reverse
) {
689 r
= sd_journal_get_realtime_usec(j
, &usec
);
691 return log_error_errno(r
, "Failed to determine timestamp: %m");
692 if (usec
> arg_until
)
696 if (arg_since
!= USEC_INFINITY
&& arg_reverse
) {
699 r
= sd_journal_get_realtime_usec(j
, &usec
);
701 return log_error_errno(r
, "Failed to determine timestamp: %m");
702 if (usec
< arg_since
)
706 r
= print_entry(j
, n_found
++);
711 if (!arg_field
&& n_found
<= 0) {
713 log_notice("No coredumps found.");
721 static int save_core(sd_journal
*j
, FILE *file
, char **path
, bool *unlink_temp
) {
723 _cleanup_free_
char *filename
= NULL
;
726 _cleanup_close_
int fdt
= -1;
729 assert(!(file
&& path
)); /* At most one can be specified */
730 assert(!!path
== !!unlink_temp
); /* Those must be specified together */
732 /* Look for a coredump on disk first. */
733 r
= sd_journal_get_data(j
, "COREDUMP_FILENAME", (const void**) &data
, &len
);
735 retrieve(data
, len
, "COREDUMP_FILENAME", &filename
);
738 return log_error_errno(r
, "Failed to retrieve COREDUMP_FILENAME field: %m");
739 /* Check that we can have a COREDUMP field. We still haven't set a high
740 * data threshold, so we'll get a few kilobytes at most.
743 r
= sd_journal_get_data(j
, "COREDUMP", (const void**) &data
, &len
);
745 return log_error_errno(r
, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).");
747 return log_error_errno(r
, "Failed to retrieve COREDUMP field: %m");
751 if (access(filename
, R_OK
) < 0)
752 return log_error_errno(errno
, "File \"%s\" is not readable: %m", filename
);
754 if (path
&& !endswith(filename
, ".xz") && !endswith(filename
, ".lz4")) {
765 /* Create a temporary file to write the uncompressed core to. */
767 r
= var_tmp_dir(&vt
);
769 return log_error_errno(r
, "Failed to acquire temporary directory path: %m");
771 temp
= strjoin(vt
, "/coredump-XXXXXX");
775 fdt
= mkostemp_safe(temp
);
777 return log_error_errno(fdt
, "Failed to create temporary file: %m");
778 log_debug("Created temporary file %s", temp
);
782 /* If neither path or file are specified, we will write to stdout. Let's now check
783 * if stdout is connected to a tty. We checked that the file exists, or that the
784 * core might be stored in the journal. In this second case, if we found the entry,
785 * in all likelyhood we will be able to access the COREDUMP= field. In either case,
786 * we stop before doing any "real" work, i.e. before starting decompression or
787 * reading from the file or creating temporary files.
791 return log_error_errno(ENOTTY
, "Refusing to dump core to tty"
792 " (use shell redirection or specify --output).");
800 #if HAVE_XZ || HAVE_LZ4
801 _cleanup_close_
int fdf
;
803 fdf
= open(filename
, O_RDONLY
| O_CLOEXEC
);
805 r
= log_error_errno(errno
, "Failed to open %s: %m", filename
);
809 r
= decompress_stream(filename
, fdf
, fd
, -1);
811 log_error_errno(r
, "Failed to decompress %s: %m", filename
);
815 log_error("Cannot decompress file. Compiled without compression support.");
822 /* We want full data, nothing truncated. */
823 sd_journal_set_data_threshold(j
, 0);
825 r
= sd_journal_get_data(j
, "COREDUMP", (const void**) &data
, &len
);
827 return log_error_errno(r
, "Failed to retrieve COREDUMP field: %m");
833 sz
= write(fd
, data
, len
);
835 r
= log_error_errno(errno
, "Failed to write output: %m");
838 if (sz
!= (ssize_t
) len
) {
839 log_error("Short write to output.");
854 log_debug("Removed temporary file %s", temp
);
859 static int dump_core(sd_journal
* j
) {
868 print_info(arg_output
? stdout
: stderr
, j
, false);
870 r
= save_core(j
, arg_output
, NULL
, NULL
);
874 r
= sd_journal_previous(j
);
875 if (r
> 0 && !arg_quiet
)
876 log_notice("More than one entry matches, ignoring rest.");
881 static int run_gdb(sd_journal
*j
) {
882 _cleanup_free_
char *exe
= NULL
, *path
= NULL
;
883 bool unlink_path
= false;
895 print_info(stdout
, j
, false);
898 r
= sd_journal_get_data(j
, "COREDUMP_EXE", (const void**) &data
, &len
);
900 return log_error_errno(r
, "Failed to retrieve COREDUMP_EXE field: %m");
902 assert(len
> STRLEN("COREDUMP_EXE="));
903 data
+= STRLEN("COREDUMP_EXE=");
904 len
-= STRLEN("COREDUMP_EXE=");
906 exe
= strndup(data
, len
);
910 if (endswith(exe
, " (deleted)")) {
911 log_error("Binary already deleted.");
915 if (!path_is_absolute(exe
)) {
916 log_error("Binary is not an absolute path.");
920 r
= save_core(j
, NULL
, &path
, &unlink_path
);
924 /* Don't interfere with gdb and its handling of SIGINT. */
925 (void) ignore_signals(SIGINT
, -1);
927 r
= safe_fork("(gdb)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
|FORK_CLOSE_ALL_FDS
|FORK_LOG
, &pid
);
931 execlp("gdb", "gdb", exe
, path
, NULL
);
933 log_error_errno(errno
, "Failed to invoke gdb: %m");
937 r
= wait_for_terminate_and_check("gdb", pid
, WAIT_LOG_ABNORMAL
);
940 (void) default_signals(SIGINT
, -1);
943 log_debug("Removed temporary file %s", path
);
950 static int check_units_active(void) {
951 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
952 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
953 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
954 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
956 const char *id
, *state
, *substate
;
961 r
= sd_bus_default_system(&bus
);
963 return log_error_errno(r
, "Failed to acquire bus: %m");
965 r
= sd_bus_message_new_method_call(
968 "org.freedesktop.systemd1",
969 "/org/freedesktop/systemd1",
970 "org.freedesktop.systemd1.Manager",
971 "ListUnitsByPatterns");
973 return bus_log_create_error(r
);
975 r
= sd_bus_message_append_strv(m
, NULL
);
977 return bus_log_create_error(r
);
979 r
= sd_bus_message_append_strv(m
, STRV_MAKE("systemd-coredump@*.service"));
981 return bus_log_create_error(r
);
983 r
= sd_bus_call(bus
, m
, SHORT_BUS_CALL_TIMEOUT_USEC
, &error
, &reply
);
985 return log_error_errno(r
, "Failed to check if any systemd-coredump@.service units are running: %s",
986 bus_error_message(&error
, r
));
988 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "(ssssssouso)");
990 return bus_log_parse_error(r
);
992 while ((r
= sd_bus_message_read(
993 reply
, "(ssssssouso)",
994 &id
, NULL
, NULL
, &state
, &substate
,
995 NULL
, NULL
, NULL
, NULL
, NULL
)) > 0) {
996 bool found
= !STR_IN_SET(state
, "inactive", "dead", "failed");
997 log_debug("Unit %s is %s/%s, %scounting it.", id
, state
, substate
, found
? "" : "not ");
1001 return bus_log_parse_error(r
);
1003 r
= sd_bus_message_exit_container(reply
);
1005 return bus_log_parse_error(r
);
1010 int main(int argc
, char *argv
[]) {
1011 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1012 int r
= 0, units_active
;
1014 setlocale(LC_ALL
, "");
1015 log_parse_environment();
1018 r
= parse_argv(argc
, argv
);
1022 if (arg_action
== ACTION_NONE
)
1027 if (arg_directory
) {
1028 r
= sd_journal_open_directory(&j
, arg_directory
, 0);
1030 log_error_errno(r
, "Failed to open journals in directory: %s: %m", arg_directory
);
1034 r
= sd_journal_open(&j
, SD_JOURNAL_LOCAL_ONLY
);
1036 log_error_errno(r
, "Failed to open journal: %m");
1041 r
= journal_access_check_and_warn(j
, arg_quiet
, true);
1049 if (DEBUG_LOGGING
) {
1050 _cleanup_free_
char *filter
;
1052 filter
= journal_make_match_string(j
);
1053 log_debug("Journal filter: %s", filter
);
1056 units_active
= check_units_active(); /* error is treated the same as 0 */
1058 switch(arg_action
) {
1062 pager_open(arg_no_pager
, false);
1075 assert_not_reached("Shouldn't be here");
1078 if (units_active
> 0)
1079 printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n",
1080 ansi_highlight_red(),
1081 units_active
, units_active
== 1 ? "unit is running" : "units are running",
1089 return r
>= 0 ? r
: EXIT_FAILURE
;