]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/coredump.c
59c6d4b716b54c31aa9ff8f954e494e0a2e42478
[thirdparty/systemd.git] / src / journal / coredump.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <sys/prctl.h>
26 #include <sys/types.h>
27 #include <sys/xattr.h>
28
29 #include <systemd/sd-journal.h>
30 #include <systemd/sd-login.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "strv.h"
35 #include "macro.h"
36 #include "mkdir.h"
37 #include "special.h"
38 #include "cgroup-util.h"
39 #include "journald-native.h"
40 #include "conf-parser.h"
41 #include "copy.h"
42 #include "stacktrace.h"
43 #include "path-util.h"
44 #include "compress.h"
45 #include "coredump-vacuum.h"
46
47 #ifdef HAVE_ACL
48 # include <sys/acl.h>
49 # include "acl-util.h"
50 #endif
51
52 /* The maximum size up to which we process coredumps */
53 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
54
55 /* The maximum size up to which we leave the coredump around on
56 * disk */
57 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
58
59 /* The maximum size up to which we store the coredump in the
60 * journal */
61 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
62
63 /* Make sure to not make this larger than the maximum journal entry
64 * size. See ENTRY_SIZE_MAX in journald-native.c. */
65 assert_cc(JOURNAL_SIZE_MAX <= ENTRY_SIZE_MAX);
66
67 enum {
68 INFO_PID,
69 INFO_UID,
70 INFO_GID,
71 INFO_SIGNAL,
72 INFO_TIMESTAMP,
73 INFO_COMM,
74 INFO_EXE,
75 _INFO_LEN
76 };
77
78 typedef enum CoredumpStorage {
79 COREDUMP_STORAGE_NONE,
80 COREDUMP_STORAGE_EXTERNAL,
81 COREDUMP_STORAGE_JOURNAL,
82 COREDUMP_STORAGE_BOTH,
83 _COREDUMP_STORAGE_MAX,
84 _COREDUMP_STORAGE_INVALID = -1
85 } CoredumpStorage;
86
87 static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
88 [COREDUMP_STORAGE_NONE] = "none",
89 [COREDUMP_STORAGE_EXTERNAL] = "external",
90 [COREDUMP_STORAGE_JOURNAL] = "journal",
91 [COREDUMP_STORAGE_BOTH] = "both",
92 };
93
94 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
95 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
96
97 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
98 static bool arg_compress = true;
99 static off_t arg_process_size_max = PROCESS_SIZE_MAX;
100 static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
101 static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
102 static off_t arg_keep_free = (off_t) -1;
103 static off_t arg_max_use = (off_t) -1;
104
105 static int parse_config(void) {
106 static const ConfigTableItem items[] = {
107 { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
108 { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
109 { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
110 { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
111 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
112 { "Coredump", "KeepFree", config_parse_iec_off, 0, &arg_keep_free },
113 { "Coredump", "MaxUse", config_parse_iec_off, 0, &arg_max_use },
114 {}
115 };
116
117 return config_parse(
118 NULL,
119 "/etc/systemd/coredump.conf",
120 NULL,
121 "Coredump\0",
122 config_item_table_lookup,
123 (void*) items,
124 false,
125 false,
126 NULL);
127 }
128
129 static int fix_acl(int fd, uid_t uid) {
130
131 #ifdef HAVE_ACL
132 _cleanup_(acl_freep) acl_t acl = NULL;
133 acl_entry_t entry;
134 acl_permset_t permset;
135
136 assert(fd >= 0);
137
138 if (uid <= SYSTEM_UID_MAX)
139 return 0;
140
141 /* Make sure normal users can read (but not write or delete)
142 * their own coredumps */
143
144 acl = acl_get_fd(fd);
145 if (!acl) {
146 log_error("Failed to get ACL: %m");
147 return -errno;
148 }
149
150 if (acl_create_entry(&acl, &entry) < 0 ||
151 acl_set_tag_type(entry, ACL_USER) < 0 ||
152 acl_set_qualifier(entry, &uid) < 0) {
153 log_error("Failed to patch ACL: %m");
154 return -errno;
155 }
156
157 if (acl_get_permset(entry, &permset) < 0 ||
158 acl_add_perm(permset, ACL_READ) < 0 ||
159 calc_acl_mask_if_needed(&acl) < 0) {
160 log_warning("Failed to patch ACL: %m");
161 return -errno;
162 }
163
164 if (acl_set_fd(fd, acl) < 0) {
165 log_error("Failed to apply ACL: %m");
166 return -errno;
167 }
168 #endif
169
170 return 0;
171 }
172
173 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
174
175 static const char * const xattrs[_INFO_LEN] = {
176 [INFO_PID] = "user.coredump.pid",
177 [INFO_UID] = "user.coredump.uid",
178 [INFO_GID] = "user.coredump.gid",
179 [INFO_SIGNAL] = "user.coredump.signal",
180 [INFO_TIMESTAMP] = "user.coredump.timestamp",
181 [INFO_COMM] = "user.coredump.comm",
182 [INFO_EXE] = "user.coredump.exe",
183 };
184
185 int r = 0;
186 unsigned i;
187
188 assert(fd >= 0);
189
190 /* Attach some metadata to coredumps via extended
191 * attributes. Just because we can. */
192
193 for (i = 0; i < _INFO_LEN; i++) {
194 int k;
195
196 if (isempty(info[i]) || !xattrs[i])
197 continue;
198
199 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
200 if (k < 0 && r == 0)
201 r = -errno;
202 }
203
204 return r;
205 }
206
207 #define filename_escape(s) xescape((s), "./ ")
208
209 static int fix_permissions(
210 int fd,
211 const char *filename,
212 const char *target,
213 const char *info[_INFO_LEN],
214 uid_t uid) {
215
216 assert(fd >= 0);
217 assert(filename);
218 assert(target);
219 assert(info);
220
221 /* Ignore errors on these */
222 fchmod(fd, 0640);
223 fix_acl(fd, uid);
224 fix_xattr(fd, info);
225
226 if (fsync(fd) < 0) {
227 log_error("Failed to sync coredump %s: %m", filename);
228 return -errno;
229 }
230
231 if (rename(filename, target) < 0) {
232 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
233 return -errno;
234 }
235
236 return 0;
237 }
238
239 static int maybe_remove_external_coredump(const char *filename, off_t size) {
240
241 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
242
243 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
244 size <= arg_external_size_max)
245 return 0;
246
247 if (!filename)
248 return 1;
249
250 if (unlink(filename) < 0 && errno != ENOENT) {
251 log_error("Failed to unlink %s: %m", filename);
252 return -errno;
253 }
254
255 return 1;
256 }
257
258 static int make_filename(const char *info[_INFO_LEN], char **ret) {
259 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
260 sd_id128_t boot;
261 int r;
262
263 assert(info);
264
265 c = filename_escape(info[INFO_COMM]);
266 if (!c)
267 return -ENOMEM;
268
269 u = filename_escape(info[INFO_UID]);
270 if (!u)
271 return -ENOMEM;
272
273 r = sd_id128_get_boot(&boot);
274 if (r < 0)
275 return r;
276
277 p = filename_escape(info[INFO_PID]);
278 if (!p)
279 return -ENOMEM;
280
281 t = filename_escape(info[INFO_TIMESTAMP]);
282 if (!t)
283 return -ENOMEM;
284
285 if (asprintf(ret,
286 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
287 c,
288 u,
289 SD_ID128_FORMAT_VAL(boot),
290 p,
291 t) < 0)
292 return -ENOMEM;
293
294 return 0;
295 }
296
297 static int save_external_coredump(
298 const char *info[_INFO_LEN],
299 uid_t uid,
300 char **ret_filename,
301 int *ret_fd,
302 off_t *ret_size) {
303
304 _cleanup_free_ char *fn = NULL, *tmp = NULL;
305 _cleanup_close_ int fd = -1;
306 struct stat st;
307 int r;
308
309 assert(info);
310 assert(ret_filename);
311 assert(ret_fd);
312 assert(ret_size);
313
314 r = make_filename(info, &fn);
315 if (r < 0) {
316 log_error("Failed to determine coredump file name: %s", strerror(-r));
317 return r;
318 }
319
320 tmp = tempfn_random(fn);
321 if (!tmp)
322 return log_oom();
323
324 mkdir_p_label("/var/lib/systemd/coredump", 0755);
325
326 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
327 if (fd < 0) {
328 log_error("Failed to create coredump file %s: %m", tmp);
329 return -errno;
330 }
331
332 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
333 if (r == -E2BIG) {
334 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
335 goto fail;
336 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
337 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
338 goto fail;
339 } else if (r < 0) {
340 log_error("Failed to dump coredump to file: %s", strerror(-r));
341 goto fail;
342 }
343
344 if (fstat(fd, &st) < 0) {
345 log_error("Failed to fstat coredump %s: %m", tmp);
346 goto fail;
347 }
348
349 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
350 log_error("Failed to seek on %s: %m", tmp);
351 goto fail;
352 }
353
354 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
355 /* If we will remove the coredump anyway, do not compress. */
356 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
357 && arg_compress) {
358
359 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
360 _cleanup_close_ int fd_compressed = -1;
361
362 fn_compressed = strappend(fn, COMPRESSED_EXT);
363 if (!fn_compressed) {
364 log_oom();
365 goto uncompressed;
366 }
367
368 tmp_compressed = tempfn_random(fn_compressed);
369 if (!tmp_compressed) {
370 log_oom();
371 goto uncompressed;
372 }
373
374 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
375 if (fd_compressed < 0) {
376 log_error("Failed to create file %s: %m", tmp_compressed);
377 goto uncompressed;
378 }
379
380 r = compress_stream(fd, fd_compressed, -1);
381 if (r < 0) {
382 log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
383 goto fail_compressed;
384 }
385
386 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
387 if (r < 0)
388 goto fail_compressed;
389
390 /* OK, this worked, we can get rid of the uncompressed version now */
391 unlink_noerrno(tmp);
392
393 *ret_filename = fn_compressed; /* compressed */
394 *ret_fd = fd; /* uncompressed */
395 *ret_size = st.st_size; /* uncompressed */
396
397 fn_compressed = NULL;
398 fd = -1;
399
400 return 0;
401
402 fail_compressed:
403 unlink_noerrno(tmp_compressed);
404 }
405 #endif
406
407 uncompressed:
408 r = fix_permissions(fd, tmp, fn, info, uid);
409 if (r < 0)
410 goto fail;
411
412 *ret_filename = fn;
413 *ret_fd = fd;
414 *ret_size = st.st_size;
415
416 fn = NULL;
417 fd = -1;
418
419 return 0;
420
421 fail:
422 unlink_noerrno(tmp);
423 return r;
424 }
425
426 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
427 _cleanup_free_ char *field = NULL;
428 ssize_t n;
429
430 assert(fd >= 0);
431 assert(ret);
432 assert(ret_size);
433
434 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
435 log_warning("Failed to seek: %m");
436 return -errno;
437 }
438
439 field = malloc(9 + size);
440 if (!field) {
441 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
442 return -ENOMEM;
443 }
444
445 memcpy(field, "COREDUMP=", 9);
446
447 n = read(fd, field + 9, size);
448 if (n < 0) {
449 log_error("Failed to read core data: %s", strerror(-n));
450 return (int) n;
451 }
452 if ((size_t) n < size) {
453 log_error("Core data too short.");
454 return -EIO;
455 }
456
457 *ret = field;
458 *ret_size = size + 9;
459
460 field = NULL;
461
462 return 0;
463 }
464
465 int main(int argc, char* argv[]) {
466
467 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
468 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
469 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
470 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
471 *exe = NULL, *comm = NULL, *filename = NULL;
472 const char *info[_INFO_LEN];
473
474 _cleanup_close_ int coredump_fd = -1;
475
476 struct iovec iovec[18];
477 off_t coredump_size;
478 int r, j = 0;
479 uid_t uid, owner_uid;
480 gid_t gid;
481 pid_t pid;
482 char *t;
483
484 /* Make sure we never enter a loop */
485 prctl(PR_SET_DUMPABLE, 0);
486
487 /* First, log to a safe place, since we don't know what
488 * crashed and it might be journald which we'd rather not log
489 * to then. */
490 log_set_target(LOG_TARGET_KMSG);
491 log_open();
492
493 if (argc < INFO_COMM + 1) {
494 log_error("Not enough arguments passed from kernel (%d, expected %d).",
495 argc - 1, INFO_COMM + 1 - 1);
496 r = -EINVAL;
497 goto finish;
498 }
499
500 /* Ignore all parse errors */
501 parse_config();
502
503 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
504 log_debug("Selected compression %s.", yes_no(arg_compress));
505
506 r = parse_uid(argv[INFO_UID + 1], &uid);
507 if (r < 0) {
508 log_error("Failed to parse UID.");
509 goto finish;
510 }
511
512 r = parse_pid(argv[INFO_PID + 1], &pid);
513 if (r < 0) {
514 log_error("Failed to parse PID.");
515 goto finish;
516 }
517
518 r = parse_gid(argv[INFO_GID + 1], &gid);
519 if (r < 0) {
520 log_error("Failed to parse GID.");
521 goto finish;
522 }
523
524 if (get_process_comm(pid, &comm) < 0) {
525 log_warning("Failed to get COMM, falling back to the commandline.");
526 comm = strv_join(argv + INFO_COMM + 1, " ");
527 }
528
529 if (get_process_exe(pid, &exe) < 0)
530 log_warning("Failed to get EXE.");
531
532 info[INFO_PID] = argv[INFO_PID + 1];
533 info[INFO_UID] = argv[INFO_UID + 1];
534 info[INFO_GID] = argv[INFO_GID + 1];
535 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
536 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
537 info[INFO_COMM] = comm;
538 info[INFO_EXE] = exe;
539
540 if (cg_pid_get_unit(pid, &t) >= 0) {
541
542 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
543
544 /* If we are journald, we cut things short,
545 * don't write to the journal, but still
546 * create a coredump. */
547
548 if (arg_storage != COREDUMP_STORAGE_NONE)
549 arg_storage = COREDUMP_STORAGE_EXTERNAL;
550
551 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
552 if (r < 0)
553 goto finish;
554
555 r = maybe_remove_external_coredump(filename, coredump_size);
556 if (r < 0)
557 goto finish;
558
559 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
560 goto finish;
561 }
562
563 core_unit = strappend("COREDUMP_UNIT=", t);
564 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
565 core_unit = strappend("COREDUMP_USER_UNIT=", t);
566
567 if (core_unit)
568 IOVEC_SET_STRING(iovec[j++], core_unit);
569
570 /* OK, now we know it's not the journal, hence we can make use
571 * of it now. */
572 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
573 log_open();
574
575 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
576 if (core_pid)
577 IOVEC_SET_STRING(iovec[j++], core_pid);
578
579 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
580 if (core_uid)
581 IOVEC_SET_STRING(iovec[j++], core_uid);
582
583 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
584 if (core_gid)
585 IOVEC_SET_STRING(iovec[j++], core_gid);
586
587 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
588 if (core_signal)
589 IOVEC_SET_STRING(iovec[j++], core_signal);
590
591 if (sd_pid_get_session(pid, &t) >= 0) {
592 core_session = strappend("COREDUMP_SESSION=", t);
593 free(t);
594
595 if (core_session)
596 IOVEC_SET_STRING(iovec[j++], core_session);
597 }
598
599 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
600 asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
601
602 if (core_owner_uid)
603 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
604 }
605
606 if (sd_pid_get_slice(pid, &t) >= 0) {
607 core_slice = strappend("COREDUMP_SLICE=", t);
608 free(t);
609
610 if (core_slice)
611 IOVEC_SET_STRING(iovec[j++], core_slice);
612 }
613
614 if (comm) {
615 core_comm = strappend("COREDUMP_COMM=", comm);
616 if (core_comm)
617 IOVEC_SET_STRING(iovec[j++], core_comm);
618 }
619
620 if (exe) {
621 core_exe = strappend("COREDUMP_EXE=", exe);
622 if (core_exe)
623 IOVEC_SET_STRING(iovec[j++], core_exe);
624 }
625
626 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
627 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
628 free(t);
629
630 if (core_cmdline)
631 IOVEC_SET_STRING(iovec[j++], core_cmdline);
632 }
633
634 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
635 core_cgroup = strappend("COREDUMP_CGROUP=", t);
636 free(t);
637
638 if (core_cgroup)
639 IOVEC_SET_STRING(iovec[j++], core_cgroup);
640 }
641
642 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
643 if (core_timestamp)
644 IOVEC_SET_STRING(iovec[j++], core_timestamp);
645
646 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
647 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
648
649 /* Vacuum before we write anything again */
650 coredump_vacuum(-1, arg_keep_free, arg_max_use);
651
652 /* Always stream the coredump to disk, if that's possible */
653 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
654 if (r < 0)
655 /* skip whole core dumping part */
656 goto log;
657
658 /* If we don't want to keep the coredump on disk, remove it
659 * now, as later on we will lack the privileges for
660 * it. However, we keep the fd to it, so that we can still
661 * process it and log it. */
662 r = maybe_remove_external_coredump(filename, coredump_size);
663 if (r < 0)
664 goto finish;
665 if (r == 0) {
666 const char *coredump_filename;
667
668 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
669 IOVEC_SET_STRING(iovec[j++], coredump_filename);
670 }
671
672 /* Vacuum again, but exclude the coredump we just created */
673 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
674
675 /* Now, let's drop privileges to become the user who owns the
676 * segfaulted process and allocate the coredump memory under
677 * his uid. This also ensures that the credentials journald
678 * will see are the ones of the coredumping user, thus making
679 * sure the user himself gets access to the core dump. */
680 if (setresgid(gid, gid, gid) < 0 ||
681 setresuid(uid, uid, uid) < 0) {
682 log_error("Failed to drop privileges: %m");
683 r = -errno;
684 goto finish;
685 }
686
687 #ifdef HAVE_ELFUTILS
688 /* Try to get a strack trace if we can */
689 if (coredump_size <= arg_process_size_max) {
690 _cleanup_free_ char *stacktrace = NULL;
691
692 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
693 if (r >= 0)
694 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
695 else
696 log_warning("Failed to generate stack trace: %s", strerror(-r));
697 }
698
699 if (!core_message)
700 #endif
701 log:
702 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
703 if (core_message)
704 IOVEC_SET_STRING(iovec[j++], core_message);
705
706 /* Optionally store the entire coredump in the journal */
707 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
708 coredump_size <= (off_t) arg_journal_size_max) {
709 size_t sz;
710
711 /* Store the coredump itself in the journal */
712
713 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
714 if (r >= 0) {
715 iovec[j].iov_base = coredump_data;
716 iovec[j].iov_len = sz;
717 j++;
718 }
719 }
720
721 r = sd_journal_sendv(iovec, j);
722 if (r < 0)
723 log_error("Failed to log coredump: %s", strerror(-r));
724
725 finish:
726 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
727 }