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"
43 #include "dirent-util.h"
48 #include "journald-native.h"
52 #include "parse-util.h"
53 #include "process-util.h"
55 #include "stacktrace.h"
56 #include "string-util.h"
58 #include "user-util.h"
61 /* The maximum size up to which we process coredumps */
62 #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
64 /* The maximum size up to which we leave the coredump around on
66 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
68 /* The maximum size up to which we store the coredump in the
70 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
72 /* Make sure to not make this larger than the maximum journal entry
73 * size. See DATA_SIZE_MAX in journald-native.c. */
74 assert_cc(JOURNAL_SIZE_MAX
<= DATA_SIZE_MAX
);
87 typedef enum CoredumpStorage
{
88 COREDUMP_STORAGE_NONE
,
89 COREDUMP_STORAGE_EXTERNAL
,
90 COREDUMP_STORAGE_JOURNAL
,
91 COREDUMP_STORAGE_BOTH
,
92 _COREDUMP_STORAGE_MAX
,
93 _COREDUMP_STORAGE_INVALID
= -1
96 static const char* const coredump_storage_table
[_COREDUMP_STORAGE_MAX
] = {
97 [COREDUMP_STORAGE_NONE
] = "none",
98 [COREDUMP_STORAGE_EXTERNAL
] = "external",
99 [COREDUMP_STORAGE_JOURNAL
] = "journal",
100 [COREDUMP_STORAGE_BOTH
] = "both",
103 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage
, CoredumpStorage
);
104 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage
, coredump_storage
, CoredumpStorage
, "Failed to parse storage setting");
106 static CoredumpStorage arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
107 static bool arg_compress
= true;
108 static uint64_t arg_process_size_max
= PROCESS_SIZE_MAX
;
109 static uint64_t arg_external_size_max
= EXTERNAL_SIZE_MAX
;
110 static size_t arg_journal_size_max
= JOURNAL_SIZE_MAX
;
111 static uint64_t arg_keep_free
= (uint64_t) -1;
112 static uint64_t arg_max_use
= (uint64_t) -1;
114 static int parse_config(void) {
115 static const ConfigTableItem items
[] = {
116 { "Coredump", "Storage", config_parse_coredump_storage
, 0, &arg_storage
},
117 { "Coredump", "Compress", config_parse_bool
, 0, &arg_compress
},
118 { "Coredump", "ProcessSizeMax", config_parse_iec_uint64
, 0, &arg_process_size_max
},
119 { "Coredump", "ExternalSizeMax", config_parse_iec_uint64
, 0, &arg_external_size_max
},
120 { "Coredump", "JournalSizeMax", config_parse_iec_size
, 0, &arg_journal_size_max
},
121 { "Coredump", "KeepFree", config_parse_iec_uint64
, 0, &arg_keep_free
},
122 { "Coredump", "MaxUse", config_parse_iec_uint64
, 0, &arg_max_use
},
126 return config_parse_many("/etc/systemd/coredump.conf",
127 CONF_DIRS_NULSTR("systemd/coredump.conf"),
129 config_item_table_lookup
, items
,
133 static int fix_acl(int fd
, uid_t uid
) {
136 _cleanup_(acl_freep
) acl_t acl
= NULL
;
138 acl_permset_t permset
;
142 if (uid
<= SYSTEM_UID_MAX
)
145 /* Make sure normal users can read (but not write or delete)
146 * their own coredumps */
148 acl
= acl_get_fd(fd
);
150 return log_error_errno(errno
, "Failed to get ACL: %m");
152 if (acl_create_entry(&acl
, &entry
) < 0 ||
153 acl_set_tag_type(entry
, ACL_USER
) < 0 ||
154 acl_set_qualifier(entry
, &uid
) < 0) {
155 log_error_errno(errno
, "Failed to patch ACL: %m");
159 if (acl_get_permset(entry
, &permset
) < 0 ||
160 acl_add_perm(permset
, ACL_READ
) < 0 ||
161 calc_acl_mask_if_needed(&acl
) < 0) {
162 log_warning_errno(errno
, "Failed to patch ACL: %m");
166 if (acl_set_fd(fd
, acl
) < 0)
167 return log_error_errno(errno
, "Failed to apply ACL: %m");
173 static int fix_xattr(int fd
, const char *info
[_INFO_LEN
]) {
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",
190 /* Attach some metadata to coredumps via extended
191 * attributes. Just because we can. */
193 for (i
= 0; i
< _INFO_LEN
; i
++) {
196 if (isempty(info
[i
]) || !xattrs
[i
])
199 k
= fsetxattr(fd
, xattrs
[i
], info
[i
], strlen(info
[i
]), XATTR_CREATE
);
207 #define filename_escape(s) xescape((s), "./ ")
209 static int fix_permissions(
211 const char *filename
,
213 const char *info
[_INFO_LEN
],
221 /* Ignore errors on these */
227 return log_error_errno(errno
, "Failed to sync coredump %s: %m", filename
);
229 if (rename(filename
, target
) < 0)
230 return log_error_errno(errno
, "Failed to rename coredump %s -> %s: %m", filename
, target
);
235 static int maybe_remove_external_coredump(const char *filename
, uint64_t size
) {
237 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
239 if (IN_SET(arg_storage
, COREDUMP_STORAGE_EXTERNAL
, COREDUMP_STORAGE_BOTH
) &&
240 size
<= arg_external_size_max
)
246 if (unlink(filename
) < 0 && errno
!= ENOENT
)
247 return log_error_errno(errno
, "Failed to unlink %s: %m", filename
);
252 static int make_filename(const char *info
[_INFO_LEN
], char **ret
) {
253 _cleanup_free_
char *c
= NULL
, *u
= NULL
, *p
= NULL
, *t
= NULL
;
254 sd_id128_t boot
= {};
259 c
= filename_escape(info
[INFO_COMM
]);
263 u
= filename_escape(info
[INFO_UID
]);
267 r
= sd_id128_get_boot(&boot
);
271 p
= filename_escape(info
[INFO_PID
]);
275 t
= filename_escape(info
[INFO_TIMESTAMP
]);
280 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR
".%s.%s000000",
283 SD_ID128_FORMAT_VAL(boot
),
291 static int save_external_coredump(
292 const char *info
[_INFO_LEN
],
296 uint64_t *ret_size
) {
298 _cleanup_free_
char *fn
= NULL
, *tmp
= NULL
;
299 _cleanup_close_
int fd
= -1;
304 assert(ret_filename
);
308 r
= make_filename(info
, &fn
);
310 return log_error_errno(r
, "Failed to determine coredump file name: %m");
312 r
= tempfn_random(fn
, NULL
, &tmp
);
314 return log_error_errno(r
, "Failed to determine temporary file name: %m");
316 mkdir_p_label("/var/lib/systemd/coredump", 0755);
318 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
320 return log_error_errno(errno
, "Failed to create coredump file %s: %m", tmp
);
322 r
= copy_bytes(STDIN_FILENO
, fd
, arg_process_size_max
, false);
324 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
326 } else if (IN_SET(r
, -EDQUOT
, -ENOSPC
)) {
327 log_error("Not enough disk space for coredump of %s (%s), refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
330 log_error_errno(r
, "Failed to dump coredump to file: %m");
334 if (fstat(fd
, &st
) < 0) {
335 log_error_errno(errno
, "Failed to fstat coredump %s: %m", tmp
);
339 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1) {
340 log_error_errno(errno
, "Failed to seek on %s: %m", tmp
);
344 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
345 /* If we will remove the coredump anyway, do not compress. */
346 if (maybe_remove_external_coredump(NULL
, st
.st_size
) == 0
349 _cleanup_free_
char *fn_compressed
= NULL
, *tmp_compressed
= NULL
;
350 _cleanup_close_
int fd_compressed
= -1;
352 fn_compressed
= strappend(fn
, COMPRESSED_EXT
);
353 if (!fn_compressed
) {
358 r
= tempfn_random(fn_compressed
, NULL
, &tmp_compressed
);
360 log_error_errno(r
, "Failed to determine temporary file name for %s: %m", fn_compressed
);
364 fd_compressed
= open(tmp_compressed
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
365 if (fd_compressed
< 0) {
366 log_error_errno(errno
, "Failed to create file %s: %m", tmp_compressed
);
370 r
= compress_stream(fd
, fd_compressed
, -1);
372 log_error_errno(r
, "Failed to compress %s: %m", tmp_compressed
);
373 goto fail_compressed
;
376 r
= fix_permissions(fd_compressed
, tmp_compressed
, fn_compressed
, info
, uid
);
378 goto fail_compressed
;
380 /* OK, this worked, we can get rid of the uncompressed version now */
383 *ret_filename
= fn_compressed
; /* compressed */
384 *ret_fd
= fd
; /* uncompressed */
385 *ret_size
= (uint64_t) st
.st_size
; /* uncompressed */
387 fn_compressed
= NULL
;
393 unlink_noerrno(tmp_compressed
);
398 r
= fix_permissions(fd
, tmp
, fn
, info
, uid
);
404 *ret_size
= (uint64_t) st
.st_size
;
416 static int allocate_journal_field(int fd
, size_t size
, char **ret
, size_t *ret_size
) {
417 _cleanup_free_
char *field
= NULL
;
424 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
425 return log_warning_errno(errno
, "Failed to seek: %m");
427 field
= malloc(9 + size
);
429 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
433 memcpy(field
, "COREDUMP=", 9);
435 n
= read(fd
, field
+ 9, size
);
437 return log_error_errno((int) n
, "Failed to read core data: %m");
438 if ((size_t) n
< size
) {
439 log_error("Core data too short.");
444 *ret_size
= size
+ 9;
451 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
465 static int compose_open_fds(pid_t pid
, char **open_fds
) {
466 _cleanup_closedir_
DIR *proc_fd_dir
= NULL
;
467 _cleanup_close_
int proc_fdinfo_fd
= -1;
468 _cleanup_free_
char *buffer
= NULL
;
469 _cleanup_fclose_
FILE *stream
= NULL
;
470 const char *fddelim
= "", *path
;
471 struct dirent
*dent
= NULL
;
476 assert(open_fds
!= NULL
);
478 path
= procfs_file_alloca(pid
, "fd");
479 proc_fd_dir
= opendir(path
);
483 proc_fdinfo_fd
= openat(dirfd(proc_fd_dir
), "../fdinfo", O_DIRECTORY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
484 if (proc_fdinfo_fd
< 0)
487 stream
= open_memstream(&buffer
, &size
);
491 FOREACH_DIRENT(dent
, proc_fd_dir
, return -errno
) {
492 _cleanup_fclose_
FILE *fdinfo
= NULL
;
493 _cleanup_free_
char *fdname
= NULL
;
497 r
= readlinkat_malloc(dirfd(proc_fd_dir
), dent
->d_name
, &fdname
);
501 fprintf(stream
, "%s%s:%s\n", fddelim
, dent
->d_name
, fdname
);
504 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
505 fd
= openat(proc_fdinfo_fd
, dent
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_RDONLY
);
509 fdinfo
= fdopen(fd
, "re");
510 if (fdinfo
== NULL
) {
515 FOREACH_LINE(line
, fdinfo
, break) {
517 if (!endswith(line
, "\n"))
523 stream
= safe_fclose(stream
);
534 int main(int argc
, char* argv
[]) {
536 /* The small core field we allocate on the stack, to keep things simple */
538 *core_pid
= NULL
, *core_uid
= NULL
, *core_gid
= NULL
, *core_signal
= NULL
,
539 *core_session
= NULL
, *core_exe
= NULL
, *core_comm
= NULL
, *core_cmdline
= NULL
,
540 *core_cgroup
= NULL
, *core_cwd
= NULL
, *core_root
= NULL
, *core_unit
= NULL
,
543 /* The larger ones we allocate on the heap */
545 *core_timestamp
= NULL
, *core_message
= NULL
, *coredump_data
= NULL
, *core_owner_uid
= NULL
,
546 *core_open_fds
= NULL
, *core_proc_status
= NULL
, *core_proc_maps
= NULL
, *core_proc_limits
= NULL
,
547 *core_proc_cgroup
= NULL
, *core_environ
= NULL
;
549 _cleanup_free_
char *exe
= NULL
, *comm
= NULL
, *filename
= NULL
;
550 const char *info
[_INFO_LEN
];
552 _cleanup_close_
int coredump_fd
= -1;
554 struct iovec iovec
[26];
555 uint64_t coredump_size
;
557 uid_t uid
, owner_uid
;
563 /* Make sure we never enter a loop */
564 prctl(PR_SET_DUMPABLE
, 0);
566 /* First, log to a safe place, since we don't know what
567 * crashed and it might be journald which we'd rather not log
569 log_set_target(LOG_TARGET_KMSG
);
572 if (argc
< INFO_COMM
+ 1) {
573 log_error("Not enough arguments passed from kernel (%d, expected %d).",
574 argc
- 1, INFO_COMM
+ 1 - 1);
579 /* Ignore all parse errors */
582 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage
));
583 log_debug("Selected compression %s.", yes_no(arg_compress
));
585 r
= parse_uid(argv
[INFO_UID
+ 1], &uid
);
587 log_error("Failed to parse UID.");
591 r
= parse_pid(argv
[INFO_PID
+ 1], &pid
);
593 log_error("Failed to parse PID.");
597 r
= parse_gid(argv
[INFO_GID
+ 1], &gid
);
599 log_error("Failed to parse GID.");
603 if (get_process_comm(pid
, &comm
) < 0) {
604 log_warning("Failed to get COMM, falling back to the command line.");
605 comm
= strv_join(argv
+ INFO_COMM
+ 1, " ");
608 if (get_process_exe(pid
, &exe
) < 0)
609 log_warning("Failed to get EXE.");
611 info
[INFO_PID
] = argv
[INFO_PID
+ 1];
612 info
[INFO_UID
] = argv
[INFO_UID
+ 1];
613 info
[INFO_GID
] = argv
[INFO_GID
+ 1];
614 info
[INFO_SIGNAL
] = argv
[INFO_SIGNAL
+ 1];
615 info
[INFO_TIMESTAMP
] = argv
[INFO_TIMESTAMP
+ 1];
616 info
[INFO_COMM
] = comm
;
617 info
[INFO_EXE
] = exe
;
619 if (cg_pid_get_unit(pid
, &t
) >= 0) {
621 if (streq(t
, SPECIAL_JOURNALD_SERVICE
)) {
624 /* If we are journald, we cut things short,
625 * don't write to the journal, but still
626 * create a coredump. */
628 if (arg_storage
!= COREDUMP_STORAGE_NONE
)
629 arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
631 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
635 r
= maybe_remove_external_coredump(filename
, coredump_size
);
639 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename
);
643 core_unit
= strjoina("COREDUMP_UNIT=", t
);
646 } else if (cg_pid_get_user_unit(pid
, &t
) >= 0) {
647 core_unit
= strjoina("COREDUMP_USER_UNIT=", t
);
652 IOVEC_SET_STRING(iovec
[j
++], core_unit
);
654 /* OK, now we know it's not the journal, hence we can make use
656 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
);
659 core_pid
= strjoina("COREDUMP_PID=", info
[INFO_PID
]);
660 IOVEC_SET_STRING(iovec
[j
++], core_pid
);
662 core_uid
= strjoina("COREDUMP_UID=", info
[INFO_UID
]);
663 IOVEC_SET_STRING(iovec
[j
++], core_uid
);
665 core_gid
= strjoina("COREDUMP_GID=", info
[INFO_GID
]);
666 IOVEC_SET_STRING(iovec
[j
++], core_gid
);
668 core_signal
= strjoina("COREDUMP_SIGNAL=", info
[INFO_SIGNAL
]);
669 IOVEC_SET_STRING(iovec
[j
++], core_signal
);
671 if (sd_pid_get_session(pid
, &t
) >= 0) {
672 core_session
= strjoina("COREDUMP_SESSION=", t
);
675 IOVEC_SET_STRING(iovec
[j
++], core_session
);
678 if (sd_pid_get_owner_uid(pid
, &owner_uid
) >= 0) {
679 r
= asprintf(&core_owner_uid
,
680 "COREDUMP_OWNER_UID=" UID_FMT
, owner_uid
);
682 IOVEC_SET_STRING(iovec
[j
++], core_owner_uid
);
685 if (sd_pid_get_slice(pid
, &t
) >= 0) {
686 core_slice
= strjoina("COREDUMP_SLICE=", t
);
689 IOVEC_SET_STRING(iovec
[j
++], core_slice
);
693 core_comm
= strjoina("COREDUMP_COMM=", comm
);
694 IOVEC_SET_STRING(iovec
[j
++], core_comm
);
698 core_exe
= strjoina("COREDUMP_EXE=", exe
);
699 IOVEC_SET_STRING(iovec
[j
++], core_exe
);
702 if (get_process_cmdline(pid
, 0, false, &t
) >= 0) {
703 core_cmdline
= strjoina("COREDUMP_CMDLINE=", t
);
706 IOVEC_SET_STRING(iovec
[j
++], core_cmdline
);
709 if (cg_pid_get_path_shifted(pid
, NULL
, &t
) >= 0) {
710 core_cgroup
= strjoina("COREDUMP_CGROUP=", t
);
713 IOVEC_SET_STRING(iovec
[j
++], core_cgroup
);
716 if (compose_open_fds(pid
, &t
) >= 0) {
717 core_open_fds
= strappend("COREDUMP_OPEN_FDS=", t
);
721 IOVEC_SET_STRING(iovec
[j
++], core_open_fds
);
724 p
= procfs_file_alloca(pid
, "status");
725 if (read_full_file(p
, &t
, NULL
) >= 0) {
726 core_proc_status
= strappend("COREDUMP_PROC_STATUS=", t
);
729 if (core_proc_status
)
730 IOVEC_SET_STRING(iovec
[j
++], core_proc_status
);
733 p
= procfs_file_alloca(pid
, "maps");
734 if (read_full_file(p
, &t
, NULL
) >= 0) {
735 core_proc_maps
= strappend("COREDUMP_PROC_MAPS=", t
);
739 IOVEC_SET_STRING(iovec
[j
++], core_proc_maps
);
742 p
= procfs_file_alloca(pid
, "limits");
743 if (read_full_file(p
, &t
, NULL
) >= 0) {
744 core_proc_limits
= strappend("COREDUMP_PROC_LIMITS=", t
);
747 if (core_proc_limits
)
748 IOVEC_SET_STRING(iovec
[j
++], core_proc_limits
);
751 p
= procfs_file_alloca(pid
, "cgroup");
752 if (read_full_file(p
, &t
, NULL
) >=0) {
753 core_proc_cgroup
= strappend("COREDUMP_PROC_CGROUP=", t
);
756 if (core_proc_cgroup
)
757 IOVEC_SET_STRING(iovec
[j
++], core_proc_cgroup
);
760 if (get_process_cwd(pid
, &t
) >= 0) {
761 core_cwd
= strjoina("COREDUMP_CWD=", t
);
764 IOVEC_SET_STRING(iovec
[j
++], core_cwd
);
767 if (get_process_root(pid
, &t
) >= 0) {
768 core_root
= strjoina("COREDUMP_ROOT=", t
);
771 IOVEC_SET_STRING(iovec
[j
++], core_root
);
774 if (get_process_environ(pid
, &t
) >= 0) {
775 core_environ
= strappend("COREDUMP_ENVIRON=", t
);
779 IOVEC_SET_STRING(iovec
[j
++], core_environ
);
782 core_timestamp
= strjoin("COREDUMP_TIMESTAMP=", info
[INFO_TIMESTAMP
], "000000", NULL
);
784 IOVEC_SET_STRING(iovec
[j
++], core_timestamp
);
786 IOVEC_SET_STRING(iovec
[j
++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
787 IOVEC_SET_STRING(iovec
[j
++], "PRIORITY=2");
789 /* Vacuum before we write anything again */
790 coredump_vacuum(-1, arg_keep_free
, arg_max_use
);
792 /* Always stream the coredump to disk, if that's possible */
793 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
795 /* skip whole core dumping part */
798 /* If we don't want to keep the coredump on disk, remove it
799 * now, as later on we will lack the privileges for
800 * it. However, we keep the fd to it, so that we can still
801 * process it and log it. */
802 r
= maybe_remove_external_coredump(filename
, coredump_size
);
806 const char *coredump_filename
;
808 coredump_filename
= strjoina("COREDUMP_FILENAME=", filename
);
809 IOVEC_SET_STRING(iovec
[j
++], coredump_filename
);
812 /* Vacuum again, but exclude the coredump we just created */
813 coredump_vacuum(coredump_fd
, arg_keep_free
, arg_max_use
);
815 /* Now, let's drop privileges to become the user who owns the
816 * segfaulted process and allocate the coredump memory under
817 * the user's uid. This also ensures that the credentials
818 * journald will see are the ones of the coredumping user,
819 * thus making sure the user gets access to the core
820 * dump. Let's also get rid of all capabilities, if we run as
821 * root, we won't need them anymore. */
822 r
= drop_privileges(uid
, gid
, 0);
824 log_error_errno(r
, "Failed to drop privileges: %m");
829 /* Try to get a strack trace if we can */
830 if (coredump_size
<= arg_process_size_max
) {
831 _cleanup_free_
char *stacktrace
= NULL
;
833 r
= coredump_make_stack_trace(coredump_fd
, exe
, &stacktrace
);
835 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.\n\n", stacktrace
, NULL
);
836 else if (r
== -EINVAL
)
837 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
839 log_warning_errno(r
, "Failed to generate stack trace: %m");
845 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.", NULL
);
847 IOVEC_SET_STRING(iovec
[j
++], core_message
);
849 /* Optionally store the entire coredump in the journal */
850 if (IN_SET(arg_storage
, COREDUMP_STORAGE_JOURNAL
, COREDUMP_STORAGE_BOTH
) &&
851 coredump_size
<= arg_journal_size_max
) {
854 /* Store the coredump itself in the journal */
856 r
= allocate_journal_field(coredump_fd
, (size_t) coredump_size
, &coredump_data
, &sz
);
858 iovec
[j
].iov_base
= coredump_data
;
859 iovec
[j
].iov_len
= sz
;
864 r
= sd_journal_sendv(iovec
, j
);
866 log_error_errno(r
, "Failed to log coredump: %m");
869 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;