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/>.
25 #include <sys/prctl.h>
26 #include <sys/xattr.h>
30 # include <elfutils/libdwfl.h>
33 #include "sd-journal.h"
42 #include "cgroup-util.h"
43 #include "conf-parser.h"
45 #include "stacktrace.h"
48 #include "capability.h"
49 #include "journald-native.h"
50 #include "coredump-vacuum.h"
51 #include "process-util.h"
53 /* The maximum size up to which we process coredumps */
54 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
56 /* The maximum size up to which we leave the coredump around on
58 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
60 /* The maximum size up to which we store the coredump in the
62 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
64 /* Make sure to not make this larger than the maximum journal entry
65 * size. See DATA_SIZE_MAX in journald-native.c. */
66 assert_cc(JOURNAL_SIZE_MAX
<= DATA_SIZE_MAX
);
79 typedef enum CoredumpStorage
{
80 COREDUMP_STORAGE_NONE
,
81 COREDUMP_STORAGE_EXTERNAL
,
82 COREDUMP_STORAGE_JOURNAL
,
83 COREDUMP_STORAGE_BOTH
,
84 _COREDUMP_STORAGE_MAX
,
85 _COREDUMP_STORAGE_INVALID
= -1
88 static const char* const coredump_storage_table
[_COREDUMP_STORAGE_MAX
] = {
89 [COREDUMP_STORAGE_NONE
] = "none",
90 [COREDUMP_STORAGE_EXTERNAL
] = "external",
91 [COREDUMP_STORAGE_JOURNAL
] = "journal",
92 [COREDUMP_STORAGE_BOTH
] = "both",
95 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage
, CoredumpStorage
);
96 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage
, coredump_storage
, CoredumpStorage
, "Failed to parse storage setting");
98 static CoredumpStorage arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
99 static bool arg_compress
= true;
100 static off_t arg_process_size_max
= PROCESS_SIZE_MAX
;
101 static off_t arg_external_size_max
= EXTERNAL_SIZE_MAX
;
102 static size_t arg_journal_size_max
= JOURNAL_SIZE_MAX
;
103 static off_t arg_keep_free
= (off_t
) -1;
104 static off_t arg_max_use
= (off_t
) -1;
106 static int parse_config(void) {
107 static const ConfigTableItem items
[] = {
108 { "Coredump", "Storage", config_parse_coredump_storage
, 0, &arg_storage
},
109 { "Coredump", "Compress", config_parse_bool
, 0, &arg_compress
},
110 { "Coredump", "ProcessSizeMax", config_parse_iec_off
, 0, &arg_process_size_max
},
111 { "Coredump", "ExternalSizeMax", config_parse_iec_off
, 0, &arg_external_size_max
},
112 { "Coredump", "JournalSizeMax", config_parse_iec_size
, 0, &arg_journal_size_max
},
113 { "Coredump", "KeepFree", config_parse_iec_off
, 0, &arg_keep_free
},
114 { "Coredump", "MaxUse", config_parse_iec_off
, 0, &arg_max_use
},
118 return config_parse_many("/etc/systemd/coredump.conf",
119 CONF_DIRS_NULSTR("systemd/coredump.conf"),
121 config_item_table_lookup
, items
,
125 static int fix_acl(int fd
, uid_t uid
) {
128 _cleanup_(acl_freep
) acl_t acl
= NULL
;
130 acl_permset_t permset
;
134 if (uid
<= SYSTEM_UID_MAX
)
137 /* Make sure normal users can read (but not write or delete)
138 * their own coredumps */
140 acl
= acl_get_fd(fd
);
142 return log_error_errno(errno
, "Failed to get ACL: %m");
144 if (acl_create_entry(&acl
, &entry
) < 0 ||
145 acl_set_tag_type(entry
, ACL_USER
) < 0 ||
146 acl_set_qualifier(entry
, &uid
) < 0) {
147 log_error_errno(errno
, "Failed to patch ACL: %m");
151 if (acl_get_permset(entry
, &permset
) < 0 ||
152 acl_add_perm(permset
, ACL_READ
) < 0 ||
153 calc_acl_mask_if_needed(&acl
) < 0) {
154 log_warning_errno(errno
, "Failed to patch ACL: %m");
158 if (acl_set_fd(fd
, acl
) < 0)
159 return log_error_errno(errno
, "Failed to apply ACL: %m");
165 static int fix_xattr(int fd
, const char *info
[_INFO_LEN
]) {
167 static const char * const xattrs
[_INFO_LEN
] = {
168 [INFO_PID
] = "user.coredump.pid",
169 [INFO_UID
] = "user.coredump.uid",
170 [INFO_GID
] = "user.coredump.gid",
171 [INFO_SIGNAL
] = "user.coredump.signal",
172 [INFO_TIMESTAMP
] = "user.coredump.timestamp",
173 [INFO_COMM
] = "user.coredump.comm",
174 [INFO_EXE
] = "user.coredump.exe",
182 /* Attach some metadata to coredumps via extended
183 * attributes. Just because we can. */
185 for (i
= 0; i
< _INFO_LEN
; i
++) {
188 if (isempty(info
[i
]) || !xattrs
[i
])
191 k
= fsetxattr(fd
, xattrs
[i
], info
[i
], strlen(info
[i
]), XATTR_CREATE
);
199 #define filename_escape(s) xescape((s), "./ ")
201 static int fix_permissions(
203 const char *filename
,
205 const char *info
[_INFO_LEN
],
213 /* Ignore errors on these */
219 return log_error_errno(errno
, "Failed to sync coredump %s: %m", filename
);
221 if (rename(filename
, target
) < 0)
222 return log_error_errno(errno
, "Failed to rename coredump %s -> %s: %m", filename
, target
);
227 static int maybe_remove_external_coredump(const char *filename
, off_t size
) {
229 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
231 if (IN_SET(arg_storage
, COREDUMP_STORAGE_EXTERNAL
, COREDUMP_STORAGE_BOTH
) &&
232 size
<= arg_external_size_max
)
238 if (unlink(filename
) < 0 && errno
!= ENOENT
)
239 return log_error_errno(errno
, "Failed to unlink %s: %m", filename
);
244 static int make_filename(const char *info
[_INFO_LEN
], char **ret
) {
245 _cleanup_free_
char *c
= NULL
, *u
= NULL
, *p
= NULL
, *t
= NULL
;
246 sd_id128_t boot
= {};
251 c
= filename_escape(info
[INFO_COMM
]);
255 u
= filename_escape(info
[INFO_UID
]);
259 r
= sd_id128_get_boot(&boot
);
263 p
= filename_escape(info
[INFO_PID
]);
267 t
= filename_escape(info
[INFO_TIMESTAMP
]);
272 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR
".%s.%s000000",
275 SD_ID128_FORMAT_VAL(boot
),
283 static int save_external_coredump(
284 const char *info
[_INFO_LEN
],
290 _cleanup_free_
char *fn
= NULL
, *tmp
= NULL
;
291 _cleanup_close_
int fd
= -1;
296 assert(ret_filename
);
300 r
= make_filename(info
, &fn
);
302 return log_error_errno(r
, "Failed to determine coredump file name: %m");
304 r
= tempfn_random(fn
, &tmp
);
306 return log_error_errno(r
, "Failed to determine temporary file name: %m");
308 mkdir_p_label("/var/lib/systemd/coredump", 0755);
310 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
312 return log_error_errno(errno
, "Failed to create coredump file %s: %m", tmp
);
314 r
= copy_bytes(STDIN_FILENO
, fd
, arg_process_size_max
, false);
316 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
318 } else if (IN_SET(r
, -EDQUOT
, -ENOSPC
)) {
319 log_error("Not enough disk space for coredump of %s (%s), refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
322 log_error_errno(r
, "Failed to dump coredump to file: %m");
326 if (fstat(fd
, &st
) < 0) {
327 log_error_errno(errno
, "Failed to fstat coredump %s: %m", tmp
);
331 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1) {
332 log_error_errno(errno
, "Failed to seek on %s: %m", tmp
);
336 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
337 /* If we will remove the coredump anyway, do not compress. */
338 if (maybe_remove_external_coredump(NULL
, st
.st_size
) == 0
341 _cleanup_free_
char *fn_compressed
= NULL
, *tmp_compressed
= NULL
;
342 _cleanup_close_
int fd_compressed
= -1;
344 fn_compressed
= strappend(fn
, COMPRESSED_EXT
);
345 if (!fn_compressed
) {
350 r
= tempfn_random(fn_compressed
, &tmp_compressed
);
352 log_error_errno(r
, "Failed to determine temporary file name for %s: %m", fn_compressed
);
356 fd_compressed
= open(tmp_compressed
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
357 if (fd_compressed
< 0) {
358 log_error_errno(errno
, "Failed to create file %s: %m", tmp_compressed
);
362 r
= compress_stream(fd
, fd_compressed
, -1);
364 log_error_errno(r
, "Failed to compress %s: %m", tmp_compressed
);
365 goto fail_compressed
;
368 r
= fix_permissions(fd_compressed
, tmp_compressed
, fn_compressed
, info
, uid
);
370 goto fail_compressed
;
372 /* OK, this worked, we can get rid of the uncompressed version now */
375 *ret_filename
= fn_compressed
; /* compressed */
376 *ret_fd
= fd
; /* uncompressed */
377 *ret_size
= st
.st_size
; /* uncompressed */
379 fn_compressed
= NULL
;
385 unlink_noerrno(tmp_compressed
);
390 r
= fix_permissions(fd
, tmp
, fn
, info
, uid
);
396 *ret_size
= st
.st_size
;
408 static int allocate_journal_field(int fd
, size_t size
, char **ret
, size_t *ret_size
) {
409 _cleanup_free_
char *field
= NULL
;
416 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
417 return log_warning_errno(errno
, "Failed to seek: %m");
419 field
= malloc(9 + size
);
421 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
425 memcpy(field
, "COREDUMP=", 9);
427 n
= read(fd
, field
+ 9, size
);
429 return log_error_errno((int) n
, "Failed to read core data: %m");
430 if ((size_t) n
< size
) {
431 log_error("Core data too short.");
436 *ret_size
= size
+ 9;
443 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
457 static int compose_open_fds(pid_t pid
, char **open_fds
) {
458 _cleanup_closedir_
DIR *proc_fd_dir
= NULL
;
459 _cleanup_close_
int proc_fdinfo_fd
= -1;
460 _cleanup_free_
char *buffer
= NULL
;
461 _cleanup_fclose_
FILE *stream
= NULL
;
462 const char *fddelim
= "", *path
;
463 struct dirent
*dent
= NULL
;
468 assert(open_fds
!= NULL
);
470 path
= procfs_file_alloca(pid
, "fd");
471 proc_fd_dir
= opendir(path
);
475 proc_fdinfo_fd
= openat(dirfd(proc_fd_dir
), "../fdinfo", O_DIRECTORY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
476 if (proc_fdinfo_fd
< 0)
479 stream
= open_memstream(&buffer
, &size
);
483 FOREACH_DIRENT(dent
, proc_fd_dir
, return -errno
) {
484 _cleanup_fclose_
FILE *fdinfo
= NULL
;
485 _cleanup_free_
char *fdname
= NULL
;
489 r
= readlinkat_malloc(dirfd(proc_fd_dir
), dent
->d_name
, &fdname
);
493 fprintf(stream
, "%s%s:%s\n", fddelim
, dent
->d_name
, fdname
);
496 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
497 fd
= openat(proc_fdinfo_fd
, dent
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_RDONLY
);
501 fdinfo
= fdopen(fd
, "re");
502 if (fdinfo
== NULL
) {
507 FOREACH_LINE(line
, fdinfo
, break) {
509 if (!endswith(line
, "\n"))
527 int main(int argc
, char* argv
[]) {
529 /* The small core field we allocate on the stack, to keep things simple */
531 *core_pid
= NULL
, *core_uid
= NULL
, *core_gid
= NULL
, *core_signal
= NULL
,
532 *core_session
= NULL
, *core_exe
= NULL
, *core_comm
= NULL
, *core_cmdline
= NULL
,
533 *core_cgroup
= NULL
, *core_cwd
= NULL
, *core_root
= NULL
, *core_unit
= NULL
,
536 /* The larger ones we allocate on the heap */
538 *core_timestamp
= NULL
, *core_message
= NULL
, *coredump_data
= NULL
, *core_owner_uid
= NULL
,
539 *core_open_fds
= NULL
, *core_proc_status
= NULL
, *core_proc_maps
= NULL
, *core_proc_limits
= NULL
,
540 *core_proc_cgroup
= NULL
, *core_environ
= NULL
;
542 _cleanup_free_
char *exe
= NULL
, *comm
= NULL
, *filename
= NULL
;
543 const char *info
[_INFO_LEN
];
545 _cleanup_close_
int coredump_fd
= -1;
547 struct iovec iovec
[26];
550 uid_t uid
, owner_uid
;
556 /* Make sure we never enter a loop */
557 prctl(PR_SET_DUMPABLE
, 0);
559 /* First, log to a safe place, since we don't know what
560 * crashed and it might be journald which we'd rather not log
562 log_set_target(LOG_TARGET_KMSG
);
565 if (argc
< INFO_COMM
+ 1) {
566 log_error("Not enough arguments passed from kernel (%d, expected %d).",
567 argc
- 1, INFO_COMM
+ 1 - 1);
572 /* Ignore all parse errors */
575 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage
));
576 log_debug("Selected compression %s.", yes_no(arg_compress
));
578 r
= parse_uid(argv
[INFO_UID
+ 1], &uid
);
580 log_error("Failed to parse UID.");
584 r
= parse_pid(argv
[INFO_PID
+ 1], &pid
);
586 log_error("Failed to parse PID.");
590 r
= parse_gid(argv
[INFO_GID
+ 1], &gid
);
592 log_error("Failed to parse GID.");
596 if (get_process_comm(pid
, &comm
) < 0) {
597 log_warning("Failed to get COMM, falling back to the command line.");
598 comm
= strv_join(argv
+ INFO_COMM
+ 1, " ");
601 if (get_process_exe(pid
, &exe
) < 0)
602 log_warning("Failed to get EXE.");
604 info
[INFO_PID
] = argv
[INFO_PID
+ 1];
605 info
[INFO_UID
] = argv
[INFO_UID
+ 1];
606 info
[INFO_GID
] = argv
[INFO_GID
+ 1];
607 info
[INFO_SIGNAL
] = argv
[INFO_SIGNAL
+ 1];
608 info
[INFO_TIMESTAMP
] = argv
[INFO_TIMESTAMP
+ 1];
609 info
[INFO_COMM
] = comm
;
610 info
[INFO_EXE
] = exe
;
612 if (cg_pid_get_unit(pid
, &t
) >= 0) {
614 if (streq(t
, SPECIAL_JOURNALD_SERVICE
)) {
617 /* If we are journald, we cut things short,
618 * don't write to the journal, but still
619 * create a coredump. */
621 if (arg_storage
!= COREDUMP_STORAGE_NONE
)
622 arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
624 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
628 r
= maybe_remove_external_coredump(filename
, coredump_size
);
632 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename
);
636 core_unit
= strjoina("COREDUMP_UNIT=", t
);
639 } else if (cg_pid_get_user_unit(pid
, &t
) >= 0) {
640 core_unit
= strjoina("COREDUMP_USER_UNIT=", t
);
645 IOVEC_SET_STRING(iovec
[j
++], core_unit
);
647 /* OK, now we know it's not the journal, hence we can make use
649 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
);
652 core_pid
= strjoina("COREDUMP_PID=", info
[INFO_PID
]);
653 IOVEC_SET_STRING(iovec
[j
++], core_pid
);
655 core_uid
= strjoina("COREDUMP_UID=", info
[INFO_UID
]);
656 IOVEC_SET_STRING(iovec
[j
++], core_uid
);
658 core_gid
= strjoina("COREDUMP_GID=", info
[INFO_GID
]);
659 IOVEC_SET_STRING(iovec
[j
++], core_gid
);
661 core_signal
= strjoina("COREDUMP_SIGNAL=", info
[INFO_SIGNAL
]);
662 IOVEC_SET_STRING(iovec
[j
++], core_signal
);
664 if (sd_pid_get_session(pid
, &t
) >= 0) {
665 core_session
= strjoina("COREDUMP_SESSION=", t
);
668 IOVEC_SET_STRING(iovec
[j
++], core_session
);
671 if (sd_pid_get_owner_uid(pid
, &owner_uid
) >= 0) {
672 r
= asprintf(&core_owner_uid
,
673 "COREDUMP_OWNER_UID=" UID_FMT
, owner_uid
);
675 IOVEC_SET_STRING(iovec
[j
++], core_owner_uid
);
678 if (sd_pid_get_slice(pid
, &t
) >= 0) {
679 core_slice
= strjoina("COREDUMP_SLICE=", t
);
682 IOVEC_SET_STRING(iovec
[j
++], core_slice
);
686 core_comm
= strjoina("COREDUMP_COMM=", comm
);
687 IOVEC_SET_STRING(iovec
[j
++], core_comm
);
691 core_exe
= strjoina("COREDUMP_EXE=", exe
);
692 IOVEC_SET_STRING(iovec
[j
++], core_exe
);
695 if (get_process_cmdline(pid
, 0, false, &t
) >= 0) {
696 core_cmdline
= strjoina("COREDUMP_CMDLINE=", t
);
699 IOVEC_SET_STRING(iovec
[j
++], core_cmdline
);
702 if (cg_pid_get_path_shifted(pid
, NULL
, &t
) >= 0) {
703 core_cgroup
= strjoina("COREDUMP_CGROUP=", t
);
706 IOVEC_SET_STRING(iovec
[j
++], core_cgroup
);
709 if (compose_open_fds(pid
, &t
) >= 0) {
710 core_open_fds
= strappend("COREDUMP_OPEN_FDS=", t
);
714 IOVEC_SET_STRING(iovec
[j
++], core_open_fds
);
717 p
= procfs_file_alloca(pid
, "status");
718 if (read_full_file(p
, &t
, NULL
) >= 0) {
719 core_proc_status
= strappend("COREDUMP_PROC_STATUS=", t
);
722 if (core_proc_status
)
723 IOVEC_SET_STRING(iovec
[j
++], core_proc_status
);
726 p
= procfs_file_alloca(pid
, "maps");
727 if (read_full_file(p
, &t
, NULL
) >= 0) {
728 core_proc_maps
= strappend("COREDUMP_PROC_MAPS=", t
);
732 IOVEC_SET_STRING(iovec
[j
++], core_proc_maps
);
735 p
= procfs_file_alloca(pid
, "limits");
736 if (read_full_file(p
, &t
, NULL
) >= 0) {
737 core_proc_limits
= strappend("COREDUMP_PROC_LIMITS=", t
);
740 if (core_proc_limits
)
741 IOVEC_SET_STRING(iovec
[j
++], core_proc_limits
);
744 p
= procfs_file_alloca(pid
, "cgroup");
745 if (read_full_file(p
, &t
, NULL
) >=0) {
746 core_proc_cgroup
= strappend("COREDUMP_PROC_CGROUP=", t
);
749 if (core_proc_cgroup
)
750 IOVEC_SET_STRING(iovec
[j
++], core_proc_cgroup
);
753 if (get_process_cwd(pid
, &t
) >= 0) {
754 core_cwd
= strjoina("COREDUMP_CWD=", t
);
757 IOVEC_SET_STRING(iovec
[j
++], core_cwd
);
760 if (get_process_root(pid
, &t
) >= 0) {
761 core_root
= strjoina("COREDUMP_ROOT=", t
);
764 IOVEC_SET_STRING(iovec
[j
++], core_root
);
767 if (get_process_environ(pid
, &t
) >= 0) {
768 core_environ
= strappend("COREDUMP_ENVIRON=", t
);
772 IOVEC_SET_STRING(iovec
[j
++], core_environ
);
775 core_timestamp
= strjoin("COREDUMP_TIMESTAMP=", info
[INFO_TIMESTAMP
], "000000", NULL
);
777 IOVEC_SET_STRING(iovec
[j
++], core_timestamp
);
779 IOVEC_SET_STRING(iovec
[j
++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
780 IOVEC_SET_STRING(iovec
[j
++], "PRIORITY=2");
782 /* Vacuum before we write anything again */
783 coredump_vacuum(-1, arg_keep_free
, arg_max_use
);
785 /* Always stream the coredump to disk, if that's possible */
786 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
788 /* skip whole core dumping part */
791 /* If we don't want to keep the coredump on disk, remove it
792 * now, as later on we will lack the privileges for
793 * it. However, we keep the fd to it, so that we can still
794 * process it and log it. */
795 r
= maybe_remove_external_coredump(filename
, coredump_size
);
799 const char *coredump_filename
;
801 coredump_filename
= strjoina("COREDUMP_FILENAME=", filename
);
802 IOVEC_SET_STRING(iovec
[j
++], coredump_filename
);
805 /* Vacuum again, but exclude the coredump we just created */
806 coredump_vacuum(coredump_fd
, arg_keep_free
, arg_max_use
);
808 /* Now, let's drop privileges to become the user who owns the
809 * segfaulted process and allocate the coredump memory under
810 * the user's uid. This also ensures that the credentials
811 * journald will see are the ones of the coredumping user,
812 * thus making sure the user gets access to the core
813 * dump. Let's also get rid of all capabilities, if we run as
814 * root, we won't need them anymore. */
815 r
= drop_privileges(uid
, gid
, 0);
817 log_error_errno(r
, "Failed to drop privileges: %m");
822 /* Try to get a strack trace if we can */
823 if (coredump_size
<= arg_process_size_max
) {
824 _cleanup_free_
char *stacktrace
= NULL
;
826 r
= coredump_make_stack_trace(coredump_fd
, exe
, &stacktrace
);
828 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.\n\n", stacktrace
, NULL
);
829 else if (r
== -EINVAL
)
830 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
832 log_warning_errno(r
, "Failed to generate stack trace: %m");
838 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.", NULL
);
840 IOVEC_SET_STRING(iovec
[j
++], core_message
);
842 /* Optionally store the entire coredump in the journal */
843 if (IN_SET(arg_storage
, COREDUMP_STORAGE_JOURNAL
, COREDUMP_STORAGE_BOTH
) &&
844 coredump_size
<= (off_t
) arg_journal_size_max
) {
847 /* Store the coredump itself in the journal */
849 r
= allocate_journal_field(coredump_fd
, (size_t) coredump_size
, &coredump_data
, &sz
);
851 iovec
[j
].iov_base
= coredump_data
;
852 iovec
[j
].iov_len
= sz
;
857 r
= sd_journal_sendv(iovec
, j
);
859 log_error_errno(r
, "Failed to log coredump: %m");
862 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;