]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/coredump/coredumpctl.c
coredump: parse and append package metadata to journal message
[thirdparty/systemd.git] / src / coredump / coredumpctl.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
5de0409e 2
3f6fd1ba
LP
3#include <fcntl.h>
4#include <getopt.h>
a9cdc94f 5#include <locale.h>
5de0409e 6#include <stdio.h>
ada45c78 7#include <unistd.h>
5de0409e 8
012f2b7d 9#include "sd-bus.h"
2cf4172a 10#include "sd-journal.h"
2b044526 11#include "sd-messages.h"
3f6fd1ba 12
b5efdb8a 13#include "alloc-util.h"
012f2b7d
ZJS
14#include "bus-error.h"
15#include "bus-util.h"
3f6fd1ba 16#include "compress.h"
1abaf488 17#include "def.h"
3ffd4af2 18#include "fd-util.h"
0689cfdb 19#include "format-table.h"
992e8f22 20#include "fs-util.h"
aeb56450 21#include "glob-util.h"
3f6fd1ba 22#include "journal-internal.h"
b9aaa7f4 23#include "journal-util.h"
5de0409e 24#include "log.h"
763c7aa2 25#include "macro.h"
c118b577 26#include "main-func.h"
3f6fd1ba 27#include "pager.h"
b1e8f46c 28#include "parse-argument.h"
6bedfcbb 29#include "parse-util.h"
3f6fd1ba 30#include "path-util.h"
294bf0c3 31#include "pretty-print.h"
0b452006 32#include "process-util.h"
1abaf488 33#include "rlimit-util.h"
3f6fd1ba 34#include "sigbus.h"
24882e06 35#include "signal-util.h"
07630cea 36#include "string-util.h"
5ab9ed07 37#include "strv.h"
3f6fd1ba 38#include "terminal-util.h"
e4de7287 39#include "tmpfile-util.h"
b1d4f8e1 40#include "user-util.h"
6bedfcbb 41#include "util.h"
5ce97d33 42#include "verbs.h"
5de0409e 43
501551e8
LP
44#define SHORT_BUS_CALL_TIMEOUT_USEC (3 * USEC_PER_SEC)
45
32485d09 46static usec_t arg_since = USEC_INFINITY, arg_until = USEC_INFINITY;
e15758cc 47static const char* arg_field = NULL;
c5896b6a 48static const char *arg_debugger = NULL;
a2be8be2 49static char **arg_debugger_args = NULL;
b73e9a02 50static const char *arg_directory = NULL;
aeb56450 51static char **arg_file = NULL;
0689cfdb 52static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
0221d68a 53static PagerFlags arg_pager_flags = 0;
0689cfdb
LP
54static int arg_legend = true;
55static size_t arg_rows_max = SIZE_MAX;
158ecef5 56static const char* arg_output = NULL;
df65f77b 57static bool arg_reverse = false;
b9aaa7f4 58static bool arg_quiet = false;
5de0409e 59
a2be8be2 60STATIC_DESTRUCTOR_REGISTER(arg_debugger_args, strv_freep);
aeb56450
FS
61STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep);
62
5ab9ed07 63static int add_match(sd_journal *j, const char *match) {
7fd1b19b 64 _cleanup_free_ char *p = NULL;
43bfe750 65 const char* prefix, *pattern;
0f474365
LP
66 pid_t pid;
67 int r;
5de0409e
ZJS
68
69 if (strchr(match, '='))
70 prefix = "";
71 else if (strchr(match, '/')) {
0f474365
LP
72 r = path_make_absolute_cwd(match, &p);
73 if (r < 0)
5ab9ed07
ZJS
74 return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match);
75
5de0409e
ZJS
76 match = p;
77 prefix = "COREDUMP_EXE=";
0f474365 78 } else if (parse_pid(match, &pid) >= 0)
5de0409e
ZJS
79 prefix = "COREDUMP_PID=";
80 else
81 prefix = "COREDUMP_COMM=";
82
e8fb0238 83 pattern = strjoina(prefix, match);
5ab9ed07
ZJS
84 log_debug("Adding match: %s", pattern);
85 r = sd_journal_add_match(j, pattern, 0);
86 if (r < 0)
87 return log_error_errno(r, "Failed to add match \"%s\": %m", match);
43bfe750 88
5ab9ed07
ZJS
89 return 0;
90}
91
5ce97d33 92static int add_matches(sd_journal *j, char **matches) {
5ab9ed07
ZJS
93 char **match;
94 int r;
5de0409e 95
2b044526 96 r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0);
0f474365 97 if (r < 0)
2b044526 98 return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
5ab9ed07 99
a7581ff9
ZJS
100 r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR, 0);
101 if (r < 0)
102 return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
103
5ce97d33 104 STRV_FOREACH(match, matches) {
5ab9ed07
ZJS
105 r = add_match(j, *match);
106 if (r < 0)
107 return r;
108 }
5de0409e
ZJS
109
110 return 0;
5de0409e
ZJS
111}
112
5ce97d33
YW
113static int acquire_journal(sd_journal **ret, char **matches) {
114 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
115 int r;
116
117 assert(ret);
118
119 if (arg_directory) {
120 r = sd_journal_open_directory(&j, arg_directory, 0);
121 if (r < 0)
122 return log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory);
aeb56450
FS
123 } else if (arg_file) {
124 r = sd_journal_open_files(&j, (const char**)arg_file, 0);
125 if (r < 0)
126 return log_error_errno(r, "Failed to open journal files: %m");
5ce97d33
YW
127 } else {
128 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
129 if (r < 0)
130 return log_error_errno(r, "Failed to open journal: %m");
131 }
132
133 r = journal_access_check_and_warn(j, arg_quiet, true);
134 if (r < 0)
135 return r;
136
137 r = add_matches(j, matches);
138 if (r < 0)
139 return r;
140
141 if (DEBUG_LOGGING) {
142 _cleanup_free_ char *filter;
143
144 filter = journal_make_match_string(j);
145 log_debug("Journal filter: %s", filter);
146 }
147
1cc6c93a 148 *ret = TAKE_PTR(j);
5ce97d33
YW
149
150 return 0;
151}
152
153static int help(void) {
37ec0fdd
LP
154 _cleanup_free_ char *link = NULL;
155 int r;
156
157 r = terminal_urlify_man("coredumpctl", "1", &link);
158 if (r < 0)
159 return log_oom();
160
0689cfdb
LP
161 printf("%1$s [OPTIONS...] COMMAND ...\n\n"
162 "%5$sList or retrieve coredumps from the journal.%6$s\n"
163 "\n%3$sCommands:%4$s\n"
e1fac8a6
ZJS
164 " list [MATCHES...] List available coredumps (default)\n"
165 " info [MATCHES...] Show detailed information about one or more coredumps\n"
166 " dump [MATCHES...] Print first matching coredump to stdout\n"
167 " debug [MATCHES...] Start a debugger for the first matching coredump\n"
0689cfdb 168 "\n%3$sOptions:%4$s\n"
a2be8be2
MF
169 " -h --help Show this help\n"
170 " --version Print version string\n"
171 " --no-pager Do not pipe output into a pager\n"
172 " --no-legend Do not print the column headers\n"
0689cfdb
LP
173 " --json=pretty|short|off\n"
174 " Generate JSON output\n"
a2be8be2
MF
175 " --debugger=DEBUGGER Use the given debugger\n"
176 " -A --debugger-arguments=ARGS Pass the given arguments to the debugger\n"
0689cfdb 177 " -n INT Show maximum number of rows\n"
a2be8be2
MF
178 " -1 Show information about most recent entry only\n"
179 " -S --since=DATE Only print coredumps since the date\n"
180 " -U --until=DATE Only print coredumps until the date\n"
181 " -r --reverse Show the newest entries first\n"
182 " -F --field=FIELD List all values a certain field takes\n"
183 " -o --output=FILE Write output to FILE\n"
184 " --file=PATH Use journal file\n"
185 " -D --directory=DIR Use journal files from directory\n\n"
186 " -q --quiet Do not show info messages and privilege warning\n"
0689cfdb 187 "\nSee the %2$s for details.\n",
bc556335 188 program_invocation_short_name,
0689cfdb
LP
189 link,
190 ansi_underline(),
bc556335 191 ansi_normal(),
0689cfdb
LP
192 ansi_highlight(),
193 ansi_normal());
5ce97d33
YW
194
195 return 0;
601185b4
ZJS
196}
197
5ab9ed07 198static int parse_argv(int argc, char *argv[]) {
5de0409e
ZJS
199 enum {
200 ARG_VERSION = 0x100,
201 ARG_NO_PAGER,
9a340880 202 ARG_NO_LEGEND,
0689cfdb 203 ARG_JSON,
c5896b6a 204 ARG_DEBUGGER,
aeb56450 205 ARG_FILE,
5de0409e
ZJS
206 };
207
32485d09 208 int c, r;
5de0409e
ZJS
209
210 static const struct option options[] = {
a2be8be2
MF
211 { "help", no_argument, NULL, 'h' },
212 { "version" , no_argument, NULL, ARG_VERSION },
213 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
214 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
215 { "debugger", required_argument, NULL, ARG_DEBUGGER },
216 { "debugger-arguments", required_argument, NULL, 'A' },
217 { "output", required_argument, NULL, 'o' },
218 { "field", required_argument, NULL, 'F' },
219 { "file", required_argument, NULL, ARG_FILE },
220 { "directory", required_argument, NULL, 'D' },
221 { "reverse", no_argument, NULL, 'r' },
222 { "since", required_argument, NULL, 'S' },
223 { "until", required_argument, NULL, 'U' },
224 { "quiet", no_argument, NULL, 'q' },
0689cfdb 225 { "json", required_argument, NULL, ARG_JSON },
eb9da376 226 {}
5de0409e
ZJS
227 };
228
229 assert(argc >= 0);
230 assert(argv);
231
0689cfdb 232 while ((c = getopt_long(argc, argv, "hA:o:F:1D:rS:U:qn:", options, NULL)) >= 0)
5de0409e
ZJS
233 switch(c) {
234 case 'h':
5ce97d33 235 return help();
5de0409e
ZJS
236
237 case ARG_VERSION:
3f6fd1ba 238 return version();
5de0409e
ZJS
239
240 case ARG_NO_PAGER:
0221d68a 241 arg_pager_flags |= PAGER_DISABLE;
5de0409e
ZJS
242 break;
243
9a340880 244 case ARG_NO_LEGEND:
0689cfdb 245 arg_legend = false;
9a340880
ZJS
246 break;
247
c5896b6a
RG
248 case ARG_DEBUGGER:
249 arg_debugger = optarg;
250 break;
251
a2be8be2
MF
252 case 'A': {
253 _cleanup_strv_free_ char **l = NULL;
254 r = strv_split_full(&l, optarg, WHITESPACE, EXTRACT_UNQUOTE);
255 if (r < 0)
256 return log_error_errno(r, "Failed to parse debugger arguments '%s': %m", optarg);
257 strv_free_and_replace(arg_debugger_args, l);
258 break;
259 }
260
aeb56450 261 case ARG_FILE:
544e146b 262 r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
aeb56450
FS
263 if (r < 0)
264 return log_error_errno(r, "Failed to add paths: %m");
265 break;
266
5de0409e 267 case 'o':
baaa35ad
ZJS
268 if (arg_output)
269 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
270 "Cannot set output more than once.");
5de0409e 271
158ecef5 272 arg_output = optarg;
5de0409e 273 break;
57ce4bd4 274
32485d09
GS
275 case 'S':
276 r = parse_timestamp(optarg, &arg_since);
277 if (r < 0)
9d77ca39 278 return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg);
32485d09
GS
279 break;
280
281 case 'U':
282 r = parse_timestamp(optarg, &arg_until);
283 if (r < 0)
9d77ca39 284 return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg);
32485d09
GS
285 break;
286
4f76ae1b 287 case 'F':
baaa35ad
ZJS
288 if (arg_field)
289 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
290 "Cannot use --field/-F more than once.");
a276ae74 291 arg_field = optarg;
4f76ae1b
ZJS
292 break;
293
0c51aada 294 case '1':
0689cfdb
LP
295 arg_rows_max = 1;
296 arg_reverse = true;
0c51aada
LP
297 break;
298
0689cfdb
LP
299 case 'n': {
300 unsigned n;
301
302 r = safe_atou(optarg, &n);
303 if (r < 0 || n < 1)
304 return log_error_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL),
305 "Invalid numeric parameter to -n: %s", optarg);
306
307 arg_rows_max = n;
308 break;
309 }
310
b73e9a02
SW
311 case 'D':
312 arg_directory = optarg;
313 break;
314
df65f77b
NK
315 case 'r':
316 arg_reverse = true;
317 break;
318
b9aaa7f4
ZJS
319 case 'q':
320 arg_quiet = true;
321 break;
322
0689cfdb 323 case ARG_JSON:
b1e8f46c 324 r = parse_json_argument(optarg, &arg_json_format_flags);
0689cfdb
LP
325 if (r <= 0)
326 return r;
327
328 break;
329
57ce4bd4
ZJS
330 case '?':
331 return -EINVAL;
332
5de0409e 333 default:
eb9da376 334 assert_not_reached("Unhandled option");
5de0409e
ZJS
335 }
336
32485d09 337 if (arg_since != USEC_INFINITY && arg_until != USEC_INFINITY &&
baaa35ad
ZJS
338 arg_since > arg_until)
339 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
340 "--since= must be before --until=.");
32485d09 341
5ce97d33 342 return 1;
5de0409e
ZJS
343}
344
8bc8ab83
LP
345static int retrieve(const void *data,
346 size_t len,
347 const char *name,
a276ae74 348 char **var) {
5de0409e 349
4f76ae1b 350 size_t ident;
a276ae74 351 char *v;
8bc8ab83 352
4f76ae1b 353 ident = strlen(name) + 1; /* name + "=" */
8bc8ab83 354
4f76ae1b 355 if (len < ident)
8bc8ab83 356 return 0;
5de0409e 357
4f76ae1b 358 if (memcmp(data, name, ident - 1) != 0)
8bc8ab83
LP
359 return 0;
360
4f76ae1b 361 if (((const char*) data)[ident - 1] != '=')
8bc8ab83 362 return 0;
5de0409e 363
a276ae74
LP
364 v = strndup((const char*)data + ident, len - ident);
365 if (!v)
5de0409e
ZJS
366 return log_oom();
367
eba048bb 368 free_and_replace(*var, v);
062b99e8 369 return 1;
5de0409e
ZJS
370}
371
062b99e8 372static int print_field(FILE* file, sd_journal *j) {
4f76ae1b
ZJS
373 const void *d;
374 size_t l;
375
e15758cc
LP
376 assert(file);
377 assert(j);
378
a276ae74 379 assert(arg_field);
4f76ae1b 380
062b99e8 381 /* A (user-specified) field may appear more than once for a given entry.
5238e957 382 * We will print all of the occurrences.
062b99e8
ZJS
383 * This is different below for fields that systemd-coredump uses,
384 * because they cannot meaningfully appear more than once.
385 */
386 SD_JOURNAL_FOREACH_DATA(j, d, l) {
387 _cleanup_free_ char *value = NULL;
388 int r;
389
390 r = retrieve(d, l, arg_field, &value);
391 if (r < 0)
392 return r;
393 if (r > 0)
394 fprintf(file, "%s\n", value);
395 }
a276ae74 396
062b99e8 397 return 0;
4f76ae1b
ZJS
398}
399
062b99e8
ZJS
400#define RETRIEVE(d, l, name, arg) \
401 { \
402 int _r = retrieve(d, l, name, &arg); \
403 if (_r < 0) \
404 return _r; \
405 if (_r > 0) \
406 continue; \
407 }
408
4016281c
LP
409static void analyze_coredump_file(
410 const char *path,
411 const char **ret_state,
412 const char **ret_color,
413 uint64_t *ret_size) {
414
415 _cleanup_close_ int fd = -1;
416 struct stat st;
417 int r;
418
419 assert(path);
420 assert(ret_state);
421 assert(ret_color);
422 assert(ret_size);
423
424 fd = open(path, O_PATH|O_CLOEXEC);
425 if (fd < 0) {
426 if (errno == ENOENT) {
427 *ret_state = "missing";
428 *ret_color = ansi_grey();
429 *ret_size = UINT64_MAX;
430 return;
431 }
432
433 r = -errno;
434 } else
435 r = access_fd(fd, R_OK);
436 if (ERRNO_IS_PRIVILEGE(r)) {
437 *ret_state = "inaccessible";
438 *ret_color = ansi_highlight_yellow();
439 *ret_size = UINT64_MAX;
440 return;
441 }
442 if (r < 0)
443 goto error;
444
445 if (fstat(fd, &st) < 0)
446 goto error;
447
448 if (!S_ISREG(st.st_mode))
449 goto error;
450
451 *ret_state = "present";
452 *ret_color = NULL;
453 *ret_size = st.st_size;
454 return;
455
456error:
457 *ret_state = "error";
458 *ret_color = ansi_highlight_red();
459 *ret_size = UINT64_MAX;
460}
461
0689cfdb 462static int print_list(FILE* file, sd_journal *j, Table *t) {
a276ae74 463 _cleanup_free_ char
a7581ff9 464 *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
9fe13294 465 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
cc4419ed 466 *filename = NULL, *truncated = NULL, *coredump = NULL;
8bc8ab83
LP
467 const void *d;
468 size_t l;
0689cfdb
LP
469 usec_t ts;
470 int r, signal_as_int = 0;
4016281c
LP
471 const char *present = NULL, *color = NULL;
472 uint64_t size = UINT64_MAX;
a7581ff9 473 bool normal_coredump;
0689cfdb
LP
474 uid_t uid_as_int = UID_INVALID;
475 gid_t gid_as_int = GID_INVALID;
476 pid_t pid_as_int = 0;
8bc8ab83 477
e15758cc
LP
478 assert(file);
479 assert(j);
0689cfdb 480 assert(t);
e15758cc 481
8bc8ab83 482 SD_JOURNAL_FOREACH_DATA(j, d, l) {
a7581ff9 483 RETRIEVE(d, l, "MESSAGE_ID", mid);
062b99e8
ZJS
484 RETRIEVE(d, l, "COREDUMP_PID", pid);
485 RETRIEVE(d, l, "COREDUMP_UID", uid);
486 RETRIEVE(d, l, "COREDUMP_GID", gid);
487 RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl);
488 RETRIEVE(d, l, "COREDUMP_EXE", exe);
489 RETRIEVE(d, l, "COREDUMP_COMM", comm);
490 RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline);
491 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
cc4419ed 492 RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
062b99e8 493 RETRIEVE(d, l, "COREDUMP", coredump);
8bc8ab83 494 }
5de0409e 495
0689cfdb
LP
496 if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename)
497 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Empty coredump log entry");
684341b0 498
0689cfdb
LP
499 (void) parse_uid(uid, &uid_as_int);
500 (void) parse_gid(gid, &gid_as_int);
501 (void) parse_pid(pid, &pid_as_int);
502 signal_as_int = signal_from_string(sgnl);
503
504 r = sd_journal_get_realtime_usec(j, &ts);
23bbb0de
MS
505 if (r < 0)
506 return log_error_errno(r, "Failed to get realtime timestamp: %m");
5de0409e 507
a7581ff9
ZJS
508 normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
509
04de5879 510 if (filename)
4016281c 511 analyze_coredump_file(filename, &present, &color, &size);
04de5879
ZJS
512 else if (coredump)
513 present = "journal";
0689cfdb 514 else if (normal_coredump) {
04de5879 515 present = "none";
0689cfdb
LP
516 color = ansi_grey();
517 } else
518 present = NULL;
04de5879 519
0689cfdb 520 if (STRPTR_IN_SET(present, "present", "journal") && truncated && parse_boolean(truncated) > 0)
cc4419ed
ZJS
521 present = "truncated";
522
0689cfdb
LP
523 r = table_add_many(
524 t,
525 TABLE_TIMESTAMP, ts,
526 TABLE_PID, pid_as_int,
527 TABLE_UID, uid_as_int,
528 TABLE_GID, gid_as_int,
529 TABLE_SIGNAL, normal_coredump ? signal_as_int : 0,
530 TABLE_STRING, present,
531 TABLE_SET_COLOR, color,
4016281c
LP
532 TABLE_STRING, exe ?: comm ?: cmdline,
533 TABLE_SIZE, size);
0689cfdb
LP
534 if (r < 0)
535 return table_log_add_error(r);
684341b0
LP
536
537 return 0;
5de0409e
ZJS
538}
539
e15758cc
LP
540static int print_info(FILE *file, sd_journal *j, bool need_space) {
541 _cleanup_free_ char
a7581ff9 542 *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
e15758cc
LP
543 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
544 *unit = NULL, *user_unit = NULL, *session = NULL,
a035f819 545 *boot_id = NULL, *machine_id = NULL, *hostname = NULL,
9fe13294 546 *slice = NULL, *cgroup = NULL, *owner_uid = NULL,
47f50642 547 *message = NULL, *timestamp = NULL, *filename = NULL,
cc4419ed 548 *truncated = NULL, *coredump = NULL;
e15758cc
LP
549 const void *d;
550 size_t l;
a7581ff9 551 bool normal_coredump;
4b8cbe9a 552 int r;
e15758cc
LP
553
554 assert(file);
555 assert(j);
556
557 SD_JOURNAL_FOREACH_DATA(j, d, l) {
a7581ff9 558 RETRIEVE(d, l, "MESSAGE_ID", mid);
062b99e8
ZJS
559 RETRIEVE(d, l, "COREDUMP_PID", pid);
560 RETRIEVE(d, l, "COREDUMP_UID", uid);
561 RETRIEVE(d, l, "COREDUMP_GID", gid);
562 RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl);
563 RETRIEVE(d, l, "COREDUMP_EXE", exe);
564 RETRIEVE(d, l, "COREDUMP_COMM", comm);
565 RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline);
07461598 566 RETRIEVE(d, l, "COREDUMP_HOSTNAME", hostname);
062b99e8
ZJS
567 RETRIEVE(d, l, "COREDUMP_UNIT", unit);
568 RETRIEVE(d, l, "COREDUMP_USER_UNIT", user_unit);
569 RETRIEVE(d, l, "COREDUMP_SESSION", session);
570 RETRIEVE(d, l, "COREDUMP_OWNER_UID", owner_uid);
571 RETRIEVE(d, l, "COREDUMP_SLICE", slice);
572 RETRIEVE(d, l, "COREDUMP_CGROUP", cgroup);
573 RETRIEVE(d, l, "COREDUMP_TIMESTAMP", timestamp);
574 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
cc4419ed 575 RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
062b99e8
ZJS
576 RETRIEVE(d, l, "COREDUMP", coredump);
577 RETRIEVE(d, l, "_BOOT_ID", boot_id);
578 RETRIEVE(d, l, "_MACHINE_ID", machine_id);
062b99e8 579 RETRIEVE(d, l, "MESSAGE", message);
e15758cc
LP
580 }
581
582 if (need_space)
583 fputs("\n", file);
584
a7581ff9
ZJS
585 normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
586
81cef14f
LP
587 if (comm)
588 fprintf(file,
589 " PID: %s%s%s (%s)\n",
1fc464f6 590 ansi_highlight(), strna(pid), ansi_normal(), comm);
81cef14f
LP
591 else
592 fprintf(file,
593 " PID: %s%s%s\n",
1fc464f6 594 ansi_highlight(), strna(pid), ansi_normal());
a035f819
LP
595
596 if (uid) {
597 uid_t n;
598
599 if (parse_uid(uid, &n) >= 0) {
600 _cleanup_free_ char *u = NULL;
601
602 u = uid_to_name(n);
603 fprintf(file,
604 " UID: %s (%s)\n",
605 uid, u);
606 } else {
607 fprintf(file,
608 " UID: %s\n",
609 uid);
610 }
611 }
612
613 if (gid) {
614 gid_t n;
615
616 if (parse_gid(gid, &n) >= 0) {
617 _cleanup_free_ char *g = NULL;
618
619 g = gid_to_name(n);
620 fprintf(file,
621 " GID: %s (%s)\n",
622 gid, g);
623 } else {
624 fprintf(file,
625 " GID: %s\n",
626 gid);
627 }
628 }
e15758cc
LP
629
630 if (sgnl) {
631 int sig;
a7581ff9 632 const char *name = normal_coredump ? "Signal" : "Reason";
e15758cc 633
a7581ff9
ZJS
634 if (normal_coredump && safe_atoi(sgnl, &sig) >= 0)
635 fprintf(file, " %s: %s (%s)\n", name, sgnl, signal_to_string(sig));
e15758cc 636 else
a7581ff9 637 fprintf(file, " %s: %s\n", name, sgnl);
e15758cc
LP
638 }
639
4b8cbe9a
LP
640 if (timestamp) {
641 usec_t u;
642
643 r = safe_atou64(timestamp, &u);
644 if (r >= 0) {
645 char absolute[FORMAT_TIMESTAMP_MAX], relative[FORMAT_TIMESPAN_MAX];
646
647 fprintf(file,
648 " Timestamp: %s (%s)\n",
649 format_timestamp(absolute, sizeof(absolute), u),
650 format_timestamp_relative(relative, sizeof(relative), u));
651
652 } else
653 fprintf(file, " Timestamp: %s\n", timestamp);
654 }
655
e15758cc
LP
656 if (cmdline)
657 fprintf(file, " Command Line: %s\n", cmdline);
81cef14f 658 if (exe)
1fc464f6 659 fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_normal());
a035f819
LP
660 if (cgroup)
661 fprintf(file, " Control Group: %s\n", cgroup);
e15758cc
LP
662 if (unit)
663 fprintf(file, " Unit: %s\n", unit);
664 if (user_unit)
554ed50f 665 fprintf(file, " User Unit: %s\n", user_unit);
a035f819
LP
666 if (slice)
667 fprintf(file, " Slice: %s\n", slice);
e15758cc
LP
668 if (session)
669 fprintf(file, " Session: %s\n", session);
a035f819
LP
670 if (owner_uid) {
671 uid_t n;
672
673 if (parse_uid(owner_uid, &n) >= 0) {
674 _cleanup_free_ char *u = NULL;
675
676 u = uid_to_name(n);
677 fprintf(file,
678 " Owner UID: %s (%s)\n",
679 owner_uid, u);
680 } else {
681 fprintf(file,
682 " Owner UID: %s\n",
683 owner_uid);
684 }
685 }
e15758cc
LP
686 if (boot_id)
687 fprintf(file, " Boot ID: %s\n", boot_id);
688 if (machine_id)
689 fprintf(file, " Machine ID: %s\n", machine_id);
690 if (hostname)
691 fprintf(file, " Hostname: %s\n", hostname);
692
cc4419ed 693 if (filename) {
4016281c
LP
694 const char *state = NULL, *color = NULL;
695 uint64_t size = UINT64_MAX;
696 char buf[FORMAT_BYTES_MAX];
cc4419ed 697
4016281c
LP
698 analyze_coredump_file(filename, &state, &color, &size);
699
700 if (STRPTR_IN_SET(state, "present", "journal") && truncated && parse_boolean(truncated) > 0)
701 state = "truncated";
702
703 fprintf(file,
704 " Storage: %s%s (%s)%s\n",
705 strempty(color),
706 filename,
707 state,
708 ansi_normal());
709
710 if (size != UINT64_MAX)
711 fprintf(file,
712 " Disk Size: %s\n",
713 format_bytes(buf, sizeof(buf), size));
714 } else if (coredump)
47f50642
ZJS
715 fprintf(file, " Storage: journal\n");
716 else
717 fprintf(file, " Storage: none\n");
e15758cc 718
8d4e028f
LP
719 if (message) {
720 _cleanup_free_ char *m = NULL;
721
722 m = strreplace(message, "\n", "\n ");
723
724 fprintf(file, " Message: %s\n", strstrip(m ?: message));
725 }
726
e15758cc
LP
727 return 0;
728}
729
ada45c78 730static int focus(sd_journal *j) {
5de0409e
ZJS
731 int r;
732
5de0409e
ZJS
733 r = sd_journal_seek_tail(j);
734 if (r == 0)
735 r = sd_journal_previous(j);
23bbb0de
MS
736 if (r < 0)
737 return log_error_errno(r, "Failed to search journal: %m");
baaa35ad
ZJS
738 if (r == 0)
739 return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
740 "No match found.");
ada45c78
LP
741 return r;
742}
5de0409e 743
0689cfdb
LP
744static int print_entry(
745 sd_journal *j,
746 size_t n_found,
747 Table *t) {
748
0c51aada
LP
749 assert(j);
750
0689cfdb
LP
751 if (t)
752 return print_list(stdout, j, t);
0c51aada 753 else if (arg_field)
062b99e8 754 return print_field(stdout, j);
0c51aada 755 else
0689cfdb 756 return print_info(stdout, j, n_found > 0);
0c51aada
LP
757}
758
5ce97d33
YW
759static int dump_list(int argc, char **argv, void *userdata) {
760 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
0689cfdb
LP
761 _cleanup_(table_unrefp) Table *t = NULL;
762 size_t n_found = 0;
5ce97d33 763 bool verb_is_info;
0c51aada
LP
764 int r;
765
0689cfdb 766 verb_is_info = argc >= 1 && streq(argv[0], "info");
5ce97d33
YW
767
768 r = acquire_journal(&j, argv + 1);
769 if (r < 0)
770 return r;
771
0689cfdb
LP
772 /* The coredumps are likely compressed, and for just listing them we don't need to decompress them,
773 * so let's pick a fairly low data threshold here */
774 (void) sd_journal_set_data_threshold(j, 4096);
0c51aada 775
0689cfdb 776 if (!verb_is_info && !arg_field) {
4016281c 777 t = table_new("time", "pid", "uid", "gid", "sig", "corefile", "exe", "size");
0689cfdb
LP
778 if (!t)
779 return log_oom();
780
781 (void) table_set_align_percent(t, TABLE_HEADER_CELL(1), 100);
782 (void) table_set_align_percent(t, TABLE_HEADER_CELL(2), 100);
783 (void) table_set_align_percent(t, TABLE_HEADER_CELL(3), 100);
4016281c 784 (void) table_set_align_percent(t, TABLE_HEADER_CELL(7), 100);
0689cfdb
LP
785
786 (void) table_set_empty_string(t, "-");
787 } else
788 (void) pager_open(arg_pager_flags);
0c51aada 789
2fafabfd 790 /* "info" without pattern implies "-1" */
0689cfdb 791 if ((arg_rows_max == 1 && arg_reverse) || (verb_is_info && argc == 1)) {
0c51aada
LP
792 r = focus(j);
793 if (r < 0)
794 return r;
795
0689cfdb
LP
796 r = print_entry(j, 0, t);
797 if (r < 0)
798 return r;
0c51aada 799 } else {
32485d09
GS
800 if (arg_since != USEC_INFINITY && !arg_reverse)
801 r = sd_journal_seek_realtime_usec(j, arg_since);
802 else if (arg_until != USEC_INFINITY && arg_reverse)
803 r = sd_journal_seek_realtime_usec(j, arg_until);
804 else if (arg_reverse)
805 r = sd_journal_seek_tail(j);
806 else
807 r = sd_journal_seek_head(j);
808 if (r < 0)
809 return log_error_errno(r, "Failed to seek to date: %m");
810
811 for (;;) {
812 if (!arg_reverse)
813 r = sd_journal_next(j);
814 else
815 r = sd_journal_previous(j);
32485d09
GS
816 if (r < 0)
817 return log_error_errno(r, "Failed to iterate through journal: %m");
32485d09
GS
818 if (r == 0)
819 break;
820
821 if (arg_until != USEC_INFINITY && !arg_reverse) {
822 usec_t usec;
823
824 r = sd_journal_get_realtime_usec(j, &usec);
df65f77b 825 if (r < 0)
32485d09
GS
826 return log_error_errno(r, "Failed to determine timestamp: %m");
827 if (usec > arg_until)
828 continue;
df65f77b 829 }
32485d09
GS
830
831 if (arg_since != USEC_INFINITY && arg_reverse) {
832 usec_t usec;
833
834 r = sd_journal_get_realtime_usec(j, &usec);
df65f77b 835 if (r < 0)
32485d09
GS
836 return log_error_errno(r, "Failed to determine timestamp: %m");
837 if (usec < arg_since)
838 continue;
df65f77b 839 }
32485d09 840
0689cfdb 841 r = print_entry(j, n_found++, t);
32485d09
GS
842 if (r < 0)
843 return r;
0689cfdb
LP
844
845 if (arg_rows_max != SIZE_MAX && n_found >= arg_rows_max)
846 break;
062b99e8 847 }
0c51aada
LP
848
849 if (!arg_field && n_found <= 0) {
b9aaa7f4
ZJS
850 if (!arg_quiet)
851 log_notice("No coredumps found.");
0c51aada
LP
852 return -ESRCH;
853 }
854 }
855
0689cfdb
LP
856 if (t) {
857 r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
858 if (r < 0)
859 return r;
860 }
861
0c51aada
LP
862 return 0;
863}
864
bb7c5bad 865static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp) {
9fe13294
ZJS
866 const char *data;
867 _cleanup_free_ char *filename = NULL;
868 size_t len;
bb7c5bad 869 int r, fd;
fc6cec86
ZJS
870 _cleanup_close_ int fdt = -1;
871 char *temp = NULL;
ada45c78 872
bb7c5bad
ZJS
873 assert(!(file && path)); /* At most one can be specified */
874 assert(!!path == !!unlink_temp); /* Those must be specified together */
47f50642 875
fc6cec86 876 /* Look for a coredump on disk first. */
9fe13294 877 r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
2d0a880f
ZJS
878 if (r == 0) {
879 r = retrieve(data, len, "COREDUMP_FILENAME", &filename);
880 if (r < 0)
881 return r;
882 assert(r > 0);
883
884 if (access(filename, R_OK) < 0)
885 return log_error_errno(errno, "File \"%s\" is not readable: %m", filename);
886
ef5924aa 887 if (path && !ENDSWITH_SET(filename, ".xz", ".lz4", ".zst")) {
2d0a880f
ZJS
888 *path = TAKE_PTR(filename);
889
890 return 0;
891 }
892
893 } else {
bb7c5bad
ZJS
894 if (r != -ENOENT)
895 return log_error_errno(r, "Failed to retrieve COREDUMP_FILENAME field: %m");
896 /* Check that we can have a COREDUMP field. We still haven't set a high
897 * data threshold, so we'll get a few kilobytes at most.
898 */
899
900 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
901 if (r == -ENOENT)
902 return log_error_errno(r, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).");
903 if (r < 0)
904 return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
905 }
93b73b06 906
bb7c5bad 907 if (path) {
fc6cec86 908 const char *vt;
992e8f22 909
fc6cec86 910 /* Create a temporary file to write the uncompressed core to. */
992e8f22 911
fc6cec86
ZJS
912 r = var_tmp_dir(&vt);
913 if (r < 0)
914 return log_error_errno(r, "Failed to acquire temporary directory path: %m");
9fe13294 915
657ee2d8 916 temp = path_join(vt, "coredump-XXXXXX");
fc6cec86
ZJS
917 if (!temp)
918 return log_oom();
9fe13294 919
fc6cec86
ZJS
920 fdt = mkostemp_safe(temp);
921 if (fdt < 0)
922 return log_error_errno(fdt, "Failed to create temporary file: %m");
923 log_debug("Created temporary file %s", temp);
9fe13294 924
fc6cec86 925 fd = fdt;
bb7c5bad
ZJS
926 } else {
927 /* If neither path or file are specified, we will write to stdout. Let's now check
928 * if stdout is connected to a tty. We checked that the file exists, or that the
929 * core might be stored in the journal. In this second case, if we found the entry,
5238e957 930 * in all likelihood we will be able to access the COREDUMP= field. In either case,
bb7c5bad
ZJS
931 * we stop before doing any "real" work, i.e. before starting decompression or
932 * reading from the file or creating temporary files.
933 */
934 if (!file) {
935 if (on_tty())
886cf317
ZJS
936 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
937 "Refusing to dump core to tty"
bb7c5bad
ZJS
938 " (use shell redirection or specify --output).");
939 file = stdout;
940 }
941
942 fd = fileno(file);
fc6cec86
ZJS
943 }
944
945 if (filename) {
d80b051c 946#if HAVE_COMPRESSION
fc6cec86 947 _cleanup_close_ int fdf;
9fe13294 948
fc6cec86
ZJS
949 fdf = open(filename, O_RDONLY | O_CLOEXEC);
950 if (fdf < 0) {
951 r = log_error_errno(errno, "Failed to open %s: %m", filename);
2fb8159f 952 goto error;
fc6cec86
ZJS
953 }
954
955 r = decompress_stream(filename, fdf, fd, -1);
956 if (r < 0) {
957 log_error_errno(r, "Failed to decompress %s: %m", filename);
9fe13294
ZJS
958 goto error;
959 }
fc6cec86 960#else
3afe5c00
LP
961 r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
962 "Cannot decompress file. Compiled without compression support.");
fc6cec86
ZJS
963 goto error;
964#endif
965 } else {
966 ssize_t sz;
a276ae74 967
bb7c5bad
ZJS
968 /* We want full data, nothing truncated. */
969 sd_journal_set_data_threshold(j, 0);
970
fc6cec86
ZJS
971 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
972 if (r < 0)
bb7c5bad 973 return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
fc6cec86
ZJS
974
975 assert(len >= 9);
976 data += 9;
977 len -= 9;
978
954d3a51 979 sz = write(fd, data, len);
fc6cec86 980 if (sz < 0) {
954d3a51 981 r = log_error_errno(errno, "Failed to write output: %m");
fc6cec86 982 goto error;
a276ae74 983 }
fc6cec86 984 if (sz != (ssize_t) len) {
954d3a51 985 log_error("Short write to output.");
fc6cec86
ZJS
986 r = -EIO;
987 goto error;
988 }
989 }
a276ae74 990
fc6cec86
ZJS
991 if (temp) {
992 *path = temp;
993 *unlink_temp = true;
994 }
995 return 0;
9fe13294
ZJS
996
997error:
fc6cec86 998 if (temp) {
6990fb6b 999 (void) unlink(temp);
fc6cec86 1000 log_debug("Removed temporary file %s", temp);
9fe13294 1001 }
fc6cec86 1002 return r;
9fe13294 1003}
a276ae74 1004
5ce97d33
YW
1005static int dump_core(int argc, char **argv, void *userdata) {
1006 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
158ecef5 1007 _cleanup_fclose_ FILE *f = NULL;
9fe13294
ZJS
1008 int r;
1009
d7a0f1f4
FS
1010 if (arg_field)
1011 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1012 "Option --field/-F only makes sense with list");
5ce97d33
YW
1013
1014 r = acquire_journal(&j, argv + 1);
1015 if (r < 0)
1016 return r;
9fe13294
ZJS
1017
1018 r = focus(j);
1019 if (r < 0)
ada45c78 1020 return r;
ada45c78 1021
158ecef5
ZJS
1022 if (arg_output) {
1023 f = fopen(arg_output, "we");
1024 if (!f)
1025 return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", arg_output);
1026 }
1027
1028 print_info(f ? stdout : stderr, j, false);
9fe13294 1029
158ecef5 1030 r = save_core(j, f, NULL, NULL);
23bbb0de 1031 if (r < 0)
bb7c5bad 1032 return r;
5de0409e
ZJS
1033
1034 r = sd_journal_previous(j);
b9aaa7f4
ZJS
1035 if (r > 0 && !arg_quiet)
1036 log_notice("More than one entry matches, ignoring rest.");
5de0409e
ZJS
1037
1038 return 0;
1039}
1040
c5896b6a 1041static int run_debug(int argc, char **argv, void *userdata) {
5ce97d33 1042 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
a2be8be2
MF
1043 _cleanup_free_ char *exe = NULL, *path = NULL;
1044 _cleanup_strv_free_ char **debugger_call = NULL;
9fe13294 1045 bool unlink_path = false;
c5896b6a 1046 const char *data, *fork_name;
ada45c78 1047 size_t len;
ada45c78 1048 pid_t pid;
ada45c78 1049 int r;
ada45c78 1050
c5896b6a
RG
1051 if (!arg_debugger) {
1052 char *env_debugger;
1053
1054 env_debugger = getenv("SYSTEMD_DEBUGGER");
1055 if (env_debugger)
1056 arg_debugger = env_debugger;
1057 else
1058 arg_debugger = "gdb";
1059 }
1060
a2be8be2
MF
1061 r = strv_extend(&debugger_call, arg_debugger);
1062 if (r < 0)
1063 return log_oom();
1064
1065 r = strv_extend_strv(&debugger_call, arg_debugger_args, false);
1066 if (r < 0)
1067 return log_oom();
3f0d8b2d 1068
d7a0f1f4
FS
1069 if (arg_field)
1070 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1071 "Option --field/-F only makes sense with list");
5ce97d33
YW
1072
1073 r = acquire_journal(&j, argv + 1);
1074 if (r < 0)
1075 return r;
ada45c78
LP
1076
1077 r = focus(j);
1078 if (r < 0)
1079 return r;
1080
a174da59
FS
1081 if (!arg_quiet) {
1082 print_info(stdout, j, false);
1083 fputs("\n", stdout);
1084 }
ada45c78
LP
1085
1086 r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len);
23bbb0de
MS
1087 if (r < 0)
1088 return log_error_errno(r, "Failed to retrieve COREDUMP_EXE field: %m");
ada45c78 1089
fbd0b64f
LP
1090 assert(len > STRLEN("COREDUMP_EXE="));
1091 data += STRLEN("COREDUMP_EXE=");
1092 len -= STRLEN("COREDUMP_EXE=");
ada45c78
LP
1093
1094 exe = strndup(data, len);
1095 if (!exe)
1096 return log_oom();
1097
d7a0f1f4
FS
1098 if (endswith(exe, " (deleted)"))
1099 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
1100 "Binary already deleted.");
ada45c78 1101
d7a0f1f4
FS
1102 if (!path_is_absolute(exe))
1103 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
1104 "Binary is not an absolute path.");
a276ae74 1105
bb7c5bad 1106 r = save_core(j, NULL, &path, &unlink_path);
23bbb0de 1107 if (r < 0)
bb7c5bad 1108 return r;
ada45c78 1109
a2be8be2
MF
1110 r = strv_extend_strv(&debugger_call, STRV_MAKE(exe, "-c", path), false);
1111 if (r < 0)
1112 return log_oom();
1113
3e7bc89b 1114 /* Don't interfere with gdb and its handling of SIGINT. */
9c274488 1115 (void) ignore_signals(SIGINT);
3e7bc89b 1116
a2be8be2 1117 fork_name = strjoina("(", debugger_call[0], ")");
c5896b6a 1118
48f813c4 1119 r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_FLUSH_STDIO, &pid);
b6e1fff1 1120 if (r < 0)
ada45c78 1121 goto finish;
4c253ed1 1122 if (r == 0) {
a2be8be2 1123 execvp(debugger_call[0], debugger_call);
0b1f3c76 1124 log_open();
a2be8be2 1125 log_error_errno(errno, "Failed to invoke %s: %m", debugger_call[0]);
a45d7127 1126 _exit(EXIT_FAILURE);
ada45c78
LP
1127 }
1128
a2be8be2 1129 r = wait_for_terminate_and_check(debugger_call[0], pid, WAIT_LOG_ABNORMAL);
ada45c78
LP
1130
1131finish:
9c274488 1132 (void) default_signals(SIGINT);
3e7bc89b 1133
9fe13294
ZJS
1134 if (unlink_path) {
1135 log_debug("Removed temporary file %s", path);
6990fb6b 1136 (void) unlink(path);
9fe13294 1137 }
a276ae74 1138
ada45c78
LP
1139 return r;
1140}
1141
012f2b7d 1142static int check_units_active(void) {
7add4883 1143 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
012f2b7d
ZJS
1144 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1145 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1146 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1147 int c = 0, r;
7bbf2d84 1148 const char *id, *state, *substate;
012f2b7d 1149
b9aaa7f4
ZJS
1150 if (arg_quiet)
1151 return false;
1152
012f2b7d
ZJS
1153 r = sd_bus_default_system(&bus);
1154 if (r < 0)
1155 return log_error_errno(r, "Failed to acquire bus: %m");
1156
1157 r = sd_bus_message_new_method_call(
1158 bus,
1159 &m,
1160 "org.freedesktop.systemd1",
1161 "/org/freedesktop/systemd1",
1162 "org.freedesktop.systemd1.Manager",
1163 "ListUnitsByPatterns");
1164 if (r < 0)
1165 return bus_log_create_error(r);
1166
1167 r = sd_bus_message_append_strv(m, NULL);
1168 if (r < 0)
1169 return bus_log_create_error(r);
1170
1171 r = sd_bus_message_append_strv(m, STRV_MAKE("systemd-coredump@*.service"));
1172 if (r < 0)
1173 return bus_log_create_error(r);
1174
501551e8 1175 r = sd_bus_call(bus, m, SHORT_BUS_CALL_TIMEOUT_USEC, &error, &reply);
012f2b7d
ZJS
1176 if (r < 0)
1177 return log_error_errno(r, "Failed to check if any systemd-coredump@.service units are running: %s",
1178 bus_error_message(&error, r));
1179
1180 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
1181 if (r < 0)
1182 return bus_log_parse_error(r);
1183
1184 while ((r = sd_bus_message_read(
1185 reply, "(ssssssouso)",
7bbf2d84
ZJS
1186 &id, NULL, NULL, &state, &substate,
1187 NULL, NULL, NULL, NULL, NULL)) > 0) {
eb5877a0 1188 bool found = !STR_IN_SET(state, "inactive", "dead", "failed");
7bbf2d84
ZJS
1189 log_debug("Unit %s is %s/%s, %scounting it.", id, state, substate, found ? "" : "not ");
1190 c += found;
1191 }
012f2b7d
ZJS
1192 if (r < 0)
1193 return bus_log_parse_error(r);
1194
1195 r = sd_bus_message_exit_container(reply);
1196 if (r < 0)
1197 return bus_log_parse_error(r);
1198
1199 return c;
1200}
1201
5ce97d33
YW
1202static int coredumpctl_main(int argc, char *argv[]) {
1203
1204 static const Verb verbs[] = {
c5896b6a
RG
1205 { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, dump_list },
1206 { "info", VERB_ANY, VERB_ANY, 0, dump_list },
1207 { "dump", VERB_ANY, VERB_ANY, 0, dump_core },
1208 { "debug", VERB_ANY, VERB_ANY, 0, run_debug },
1209 { "gdb", VERB_ANY, VERB_ANY, 0, run_debug },
5ce97d33
YW
1210 {}
1211 };
1212
1213 return dispatch_verb(argc, argv, verbs, NULL);
1214}
1215
c118b577 1216static int run(int argc, char *argv[]) {
5ce97d33 1217 int r, units_active;
5de0409e 1218
a9cdc94f 1219 setlocale(LC_ALL, "");
d2acb93d 1220 log_setup();
5de0409e 1221
1abaf488
LP
1222 /* The journal merging logic potentially needs a lot of fds. */
1223 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
1224
5ab9ed07 1225 r = parse_argv(argc, argv);
5ce97d33 1226 if (r <= 0)
c118b577 1227 return r;
5de0409e 1228
2cf4172a
LP
1229 sigbus_install();
1230
012f2b7d
ZJS
1231 units_active = check_units_active(); /* error is treated the same as 0 */
1232
5ce97d33 1233 r = coredumpctl_main(argc, argv);
5de0409e 1234
012f2b7d
ZJS
1235 if (units_active > 0)
1236 printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n",
1237 ansi_highlight_red(),
1238 units_active, units_active == 1 ? "unit is running" : "units are running",
1239 ansi_normal());
aeb56450 1240
c118b577 1241 return r;
5de0409e 1242}
c118b577
ZJS
1243
1244DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);