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