1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
24 #include <sys/prctl.h>
25 #include <sys/xattr.h>
30 # include <elfutils/libdwfl.h>
33 #include "sd-journal.h"
37 #include "capability.h"
38 #include "cgroup-util.h"
40 #include "conf-parser.h"
42 #include "coredump-vacuum.h"
45 #include "journald-native.h"
49 #include "process-util.h"
51 #include "stacktrace.h"
52 #include "string-util.h"
56 /* The maximum size up to which we process coredumps */
57 #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
59 /* The maximum size up to which we leave the coredump around on
61 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
63 /* The maximum size up to which we store the coredump in the
65 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
67 /* Make sure to not make this larger than the maximum journal entry
68 * size. See DATA_SIZE_MAX in journald-native.c. */
69 assert_cc(JOURNAL_SIZE_MAX
<= DATA_SIZE_MAX
);
82 typedef enum CoredumpStorage
{
83 COREDUMP_STORAGE_NONE
,
84 COREDUMP_STORAGE_EXTERNAL
,
85 COREDUMP_STORAGE_JOURNAL
,
86 COREDUMP_STORAGE_BOTH
,
87 _COREDUMP_STORAGE_MAX
,
88 _COREDUMP_STORAGE_INVALID
= -1
91 static const char* const coredump_storage_table
[_COREDUMP_STORAGE_MAX
] = {
92 [COREDUMP_STORAGE_NONE
] = "none",
93 [COREDUMP_STORAGE_EXTERNAL
] = "external",
94 [COREDUMP_STORAGE_JOURNAL
] = "journal",
95 [COREDUMP_STORAGE_BOTH
] = "both",
98 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage
, CoredumpStorage
);
99 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage
, coredump_storage
, CoredumpStorage
, "Failed to parse storage setting");
101 static CoredumpStorage arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
102 static bool arg_compress
= true;
103 static uint64_t arg_process_size_max
= PROCESS_SIZE_MAX
;
104 static uint64_t arg_external_size_max
= EXTERNAL_SIZE_MAX
;
105 static size_t arg_journal_size_max
= JOURNAL_SIZE_MAX
;
106 static uint64_t arg_keep_free
= (uint64_t) -1;
107 static uint64_t arg_max_use
= (uint64_t) -1;
109 static int parse_config(void) {
110 static const ConfigTableItem items
[] = {
111 { "Coredump", "Storage", config_parse_coredump_storage
, 0, &arg_storage
},
112 { "Coredump", "Compress", config_parse_bool
, 0, &arg_compress
},
113 { "Coredump", "ProcessSizeMax", config_parse_iec_uint64
, 0, &arg_process_size_max
},
114 { "Coredump", "ExternalSizeMax", config_parse_iec_uint64
, 0, &arg_external_size_max
},
115 { "Coredump", "JournalSizeMax", config_parse_iec_size
, 0, &arg_journal_size_max
},
116 { "Coredump", "KeepFree", config_parse_iec_uint64
, 0, &arg_keep_free
},
117 { "Coredump", "MaxUse", config_parse_iec_uint64
, 0, &arg_max_use
},
121 return config_parse_many("/etc/systemd/coredump.conf",
122 CONF_DIRS_NULSTR("systemd/coredump.conf"),
124 config_item_table_lookup
, items
,
128 static int fix_acl(int fd
, uid_t uid
) {
131 _cleanup_(acl_freep
) acl_t acl
= NULL
;
133 acl_permset_t permset
;
137 if (uid
<= SYSTEM_UID_MAX
)
140 /* Make sure normal users can read (but not write or delete)
141 * their own coredumps */
143 acl
= acl_get_fd(fd
);
145 return log_error_errno(errno
, "Failed to get ACL: %m");
147 if (acl_create_entry(&acl
, &entry
) < 0 ||
148 acl_set_tag_type(entry
, ACL_USER
) < 0 ||
149 acl_set_qualifier(entry
, &uid
) < 0) {
150 log_error_errno(errno
, "Failed to patch ACL: %m");
154 if (acl_get_permset(entry
, &permset
) < 0 ||
155 acl_add_perm(permset
, ACL_READ
) < 0 ||
156 calc_acl_mask_if_needed(&acl
) < 0) {
157 log_warning_errno(errno
, "Failed to patch ACL: %m");
161 if (acl_set_fd(fd
, acl
) < 0)
162 return log_error_errno(errno
, "Failed to apply ACL: %m");
168 static int fix_xattr(int fd
, const char *info
[_INFO_LEN
]) {
170 static const char * const xattrs
[_INFO_LEN
] = {
171 [INFO_PID
] = "user.coredump.pid",
172 [INFO_UID
] = "user.coredump.uid",
173 [INFO_GID
] = "user.coredump.gid",
174 [INFO_SIGNAL
] = "user.coredump.signal",
175 [INFO_TIMESTAMP
] = "user.coredump.timestamp",
176 [INFO_COMM
] = "user.coredump.comm",
177 [INFO_EXE
] = "user.coredump.exe",
185 /* Attach some metadata to coredumps via extended
186 * attributes. Just because we can. */
188 for (i
= 0; i
< _INFO_LEN
; i
++) {
191 if (isempty(info
[i
]) || !xattrs
[i
])
194 k
= fsetxattr(fd
, xattrs
[i
], info
[i
], strlen(info
[i
]), XATTR_CREATE
);
202 #define filename_escape(s) xescape((s), "./ ")
204 static int fix_permissions(
206 const char *filename
,
208 const char *info
[_INFO_LEN
],
216 /* Ignore errors on these */
222 return log_error_errno(errno
, "Failed to sync coredump %s: %m", filename
);
224 if (rename(filename
, target
) < 0)
225 return log_error_errno(errno
, "Failed to rename coredump %s -> %s: %m", filename
, target
);
230 static int maybe_remove_external_coredump(const char *filename
, uint64_t size
) {
232 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
234 if (IN_SET(arg_storage
, COREDUMP_STORAGE_EXTERNAL
, COREDUMP_STORAGE_BOTH
) &&
235 size
<= arg_external_size_max
)
241 if (unlink(filename
) < 0 && errno
!= ENOENT
)
242 return log_error_errno(errno
, "Failed to unlink %s: %m", filename
);
247 static int make_filename(const char *info
[_INFO_LEN
], char **ret
) {
248 _cleanup_free_
char *c
= NULL
, *u
= NULL
, *p
= NULL
, *t
= NULL
;
249 sd_id128_t boot
= {};
254 c
= filename_escape(info
[INFO_COMM
]);
258 u
= filename_escape(info
[INFO_UID
]);
262 r
= sd_id128_get_boot(&boot
);
266 p
= filename_escape(info
[INFO_PID
]);
270 t
= filename_escape(info
[INFO_TIMESTAMP
]);
275 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR
".%s.%s000000",
278 SD_ID128_FORMAT_VAL(boot
),
286 static int save_external_coredump(
287 const char *info
[_INFO_LEN
],
291 uint64_t *ret_size
) {
293 _cleanup_free_
char *fn
= NULL
, *tmp
= NULL
;
294 _cleanup_close_
int fd
= -1;
299 assert(ret_filename
);
303 r
= make_filename(info
, &fn
);
305 return log_error_errno(r
, "Failed to determine coredump file name: %m");
307 r
= tempfn_random(fn
, NULL
, &tmp
);
309 return log_error_errno(r
, "Failed to determine temporary file name: %m");
311 mkdir_p_label("/var/lib/systemd/coredump", 0755);
313 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
315 return log_error_errno(errno
, "Failed to create coredump file %s: %m", tmp
);
317 r
= copy_bytes(STDIN_FILENO
, fd
, arg_process_size_max
, false);
319 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
321 } else if (IN_SET(r
, -EDQUOT
, -ENOSPC
)) {
322 log_error("Not enough disk space for coredump of %s (%s), refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
325 log_error_errno(r
, "Failed to dump coredump to file: %m");
329 if (fstat(fd
, &st
) < 0) {
330 log_error_errno(errno
, "Failed to fstat coredump %s: %m", tmp
);
334 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1) {
335 log_error_errno(errno
, "Failed to seek on %s: %m", tmp
);
339 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
340 /* If we will remove the coredump anyway, do not compress. */
341 if (maybe_remove_external_coredump(NULL
, st
.st_size
) == 0
344 _cleanup_free_
char *fn_compressed
= NULL
, *tmp_compressed
= NULL
;
345 _cleanup_close_
int fd_compressed
= -1;
347 fn_compressed
= strappend(fn
, COMPRESSED_EXT
);
348 if (!fn_compressed
) {
353 r
= tempfn_random(fn_compressed
, NULL
, &tmp_compressed
);
355 log_error_errno(r
, "Failed to determine temporary file name for %s: %m", fn_compressed
);
359 fd_compressed
= open(tmp_compressed
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
360 if (fd_compressed
< 0) {
361 log_error_errno(errno
, "Failed to create file %s: %m", tmp_compressed
);
365 r
= compress_stream(fd
, fd_compressed
, -1);
367 log_error_errno(r
, "Failed to compress %s: %m", tmp_compressed
);
368 goto fail_compressed
;
371 r
= fix_permissions(fd_compressed
, tmp_compressed
, fn_compressed
, info
, uid
);
373 goto fail_compressed
;
375 /* OK, this worked, we can get rid of the uncompressed version now */
378 *ret_filename
= fn_compressed
; /* compressed */
379 *ret_fd
= fd
; /* uncompressed */
380 *ret_size
= (uint64_t) st
.st_size
; /* uncompressed */
382 fn_compressed
= NULL
;
388 unlink_noerrno(tmp_compressed
);
393 r
= fix_permissions(fd
, tmp
, fn
, info
, uid
);
399 *ret_size
= (uint64_t) st
.st_size
;
411 static int allocate_journal_field(int fd
, size_t size
, char **ret
, size_t *ret_size
) {
412 _cleanup_free_
char *field
= NULL
;
419 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
420 return log_warning_errno(errno
, "Failed to seek: %m");
422 field
= malloc(9 + size
);
424 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
428 memcpy(field
, "COREDUMP=", 9);
430 n
= read(fd
, field
+ 9, size
);
432 return log_error_errno((int) n
, "Failed to read core data: %m");
433 if ((size_t) n
< size
) {
434 log_error("Core data too short.");
439 *ret_size
= size
+ 9;
446 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
460 static int compose_open_fds(pid_t pid
, char **open_fds
) {
461 _cleanup_closedir_
DIR *proc_fd_dir
= NULL
;
462 _cleanup_close_
int proc_fdinfo_fd
= -1;
463 _cleanup_free_
char *buffer
= NULL
;
464 _cleanup_fclose_
FILE *stream
= NULL
;
465 const char *fddelim
= "", *path
;
466 struct dirent
*dent
= NULL
;
471 assert(open_fds
!= NULL
);
473 path
= procfs_file_alloca(pid
, "fd");
474 proc_fd_dir
= opendir(path
);
478 proc_fdinfo_fd
= openat(dirfd(proc_fd_dir
), "../fdinfo", O_DIRECTORY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
479 if (proc_fdinfo_fd
< 0)
482 stream
= open_memstream(&buffer
, &size
);
486 FOREACH_DIRENT(dent
, proc_fd_dir
, return -errno
) {
487 _cleanup_fclose_
FILE *fdinfo
= NULL
;
488 _cleanup_free_
char *fdname
= NULL
;
492 r
= readlinkat_malloc(dirfd(proc_fd_dir
), dent
->d_name
, &fdname
);
496 fprintf(stream
, "%s%s:%s\n", fddelim
, dent
->d_name
, fdname
);
499 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
500 fd
= openat(proc_fdinfo_fd
, dent
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_RDONLY
);
504 fdinfo
= fdopen(fd
, "re");
505 if (fdinfo
== NULL
) {
510 FOREACH_LINE(line
, fdinfo
, break) {
512 if (!endswith(line
, "\n"))
518 stream
= safe_fclose(stream
);
529 int main(int argc
, char* argv
[]) {
531 /* The small core field we allocate on the stack, to keep things simple */
533 *core_pid
= NULL
, *core_uid
= NULL
, *core_gid
= NULL
, *core_signal
= NULL
,
534 *core_session
= NULL
, *core_exe
= NULL
, *core_comm
= NULL
, *core_cmdline
= NULL
,
535 *core_cgroup
= NULL
, *core_cwd
= NULL
, *core_root
= NULL
, *core_unit
= NULL
,
538 /* The larger ones we allocate on the heap */
540 *core_timestamp
= NULL
, *core_message
= NULL
, *coredump_data
= NULL
, *core_owner_uid
= NULL
,
541 *core_open_fds
= NULL
, *core_proc_status
= NULL
, *core_proc_maps
= NULL
, *core_proc_limits
= NULL
,
542 *core_proc_cgroup
= NULL
, *core_environ
= NULL
;
544 _cleanup_free_
char *exe
= NULL
, *comm
= NULL
, *filename
= NULL
;
545 const char *info
[_INFO_LEN
];
547 _cleanup_close_
int coredump_fd
= -1;
549 struct iovec iovec
[26];
550 uint64_t coredump_size
;
552 uid_t uid
, owner_uid
;
558 /* Make sure we never enter a loop */
559 prctl(PR_SET_DUMPABLE
, 0);
561 /* First, log to a safe place, since we don't know what
562 * crashed and it might be journald which we'd rather not log
564 log_set_target(LOG_TARGET_KMSG
);
567 if (argc
< INFO_COMM
+ 1) {
568 log_error("Not enough arguments passed from kernel (%d, expected %d).",
569 argc
- 1, INFO_COMM
+ 1 - 1);
574 /* Ignore all parse errors */
577 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage
));
578 log_debug("Selected compression %s.", yes_no(arg_compress
));
580 r
= parse_uid(argv
[INFO_UID
+ 1], &uid
);
582 log_error("Failed to parse UID.");
586 r
= parse_pid(argv
[INFO_PID
+ 1], &pid
);
588 log_error("Failed to parse PID.");
592 r
= parse_gid(argv
[INFO_GID
+ 1], &gid
);
594 log_error("Failed to parse GID.");
598 if (get_process_comm(pid
, &comm
) < 0) {
599 log_warning("Failed to get COMM, falling back to the command line.");
600 comm
= strv_join(argv
+ INFO_COMM
+ 1, " ");
603 if (get_process_exe(pid
, &exe
) < 0)
604 log_warning("Failed to get EXE.");
606 info
[INFO_PID
] = argv
[INFO_PID
+ 1];
607 info
[INFO_UID
] = argv
[INFO_UID
+ 1];
608 info
[INFO_GID
] = argv
[INFO_GID
+ 1];
609 info
[INFO_SIGNAL
] = argv
[INFO_SIGNAL
+ 1];
610 info
[INFO_TIMESTAMP
] = argv
[INFO_TIMESTAMP
+ 1];
611 info
[INFO_COMM
] = comm
;
612 info
[INFO_EXE
] = exe
;
614 if (cg_pid_get_unit(pid
, &t
) >= 0) {
616 if (streq(t
, SPECIAL_JOURNALD_SERVICE
)) {
619 /* If we are journald, we cut things short,
620 * don't write to the journal, but still
621 * create a coredump. */
623 if (arg_storage
!= COREDUMP_STORAGE_NONE
)
624 arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
626 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
630 r
= maybe_remove_external_coredump(filename
, coredump_size
);
634 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename
);
638 core_unit
= strjoina("COREDUMP_UNIT=", t
);
641 } else if (cg_pid_get_user_unit(pid
, &t
) >= 0) {
642 core_unit
= strjoina("COREDUMP_USER_UNIT=", t
);
647 IOVEC_SET_STRING(iovec
[j
++], core_unit
);
649 /* OK, now we know it's not the journal, hence we can make use
651 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
);
654 core_pid
= strjoina("COREDUMP_PID=", info
[INFO_PID
]);
655 IOVEC_SET_STRING(iovec
[j
++], core_pid
);
657 core_uid
= strjoina("COREDUMP_UID=", info
[INFO_UID
]);
658 IOVEC_SET_STRING(iovec
[j
++], core_uid
);
660 core_gid
= strjoina("COREDUMP_GID=", info
[INFO_GID
]);
661 IOVEC_SET_STRING(iovec
[j
++], core_gid
);
663 core_signal
= strjoina("COREDUMP_SIGNAL=", info
[INFO_SIGNAL
]);
664 IOVEC_SET_STRING(iovec
[j
++], core_signal
);
666 if (sd_pid_get_session(pid
, &t
) >= 0) {
667 core_session
= strjoina("COREDUMP_SESSION=", t
);
670 IOVEC_SET_STRING(iovec
[j
++], core_session
);
673 if (sd_pid_get_owner_uid(pid
, &owner_uid
) >= 0) {
674 r
= asprintf(&core_owner_uid
,
675 "COREDUMP_OWNER_UID=" UID_FMT
, owner_uid
);
677 IOVEC_SET_STRING(iovec
[j
++], core_owner_uid
);
680 if (sd_pid_get_slice(pid
, &t
) >= 0) {
681 core_slice
= strjoina("COREDUMP_SLICE=", t
);
684 IOVEC_SET_STRING(iovec
[j
++], core_slice
);
688 core_comm
= strjoina("COREDUMP_COMM=", comm
);
689 IOVEC_SET_STRING(iovec
[j
++], core_comm
);
693 core_exe
= strjoina("COREDUMP_EXE=", exe
);
694 IOVEC_SET_STRING(iovec
[j
++], core_exe
);
697 if (get_process_cmdline(pid
, 0, false, &t
) >= 0) {
698 core_cmdline
= strjoina("COREDUMP_CMDLINE=", t
);
701 IOVEC_SET_STRING(iovec
[j
++], core_cmdline
);
704 if (cg_pid_get_path_shifted(pid
, NULL
, &t
) >= 0) {
705 core_cgroup
= strjoina("COREDUMP_CGROUP=", t
);
708 IOVEC_SET_STRING(iovec
[j
++], core_cgroup
);
711 if (compose_open_fds(pid
, &t
) >= 0) {
712 core_open_fds
= strappend("COREDUMP_OPEN_FDS=", t
);
716 IOVEC_SET_STRING(iovec
[j
++], core_open_fds
);
719 p
= procfs_file_alloca(pid
, "status");
720 if (read_full_file(p
, &t
, NULL
) >= 0) {
721 core_proc_status
= strappend("COREDUMP_PROC_STATUS=", t
);
724 if (core_proc_status
)
725 IOVEC_SET_STRING(iovec
[j
++], core_proc_status
);
728 p
= procfs_file_alloca(pid
, "maps");
729 if (read_full_file(p
, &t
, NULL
) >= 0) {
730 core_proc_maps
= strappend("COREDUMP_PROC_MAPS=", t
);
734 IOVEC_SET_STRING(iovec
[j
++], core_proc_maps
);
737 p
= procfs_file_alloca(pid
, "limits");
738 if (read_full_file(p
, &t
, NULL
) >= 0) {
739 core_proc_limits
= strappend("COREDUMP_PROC_LIMITS=", t
);
742 if (core_proc_limits
)
743 IOVEC_SET_STRING(iovec
[j
++], core_proc_limits
);
746 p
= procfs_file_alloca(pid
, "cgroup");
747 if (read_full_file(p
, &t
, NULL
) >=0) {
748 core_proc_cgroup
= strappend("COREDUMP_PROC_CGROUP=", t
);
751 if (core_proc_cgroup
)
752 IOVEC_SET_STRING(iovec
[j
++], core_proc_cgroup
);
755 if (get_process_cwd(pid
, &t
) >= 0) {
756 core_cwd
= strjoina("COREDUMP_CWD=", t
);
759 IOVEC_SET_STRING(iovec
[j
++], core_cwd
);
762 if (get_process_root(pid
, &t
) >= 0) {
763 core_root
= strjoina("COREDUMP_ROOT=", t
);
766 IOVEC_SET_STRING(iovec
[j
++], core_root
);
769 if (get_process_environ(pid
, &t
) >= 0) {
770 core_environ
= strappend("COREDUMP_ENVIRON=", t
);
774 IOVEC_SET_STRING(iovec
[j
++], core_environ
);
777 core_timestamp
= strjoin("COREDUMP_TIMESTAMP=", info
[INFO_TIMESTAMP
], "000000", NULL
);
779 IOVEC_SET_STRING(iovec
[j
++], core_timestamp
);
781 IOVEC_SET_STRING(iovec
[j
++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
782 IOVEC_SET_STRING(iovec
[j
++], "PRIORITY=2");
784 /* Vacuum before we write anything again */
785 coredump_vacuum(-1, arg_keep_free
, arg_max_use
);
787 /* Always stream the coredump to disk, if that's possible */
788 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
790 /* skip whole core dumping part */
793 /* If we don't want to keep the coredump on disk, remove it
794 * now, as later on we will lack the privileges for
795 * it. However, we keep the fd to it, so that we can still
796 * process it and log it. */
797 r
= maybe_remove_external_coredump(filename
, coredump_size
);
801 const char *coredump_filename
;
803 coredump_filename
= strjoina("COREDUMP_FILENAME=", filename
);
804 IOVEC_SET_STRING(iovec
[j
++], coredump_filename
);
807 /* Vacuum again, but exclude the coredump we just created */
808 coredump_vacuum(coredump_fd
, arg_keep_free
, arg_max_use
);
810 /* Now, let's drop privileges to become the user who owns the
811 * segfaulted process and allocate the coredump memory under
812 * the user's uid. This also ensures that the credentials
813 * journald will see are the ones of the coredumping user,
814 * thus making sure the user gets access to the core
815 * dump. Let's also get rid of all capabilities, if we run as
816 * root, we won't need them anymore. */
817 r
= drop_privileges(uid
, gid
, 0);
819 log_error_errno(r
, "Failed to drop privileges: %m");
824 /* Try to get a strack trace if we can */
825 if (coredump_size
<= arg_process_size_max
) {
826 _cleanup_free_
char *stacktrace
= NULL
;
828 r
= coredump_make_stack_trace(coredump_fd
, exe
, &stacktrace
);
830 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.\n\n", stacktrace
, NULL
);
831 else if (r
== -EINVAL
)
832 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
834 log_warning_errno(r
, "Failed to generate stack trace: %m");
840 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.", NULL
);
842 IOVEC_SET_STRING(iovec
[j
++], core_message
);
844 /* Optionally store the entire coredump in the journal */
845 if (IN_SET(arg_storage
, COREDUMP_STORAGE_JOURNAL
, COREDUMP_STORAGE_BOTH
) &&
846 coredump_size
<= arg_journal_size_max
) {
849 /* Store the coredump itself in the journal */
851 r
= allocate_journal_field(coredump_fd
, (size_t) coredump_size
, &coredump_data
, &sz
);
853 iovec
[j
].iov_base
= coredump_data
;
854 iovec
[j
].iov_len
= sz
;
859 r
= sd_journal_sendv(iovec
, j
);
861 log_error_errno(r
, "Failed to log coredump: %m");
864 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;