]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/coredump/coredumpctl.c
Merge pull request #5131 from keszybz/environment-generators
[thirdparty/systemd.git] / src / coredump / coredumpctl.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2012 Zbigniew Jędrzejewski-Szmek
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <locale.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "sd-bus.h"
28 #include "sd-journal.h"
29 #include "sd-messages.h"
30
31 #include "alloc-util.h"
32 #include "bus-error.h"
33 #include "bus-util.h"
34 #include "compress.h"
35 #include "fd-util.h"
36 #include "fileio.h"
37 #include "fs-util.h"
38 #include "journal-internal.h"
39 #include "log.h"
40 #include "macro.h"
41 #include "pager.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "process-util.h"
45 #include "sigbus.h"
46 #include "signal-util.h"
47 #include "string-util.h"
48 #include "strv.h"
49 #include "terminal-util.h"
50 #include "user-util.h"
51 #include "util.h"
52
53 static enum {
54 ACTION_NONE,
55 ACTION_INFO,
56 ACTION_LIST,
57 ACTION_DUMP,
58 ACTION_GDB,
59 } arg_action = ACTION_LIST;
60 static const char* arg_field = NULL;
61 static const char *arg_directory = NULL;
62 static bool arg_no_pager = false;
63 static int arg_no_legend = false;
64 static int arg_one = false;
65 static FILE* arg_output = NULL;
66 static bool arg_reverse = false;
67 static char** arg_matches = NULL;
68
69 static int add_match(sd_journal *j, const char *match) {
70 _cleanup_free_ char *p = NULL;
71 char *pattern = NULL;
72 const char* prefix;
73 pid_t pid;
74 int r;
75
76 if (strchr(match, '='))
77 prefix = "";
78 else if (strchr(match, '/')) {
79 r = path_make_absolute_cwd(match, &p);
80 if (r < 0)
81 return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match);
82
83 match = p;
84 prefix = "COREDUMP_EXE=";
85 } else if (parse_pid(match, &pid) >= 0)
86 prefix = "COREDUMP_PID=";
87 else
88 prefix = "COREDUMP_COMM=";
89
90 pattern = strjoin(prefix, match);
91 if (!pattern)
92 return log_oom();
93
94 log_debug("Adding match: %s", pattern);
95 r = sd_journal_add_match(j, pattern, 0);
96 if (r < 0)
97 return log_error_errno(r, "Failed to add match \"%s\": %m", match);
98 return 0;
99 }
100
101 static int add_matches(sd_journal *j) {
102 char **match;
103 int r;
104
105 r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0);
106 if (r < 0)
107 return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
108
109 r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR, 0);
110 if (r < 0)
111 return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
112
113 STRV_FOREACH(match, arg_matches) {
114 r = add_match(j, *match);
115 if (r < 0)
116 return r;
117 }
118
119 return 0;
120 }
121
122 static void help(void) {
123 printf("%s [OPTIONS...]\n\n"
124 "List or retrieve coredumps from the journal.\n\n"
125 "Flags:\n"
126 " -h --help Show this help\n"
127 " --version Print version string\n"
128 " --no-pager Do not pipe output into a pager\n"
129 " --no-legend Do not print the column headers.\n"
130 " -1 Show information about most recent entry only\n"
131 " -r --reverse Show the newest entries first\n"
132 " -F --field=FIELD List all values a certain field takes\n"
133 " -o --output=FILE Write output to FILE\n"
134 " -D --directory=DIR Use journal files from directory\n\n"
135
136 "Commands:\n"
137 " list [MATCHES...] List available coredumps (default)\n"
138 " info [MATCHES...] Show detailed information about one or more coredumps\n"
139 " dump [MATCHES...] Print first matching coredump to stdout\n"
140 " gdb [MATCHES...] Start gdb for the first matching coredump\n"
141 , program_invocation_short_name);
142 }
143
144 static int parse_argv(int argc, char *argv[]) {
145 enum {
146 ARG_VERSION = 0x100,
147 ARG_NO_PAGER,
148 ARG_NO_LEGEND,
149 };
150
151 int c;
152
153 static const struct option options[] = {
154 { "help", no_argument, NULL, 'h' },
155 { "version" , no_argument, NULL, ARG_VERSION },
156 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
157 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
158 { "output", required_argument, NULL, 'o' },
159 { "field", required_argument, NULL, 'F' },
160 { "directory", required_argument, NULL, 'D' },
161 { "reverse", no_argument, NULL, 'r' },
162 {}
163 };
164
165 assert(argc >= 0);
166 assert(argv);
167
168 while ((c = getopt_long(argc, argv, "ho:F:1D:r", options, NULL)) >= 0)
169 switch(c) {
170
171 case 'h':
172 arg_action = ACTION_NONE;
173 help();
174 return 0;
175
176 case ARG_VERSION:
177 arg_action = ACTION_NONE;
178 return version();
179
180 case ARG_NO_PAGER:
181 arg_no_pager = true;
182 break;
183
184 case ARG_NO_LEGEND:
185 arg_no_legend = true;
186 break;
187
188 case 'o':
189 if (arg_output) {
190 log_error("cannot set output more than once");
191 return -EINVAL;
192 }
193
194 arg_output = fopen(optarg, "we");
195 if (!arg_output)
196 return log_error_errno(errno, "writing to '%s': %m", optarg);
197
198 break;
199
200 case 'F':
201 if (arg_field) {
202 log_error("cannot use --field/-F more than once");
203 return -EINVAL;
204 }
205 arg_field = optarg;
206 break;
207
208 case '1':
209 arg_one = true;
210 break;
211
212 case 'D':
213 arg_directory = optarg;
214 break;
215
216 case 'r':
217 arg_reverse = true;
218 break;
219
220 case '?':
221 return -EINVAL;
222
223 default:
224 assert_not_reached("Unhandled option");
225 }
226
227 if (optind < argc) {
228 const char *cmd = argv[optind++];
229 if (streq(cmd, "list"))
230 arg_action = ACTION_LIST;
231 else if (streq(cmd, "dump"))
232 arg_action = ACTION_DUMP;
233 else if (streq(cmd, "gdb"))
234 arg_action = ACTION_GDB;
235 else if (streq(cmd, "info"))
236 arg_action = ACTION_INFO;
237 else {
238 log_error("Unknown action '%s'", cmd);
239 return -EINVAL;
240 }
241 }
242
243 if (arg_field && arg_action != ACTION_LIST) {
244 log_error("Option --field/-F only makes sense with list");
245 return -EINVAL;
246 }
247
248 if (optind < argc)
249 arg_matches = argv + optind;
250
251 return 0;
252 }
253
254 static int retrieve(const void *data,
255 size_t len,
256 const char *name,
257 char **var) {
258
259 size_t ident;
260 char *v;
261
262 ident = strlen(name) + 1; /* name + "=" */
263
264 if (len < ident)
265 return 0;
266
267 if (memcmp(data, name, ident - 1) != 0)
268 return 0;
269
270 if (((const char*) data)[ident - 1] != '=')
271 return 0;
272
273 v = strndup((const char*)data + ident, len - ident);
274 if (!v)
275 return log_oom();
276
277 free(*var);
278 *var = v;
279
280 return 1;
281 }
282
283 static int print_field(FILE* file, sd_journal *j) {
284 const void *d;
285 size_t l;
286
287 assert(file);
288 assert(j);
289
290 assert(arg_field);
291
292 /* A (user-specified) field may appear more than once for a given entry.
293 * We will print all of the occurences.
294 * This is different below for fields that systemd-coredump uses,
295 * because they cannot meaningfully appear more than once.
296 */
297 SD_JOURNAL_FOREACH_DATA(j, d, l) {
298 _cleanup_free_ char *value = NULL;
299 int r;
300
301 r = retrieve(d, l, arg_field, &value);
302 if (r < 0)
303 return r;
304 if (r > 0)
305 fprintf(file, "%s\n", value);
306 }
307
308 return 0;
309 }
310
311 #define RETRIEVE(d, l, name, arg) \
312 { \
313 int _r = retrieve(d, l, name, &arg); \
314 if (_r < 0) \
315 return _r; \
316 if (_r > 0) \
317 continue; \
318 }
319
320 static int print_list(FILE* file, sd_journal *j, int had_legend) {
321 _cleanup_free_ char
322 *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
323 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
324 *filename = NULL, *coredump = NULL;
325 const void *d;
326 size_t l;
327 usec_t t;
328 char buf[FORMAT_TIMESTAMP_MAX];
329 int r;
330 const char *present;
331 bool normal_coredump;
332
333 assert(file);
334 assert(j);
335
336 SD_JOURNAL_FOREACH_DATA(j, d, l) {
337 RETRIEVE(d, l, "MESSAGE_ID", mid);
338 RETRIEVE(d, l, "COREDUMP_PID", pid);
339 RETRIEVE(d, l, "COREDUMP_UID", uid);
340 RETRIEVE(d, l, "COREDUMP_GID", gid);
341 RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl);
342 RETRIEVE(d, l, "COREDUMP_EXE", exe);
343 RETRIEVE(d, l, "COREDUMP_COMM", comm);
344 RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline);
345 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
346 RETRIEVE(d, l, "COREDUMP", coredump);
347 }
348
349 if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) {
350 log_warning("Empty coredump log entry");
351 return -EINVAL;
352 }
353
354 r = sd_journal_get_realtime_usec(j, &t);
355 if (r < 0)
356 return log_error_errno(r, "Failed to get realtime timestamp: %m");
357
358 format_timestamp(buf, sizeof(buf), t);
359
360 if (!had_legend && !arg_no_legend)
361 fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n",
362 FORMAT_TIMESTAMP_WIDTH, "TIME",
363 6, "PID",
364 5, "UID",
365 5, "GID",
366 3, "SIG",
367 8, "COREFILE",
368 "EXE");
369
370 normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
371
372 if (filename)
373 if (access(filename, R_OK) == 0)
374 present = "present";
375 else if (errno == ENOENT)
376 present = "missing";
377 else
378 present = "error";
379 else if (coredump)
380 present = "journal";
381 else if (normal_coredump)
382 present = "none";
383 else
384 present = "-";
385
386 fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n",
387 FORMAT_TIMESTAMP_WIDTH, buf,
388 6, strna(pid),
389 5, strna(uid),
390 5, strna(gid),
391 3, normal_coredump ? strna(sgnl) : "-",
392 8, present,
393 strna(exe ?: (comm ?: cmdline)));
394
395 return 0;
396 }
397
398 static int print_info(FILE *file, sd_journal *j, bool need_space) {
399 _cleanup_free_ char
400 *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
401 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
402 *unit = NULL, *user_unit = NULL, *session = NULL,
403 *boot_id = NULL, *machine_id = NULL, *hostname = NULL,
404 *slice = NULL, *cgroup = NULL, *owner_uid = NULL,
405 *message = NULL, *timestamp = NULL, *filename = NULL,
406 *coredump = NULL;
407 const void *d;
408 size_t l;
409 bool normal_coredump;
410 int r;
411
412 assert(file);
413 assert(j);
414
415 SD_JOURNAL_FOREACH_DATA(j, d, l) {
416 RETRIEVE(d, l, "MESSAGE_ID", mid);
417 RETRIEVE(d, l, "COREDUMP_PID", pid);
418 RETRIEVE(d, l, "COREDUMP_UID", uid);
419 RETRIEVE(d, l, "COREDUMP_GID", gid);
420 RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl);
421 RETRIEVE(d, l, "COREDUMP_EXE", exe);
422 RETRIEVE(d, l, "COREDUMP_COMM", comm);
423 RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline);
424 RETRIEVE(d, l, "COREDUMP_UNIT", unit);
425 RETRIEVE(d, l, "COREDUMP_USER_UNIT", user_unit);
426 RETRIEVE(d, l, "COREDUMP_SESSION", session);
427 RETRIEVE(d, l, "COREDUMP_OWNER_UID", owner_uid);
428 RETRIEVE(d, l, "COREDUMP_SLICE", slice);
429 RETRIEVE(d, l, "COREDUMP_CGROUP", cgroup);
430 RETRIEVE(d, l, "COREDUMP_TIMESTAMP", timestamp);
431 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
432 RETRIEVE(d, l, "COREDUMP", coredump);
433 RETRIEVE(d, l, "_BOOT_ID", boot_id);
434 RETRIEVE(d, l, "_MACHINE_ID", machine_id);
435 RETRIEVE(d, l, "_HOSTNAME", hostname);
436 RETRIEVE(d, l, "MESSAGE", message);
437 }
438
439 if (need_space)
440 fputs("\n", file);
441
442 normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
443
444 if (comm)
445 fprintf(file,
446 " PID: %s%s%s (%s)\n",
447 ansi_highlight(), strna(pid), ansi_normal(), comm);
448 else
449 fprintf(file,
450 " PID: %s%s%s\n",
451 ansi_highlight(), strna(pid), ansi_normal());
452
453 if (uid) {
454 uid_t n;
455
456 if (parse_uid(uid, &n) >= 0) {
457 _cleanup_free_ char *u = NULL;
458
459 u = uid_to_name(n);
460 fprintf(file,
461 " UID: %s (%s)\n",
462 uid, u);
463 } else {
464 fprintf(file,
465 " UID: %s\n",
466 uid);
467 }
468 }
469
470 if (gid) {
471 gid_t n;
472
473 if (parse_gid(gid, &n) >= 0) {
474 _cleanup_free_ char *g = NULL;
475
476 g = gid_to_name(n);
477 fprintf(file,
478 " GID: %s (%s)\n",
479 gid, g);
480 } else {
481 fprintf(file,
482 " GID: %s\n",
483 gid);
484 }
485 }
486
487 if (sgnl) {
488 int sig;
489 const char *name = normal_coredump ? "Signal" : "Reason";
490
491 if (normal_coredump && safe_atoi(sgnl, &sig) >= 0)
492 fprintf(file, " %s: %s (%s)\n", name, sgnl, signal_to_string(sig));
493 else
494 fprintf(file, " %s: %s\n", name, sgnl);
495 }
496
497 if (timestamp) {
498 usec_t u;
499
500 r = safe_atou64(timestamp, &u);
501 if (r >= 0) {
502 char absolute[FORMAT_TIMESTAMP_MAX], relative[FORMAT_TIMESPAN_MAX];
503
504 fprintf(file,
505 " Timestamp: %s (%s)\n",
506 format_timestamp(absolute, sizeof(absolute), u),
507 format_timestamp_relative(relative, sizeof(relative), u));
508
509 } else
510 fprintf(file, " Timestamp: %s\n", timestamp);
511 }
512
513 if (cmdline)
514 fprintf(file, " Command Line: %s\n", cmdline);
515 if (exe)
516 fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_normal());
517 if (cgroup)
518 fprintf(file, " Control Group: %s\n", cgroup);
519 if (unit)
520 fprintf(file, " Unit: %s\n", unit);
521 if (user_unit)
522 fprintf(file, " User Unit: %s\n", user_unit);
523 if (slice)
524 fprintf(file, " Slice: %s\n", slice);
525 if (session)
526 fprintf(file, " Session: %s\n", session);
527 if (owner_uid) {
528 uid_t n;
529
530 if (parse_uid(owner_uid, &n) >= 0) {
531 _cleanup_free_ char *u = NULL;
532
533 u = uid_to_name(n);
534 fprintf(file,
535 " Owner UID: %s (%s)\n",
536 owner_uid, u);
537 } else {
538 fprintf(file,
539 " Owner UID: %s\n",
540 owner_uid);
541 }
542 }
543 if (boot_id)
544 fprintf(file, " Boot ID: %s\n", boot_id);
545 if (machine_id)
546 fprintf(file, " Machine ID: %s\n", machine_id);
547 if (hostname)
548 fprintf(file, " Hostname: %s\n", hostname);
549
550 if (filename)
551 fprintf(file, " Storage: %s%s\n", filename,
552 access(filename, R_OK) < 0 ? " (inaccessible)" : "");
553 else if (coredump)
554 fprintf(file, " Storage: journal\n");
555 else
556 fprintf(file, " Storage: none\n");
557
558 if (message) {
559 _cleanup_free_ char *m = NULL;
560
561 m = strreplace(message, "\n", "\n ");
562
563 fprintf(file, " Message: %s\n", strstrip(m ?: message));
564 }
565
566 return 0;
567 }
568
569 static int focus(sd_journal *j) {
570 int r;
571
572 r = sd_journal_seek_tail(j);
573 if (r == 0)
574 r = sd_journal_previous(j);
575 if (r < 0)
576 return log_error_errno(r, "Failed to search journal: %m");
577 if (r == 0) {
578 log_error("No match found.");
579 return -ESRCH;
580 }
581 return r;
582 }
583
584 static int print_entry(sd_journal *j, unsigned n_found) {
585 assert(j);
586
587 if (arg_action == ACTION_INFO)
588 return print_info(stdout, j, n_found);
589 else if (arg_field)
590 return print_field(stdout, j);
591 else
592 return print_list(stdout, j, n_found);
593 }
594
595 static int dump_list(sd_journal *j) {
596 unsigned n_found = 0;
597 int r;
598
599 assert(j);
600
601 /* The coredumps are likely to compressed, and for just
602 * listing them we don't need to decompress them, so let's
603 * pick a fairly low data threshold here */
604 sd_journal_set_data_threshold(j, 4096);
605
606 if (arg_one) {
607 r = focus(j);
608 if (r < 0)
609 return r;
610
611 return print_entry(j, 0);
612 } else {
613 if (!arg_reverse) {
614 SD_JOURNAL_FOREACH(j) {
615 r = print_entry(j, n_found++);
616 if (r < 0)
617 return r;
618 }
619 } else {
620 SD_JOURNAL_FOREACH_BACKWARDS(j) {
621 r = print_entry(j, n_found++);
622 if (r < 0)
623 return r;
624 }
625 }
626
627 if (!arg_field && n_found <= 0) {
628 log_notice("No coredumps found.");
629 return -ESRCH;
630 }
631 }
632
633 return 0;
634 }
635
636 static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp) {
637 const char *data;
638 _cleanup_free_ char *filename = NULL;
639 size_t len;
640 int r, fd;
641 _cleanup_close_ int fdt = -1;
642 char *temp = NULL;
643
644 assert(!(file && path)); /* At most one can be specified */
645 assert(!!path == !!unlink_temp); /* Those must be specified together */
646
647 /* Look for a coredump on disk first. */
648 r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
649 if (r == 0)
650 retrieve(data, len, "COREDUMP_FILENAME", &filename);
651 else {
652 if (r != -ENOENT)
653 return log_error_errno(r, "Failed to retrieve COREDUMP_FILENAME field: %m");
654 /* Check that we can have a COREDUMP field. We still haven't set a high
655 * data threshold, so we'll get a few kilobytes at most.
656 */
657
658 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
659 if (r == -ENOENT)
660 return log_error_errno(r, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).");
661 if (r < 0)
662 return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
663 }
664
665 if (filename) {
666 if (access(filename, R_OK) < 0)
667 return log_error_errno(errno, "File \"%s\" is not readable: %m", filename);
668
669 if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) {
670 *path = filename;
671 filename = NULL;
672
673 return 0;
674 }
675 }
676
677 if (path) {
678 const char *vt;
679
680 /* Create a temporary file to write the uncompressed core to. */
681
682 r = var_tmp_dir(&vt);
683 if (r < 0)
684 return log_error_errno(r, "Failed to acquire temporary directory path: %m");
685
686 temp = strjoin(vt, "/coredump-XXXXXX");
687 if (!temp)
688 return log_oom();
689
690 fdt = mkostemp_safe(temp);
691 if (fdt < 0)
692 return log_error_errno(fdt, "Failed to create temporary file: %m");
693 log_debug("Created temporary file %s", temp);
694
695 fd = fdt;
696 } else {
697 /* If neither path or file are specified, we will write to stdout. Let's now check
698 * if stdout is connected to a tty. We checked that the file exists, or that the
699 * core might be stored in the journal. In this second case, if we found the entry,
700 * in all likelyhood we will be able to access the COREDUMP= field. In either case,
701 * we stop before doing any "real" work, i.e. before starting decompression or
702 * reading from the file or creating temporary files.
703 */
704 if (!file) {
705 if (on_tty())
706 return log_error_errno(ENOTTY, "Refusing to dump core to tty"
707 " (use shell redirection or specify --output).");
708 file = stdout;
709 }
710
711 fd = fileno(file);
712 }
713
714 if (filename) {
715 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
716 _cleanup_close_ int fdf;
717
718 fdf = open(filename, O_RDONLY | O_CLOEXEC);
719 if (fdf < 0) {
720 r = log_error_errno(errno, "Failed to open %s: %m", filename);
721 goto error;
722 }
723
724 r = decompress_stream(filename, fdf, fd, -1);
725 if (r < 0) {
726 log_error_errno(r, "Failed to decompress %s: %m", filename);
727 goto error;
728 }
729 #else
730 log_error("Cannot decompress file. Compiled without compression support.");
731 r = -EOPNOTSUPP;
732 goto error;
733 #endif
734 } else {
735 ssize_t sz;
736
737 /* We want full data, nothing truncated. */
738 sd_journal_set_data_threshold(j, 0);
739
740 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
741 if (r < 0)
742 return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
743
744 assert(len >= 9);
745 data += 9;
746 len -= 9;
747
748 sz = write(fd, data, len);
749 if (sz < 0) {
750 r = log_error_errno(errno, "Failed to write output: %m");
751 goto error;
752 }
753 if (sz != (ssize_t) len) {
754 log_error("Short write to output.");
755 r = -EIO;
756 goto error;
757 }
758 }
759
760 if (temp) {
761 *path = temp;
762 *unlink_temp = true;
763 }
764 return 0;
765
766 error:
767 if (temp) {
768 unlink(temp);
769 log_debug("Removed temporary file %s", temp);
770 }
771 return r;
772 }
773
774 static int dump_core(sd_journal* j) {
775 int r;
776
777 assert(j);
778
779 r = focus(j);
780 if (r < 0)
781 return r;
782
783 print_info(arg_output ? stdout : stderr, j, false);
784
785 r = save_core(j, arg_output, NULL, NULL);
786 if (r < 0)
787 return r;
788
789 r = sd_journal_previous(j);
790 if (r > 0)
791 log_warning("More than one entry matches, ignoring rest.");
792
793 return 0;
794 }
795
796 static int run_gdb(sd_journal *j) {
797 _cleanup_free_ char *exe = NULL, *path = NULL;
798 bool unlink_path = false;
799 const char *data;
800 siginfo_t st;
801 size_t len;
802 pid_t pid;
803 int r;
804
805 assert(j);
806
807 r = focus(j);
808 if (r < 0)
809 return r;
810
811 print_info(stdout, j, false);
812 fputs("\n", stdout);
813
814 r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len);
815 if (r < 0)
816 return log_error_errno(r, "Failed to retrieve COREDUMP_EXE field: %m");
817
818 assert(len > strlen("COREDUMP_EXE="));
819 data += strlen("COREDUMP_EXE=");
820 len -= strlen("COREDUMP_EXE=");
821
822 exe = strndup(data, len);
823 if (!exe)
824 return log_oom();
825
826 if (endswith(exe, " (deleted)")) {
827 log_error("Binary already deleted.");
828 return -ENOENT;
829 }
830
831 if (!path_is_absolute(exe)) {
832 log_error("Binary is not an absolute path.");
833 return -ENOENT;
834 }
835
836 r = save_core(j, NULL, &path, &unlink_path);
837 if (r < 0)
838 return r;
839
840 /* Don't interfere with gdb and its handling of SIGINT. */
841 (void) ignore_signals(SIGINT, -1);
842
843 pid = fork();
844 if (pid < 0) {
845 r = log_error_errno(errno, "Failed to fork(): %m");
846 goto finish;
847 }
848 if (pid == 0) {
849 (void) reset_all_signal_handlers();
850 (void) reset_signal_mask();
851
852 execlp("gdb", "gdb", exe, path, NULL);
853
854 log_error_errno(errno, "Failed to invoke gdb: %m");
855 _exit(1);
856 }
857
858 r = wait_for_terminate(pid, &st);
859 if (r < 0) {
860 log_error_errno(r, "Failed to wait for gdb: %m");
861 goto finish;
862 }
863
864 r = st.si_code == CLD_EXITED ? st.si_status : 255;
865
866 finish:
867 (void) default_signals(SIGINT, -1);
868
869 if (unlink_path) {
870 log_debug("Removed temporary file %s", path);
871 unlink(path);
872 }
873
874 return r;
875 }
876
877 static int check_units_active(void) {
878 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
879 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
880 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
881 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
882 int c = 0, r;
883 const char *state;
884
885 r = sd_bus_default_system(&bus);
886 if (r < 0)
887 return log_error_errno(r, "Failed to acquire bus: %m");
888
889 r = sd_bus_message_new_method_call(
890 bus,
891 &m,
892 "org.freedesktop.systemd1",
893 "/org/freedesktop/systemd1",
894 "org.freedesktop.systemd1.Manager",
895 "ListUnitsByPatterns");
896 if (r < 0)
897 return bus_log_create_error(r);
898
899 r = sd_bus_message_append_strv(m, NULL);
900 if (r < 0)
901 return bus_log_create_error(r);
902
903 r = sd_bus_message_append_strv(m, STRV_MAKE("systemd-coredump@*.service"));
904 if (r < 0)
905 return bus_log_create_error(r);
906
907 r = sd_bus_call(bus, m, 0, &error, &reply);
908 if (r < 0)
909 return log_error_errno(r, "Failed to check if any systemd-coredump@.service units are running: %s",
910 bus_error_message(&error, r));
911
912 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
913 if (r < 0)
914 return bus_log_parse_error(r);
915
916 while ((r = sd_bus_message_read(
917 reply, "(ssssssouso)",
918 NULL, NULL, NULL, &state, NULL,
919 NULL, NULL, NULL, NULL, NULL) > 0))
920 if (!STR_IN_SET(state, "dead", "failed"))
921 c++;
922
923 if (r < 0)
924 return bus_log_parse_error(r);
925
926 r = sd_bus_message_exit_container(reply);
927 if (r < 0)
928 return bus_log_parse_error(r);
929
930 return c;
931 }
932
933 int main(int argc, char *argv[]) {
934 _cleanup_(sd_journal_closep) sd_journal*j = NULL;
935 int r = 0, units_active;
936
937 setlocale(LC_ALL, "");
938 log_parse_environment();
939 log_open();
940
941 r = parse_argv(argc, argv);
942 if (r < 0)
943 goto end;
944
945 if (arg_action == ACTION_NONE)
946 goto end;
947
948 sigbus_install();
949
950 if (arg_directory) {
951 r = sd_journal_open_directory(&j, arg_directory, 0);
952 if (r < 0) {
953 log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory);
954 goto end;
955 }
956 } else {
957 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
958 if (r < 0) {
959 log_error_errno(r, "Failed to open journal: %m");
960 goto end;
961 }
962 }
963
964 r = add_matches(j);
965 if (r < 0)
966 goto end;
967
968 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
969 _cleanup_free_ char *filter;
970
971 filter = journal_make_match_string(j);
972 log_debug("Journal filter: %s", filter);
973 }
974
975 units_active = check_units_active(); /* error is treated the same as 0 */
976
977 switch(arg_action) {
978
979 case ACTION_LIST:
980 case ACTION_INFO:
981 pager_open(arg_no_pager, false);
982 r = dump_list(j);
983 break;
984
985 case ACTION_DUMP:
986 r = dump_core(j);
987 break;
988
989 case ACTION_GDB:
990 r = run_gdb(j);
991 break;
992
993 default:
994 assert_not_reached("Shouldn't be here");
995 }
996
997 if (units_active > 0)
998 printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n",
999 ansi_highlight_red(),
1000 units_active, units_active == 1 ? "unit is running" : "units are running",
1001 ansi_normal());
1002 end:
1003 pager_close();
1004
1005 if (arg_output)
1006 fclose(arg_output);
1007
1008 return r >= 0 ? r : EXIT_FAILURE;
1009 }