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/types.h>
27 #include <sys/xattr.h>
31 # include <elfutils/libdwfl.h>
34 #include "systemd/sd-journal.h"
35 #include "systemd/sd-login.h"
44 #include "cgroup-util.h"
45 #include "journald-native.h"
46 #include "conf-parser.h"
48 #include "stacktrace.h"
49 #include "path-util.h"
51 #include "coredump-vacuum.h"
55 # include "acl-util.h"
58 /* The maximum size up to which we process coredumps */
59 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
61 /* The maximum size up to which we leave the coredump around on
63 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
65 /* The maximum size up to which we store the coredump in the
67 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
69 /* Make sure to not make this larger than the maximum journal entry
70 * size. See DATA_SIZE_MAX in journald-native.c. */
71 assert_cc(JOURNAL_SIZE_MAX
<= DATA_SIZE_MAX
);
84 typedef enum CoredumpStorage
{
85 COREDUMP_STORAGE_NONE
,
86 COREDUMP_STORAGE_EXTERNAL
,
87 COREDUMP_STORAGE_JOURNAL
,
88 COREDUMP_STORAGE_BOTH
,
89 _COREDUMP_STORAGE_MAX
,
90 _COREDUMP_STORAGE_INVALID
= -1
93 static const char* const coredump_storage_table
[_COREDUMP_STORAGE_MAX
] = {
94 [COREDUMP_STORAGE_NONE
] = "none",
95 [COREDUMP_STORAGE_EXTERNAL
] = "external",
96 [COREDUMP_STORAGE_JOURNAL
] = "journal",
97 [COREDUMP_STORAGE_BOTH
] = "both",
100 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage
, CoredumpStorage
);
101 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage
, coredump_storage
, CoredumpStorage
, "Failed to parse storage setting");
103 static CoredumpStorage arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
104 static bool arg_compress
= true;
105 static off_t arg_process_size_max
= PROCESS_SIZE_MAX
;
106 static off_t arg_external_size_max
= EXTERNAL_SIZE_MAX
;
107 static size_t arg_journal_size_max
= JOURNAL_SIZE_MAX
;
108 static off_t arg_keep_free
= (off_t
) -1;
109 static off_t arg_max_use
= (off_t
) -1;
111 static int parse_config(void) {
112 static const ConfigTableItem items
[] = {
113 { "Coredump", "Storage", config_parse_coredump_storage
, 0, &arg_storage
},
114 { "Coredump", "Compress", config_parse_bool
, 0, &arg_compress
},
115 { "Coredump", "ProcessSizeMax", config_parse_iec_off
, 0, &arg_process_size_max
},
116 { "Coredump", "ExternalSizeMax", config_parse_iec_off
, 0, &arg_external_size_max
},
117 { "Coredump", "JournalSizeMax", config_parse_iec_size
, 0, &arg_journal_size_max
},
118 { "Coredump", "KeepFree", config_parse_iec_off
, 0, &arg_keep_free
},
119 { "Coredump", "MaxUse", config_parse_iec_off
, 0, &arg_max_use
},
123 return config_parse(NULL
, "/etc/systemd/coredump.conf", NULL
,
125 config_item_table_lookup
, items
,
126 false, false, true, NULL
);
129 static int fix_acl(int fd
, uid_t uid
) {
132 _cleanup_(acl_freep
) acl_t acl
= NULL
;
134 acl_permset_t permset
;
138 if (uid
<= SYSTEM_UID_MAX
)
141 /* Make sure normal users can read (but not write or delete)
142 * their own coredumps */
144 acl
= acl_get_fd(fd
);
146 log_error_errno(errno
, "Failed to get ACL: %m");
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_errno(errno
, "Failed to patch ACL: %m");
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_errno(errno
, "Failed to patch ACL: %m");
164 if (acl_set_fd(fd
, acl
) < 0) {
165 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 log_error_errno(errno
, "Failed to sync coredump %s: %m", filename
);
231 if (rename(filename
, target
) < 0) {
232 log_error_errno(errno
, "Failed to rename coredump %s -> %s: %m", filename
, target
);
239 static int maybe_remove_external_coredump(const char *filename
, off_t size
) {
241 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
243 if (IN_SET(arg_storage
, COREDUMP_STORAGE_EXTERNAL
, COREDUMP_STORAGE_BOTH
) &&
244 size
<= arg_external_size_max
)
250 if (unlink(filename
) < 0 && errno
!= ENOENT
) {
251 log_error_errno(errno
, "Failed to unlink %s: %m", filename
);
258 static int make_filename(const char *info
[_INFO_LEN
], char **ret
) {
259 _cleanup_free_
char *c
= NULL
, *u
= NULL
, *p
= NULL
, *t
= NULL
;
265 c
= filename_escape(info
[INFO_COMM
]);
269 u
= filename_escape(info
[INFO_UID
]);
273 r
= sd_id128_get_boot(&boot
);
277 p
= filename_escape(info
[INFO_PID
]);
281 t
= filename_escape(info
[INFO_TIMESTAMP
]);
286 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR
".%s.%s000000",
289 SD_ID128_FORMAT_VAL(boot
),
297 static int save_external_coredump(
298 const char *info
[_INFO_LEN
],
304 _cleanup_free_
char *fn
= NULL
, *tmp
= NULL
;
305 _cleanup_close_
int fd
= -1;
310 assert(ret_filename
);
314 r
= make_filename(info
, &fn
);
316 return log_error_errno(r
, "Failed to determine coredump file name: %m");
318 tmp
= tempfn_random(fn
);
322 mkdir_p_label("/var/lib/systemd/coredump", 0755);
324 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
326 log_error_errno(errno
, "Failed to create coredump file %s: %m", tmp
);
330 r
= copy_bytes(STDIN_FILENO
, fd
, arg_process_size_max
);
332 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
334 } else if (IN_SET(r
, -EDQUOT
, -ENOSPC
)) {
335 log_error("Not enough disk space for coredump of %s (%s), refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
338 log_error_errno(r
, "Failed to dump coredump to file: %m");
342 if (fstat(fd
, &st
) < 0) {
343 log_error_errno(errno
, "Failed to fstat coredump %s: %m", tmp
);
347 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1) {
348 log_error_errno(errno
, "Failed to seek on %s: %m", tmp
);
352 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
353 /* If we will remove the coredump anyway, do not compress. */
354 if (maybe_remove_external_coredump(NULL
, st
.st_size
) == 0
357 _cleanup_free_
char *fn_compressed
= NULL
, *tmp_compressed
= NULL
;
358 _cleanup_close_
int fd_compressed
= -1;
360 fn_compressed
= strappend(fn
, COMPRESSED_EXT
);
361 if (!fn_compressed
) {
366 tmp_compressed
= tempfn_random(fn_compressed
);
367 if (!tmp_compressed
) {
372 fd_compressed
= open(tmp_compressed
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
373 if (fd_compressed
< 0) {
374 log_error_errno(errno
, "Failed to create file %s: %m", tmp_compressed
);
378 r
= compress_stream(fd
, fd_compressed
, -1);
380 log_error_errno(r
, "Failed to compress %s: %m", tmp_compressed
);
381 goto fail_compressed
;
384 r
= fix_permissions(fd_compressed
, tmp_compressed
, fn_compressed
, info
, uid
);
386 goto fail_compressed
;
388 /* OK, this worked, we can get rid of the uncompressed version now */
391 *ret_filename
= fn_compressed
; /* compressed */
392 *ret_fd
= fd
; /* uncompressed */
393 *ret_size
= st
.st_size
; /* uncompressed */
395 fn_compressed
= NULL
;
401 unlink_noerrno(tmp_compressed
);
406 r
= fix_permissions(fd
, tmp
, fn
, info
, uid
);
412 *ret_size
= st
.st_size
;
424 static int allocate_journal_field(int fd
, size_t size
, char **ret
, size_t *ret_size
) {
425 _cleanup_free_
char *field
= NULL
;
432 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1) {
433 log_warning_errno(errno
, "Failed to seek: %m");
437 field
= malloc(9 + size
);
439 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
443 memcpy(field
, "COREDUMP=", 9);
445 n
= read(fd
, field
+ 9, size
);
447 return log_error_errno((int) n
, "Failed to read core data: %m");
448 if ((size_t) n
< size
) {
449 log_error("Core data too short.");
454 *ret_size
= size
+ 9;
461 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
475 static int compose_open_fds(pid_t pid
, char **open_fds
) {
476 _cleanup_fclose_
FILE *stream
= NULL
;
478 const char *fddelim
= "", *path
;
479 struct dirent
*dent
= NULL
;
480 _cleanup_closedir_
DIR *proc_fd_dir
= NULL
;
481 _cleanup_close_
int proc_fdinfo_fd
= -1;
485 assert(open_fds
!= NULL
);
487 path
= procfs_file_alloca(pid
, "fd");
488 proc_fd_dir
= opendir(path
);
492 proc_fdinfo_fd
= openat(dirfd(proc_fd_dir
), "../fdinfo",
493 O_DIRECTORY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
494 if (proc_fdinfo_fd
< 0)
497 stream
= open_memstream(open_fds
, &ignored_size
);
501 for (dent
= readdir(proc_fd_dir
); dent
!= NULL
; dent
= readdir(proc_fd_dir
)) {
502 _cleanup_free_
char *fdname
= NULL
;
504 _cleanup_fclose_
FILE *fdinfo
= NULL
;
507 if (dent
->d_name
[0] == '.' || strcmp(dent
->d_name
, "..") == 0)
510 r
= readlinkat_malloc(dirfd(proc_fd_dir
), dent
->d_name
, &fdname
);
514 fprintf(stream
, "%s%s:%s\n", fddelim
, dent
->d_name
, fdname
);
517 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
518 fd
= openat(proc_fdinfo_fd
, dent
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_RDONLY
);
522 fdinfo
= fdopen(fd
, "re");
523 if (fdinfo
== NULL
) {
528 while(fgets(line
, sizeof(line
), fdinfo
) != NULL
)
529 fprintf(stream
, "%s%s",
530 line
, strchr(line
, '\n') == NULL
? "\n" : "");
536 int main(int argc
, char* argv
[]) {
538 _cleanup_free_
char *core_pid
= NULL
, *core_uid
= NULL
, *core_gid
= NULL
, *core_signal
= NULL
,
539 *core_timestamp
= NULL
, *core_comm
= NULL
, *core_exe
= NULL
, *core_unit
= NULL
,
540 *core_session
= NULL
, *core_message
= NULL
, *core_cmdline
= NULL
, *coredump_data
= NULL
,
541 *core_slice
= NULL
, *core_cgroup
= NULL
, *core_owner_uid
= NULL
, *core_open_fds
= NULL
,
542 *core_proc_status
= NULL
, *core_proc_maps
= NULL
, *core_proc_limits
= NULL
, *core_proc_cgroup
= NULL
,
543 *core_cwd
= NULL
, *core_root
= NULL
, *core_environ
= NULL
,
544 *exe
= NULL
, *comm
= NULL
, *filename
= NULL
;
545 const char *info
[_INFO_LEN
];
547 _cleanup_close_
int coredump_fd
= -1;
549 struct iovec iovec
[26];
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
)) {
618 /* If we are journald, we cut things short,
619 * don't write to the journal, but still
620 * create a coredump. */
622 if (arg_storage
!= COREDUMP_STORAGE_NONE
)
623 arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
625 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
629 r
= maybe_remove_external_coredump(filename
, coredump_size
);
633 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename
);
637 core_unit
= strappend("COREDUMP_UNIT=", t
);
638 } else if (cg_pid_get_user_unit(pid
, &t
) >= 0)
639 core_unit
= strappend("COREDUMP_USER_UNIT=", t
);
642 IOVEC_SET_STRING(iovec
[j
++], core_unit
);
644 /* OK, now we know it's not the journal, hence we can make use
646 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
);
649 core_pid
= strappend("COREDUMP_PID=", info
[INFO_PID
]);
651 IOVEC_SET_STRING(iovec
[j
++], core_pid
);
653 core_uid
= strappend("COREDUMP_UID=", info
[INFO_UID
]);
655 IOVEC_SET_STRING(iovec
[j
++], core_uid
);
657 core_gid
= strappend("COREDUMP_GID=", info
[INFO_GID
]);
659 IOVEC_SET_STRING(iovec
[j
++], core_gid
);
661 core_signal
= strappend("COREDUMP_SIGNAL=", info
[INFO_SIGNAL
]);
663 IOVEC_SET_STRING(iovec
[j
++], core_signal
);
665 if (sd_pid_get_session(pid
, &t
) >= 0) {
666 core_session
= strappend("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
= strappend("COREDUMP_SLICE=", t
);
685 IOVEC_SET_STRING(iovec
[j
++], core_slice
);
689 core_comm
= strappend("COREDUMP_COMM=", comm
);
691 IOVEC_SET_STRING(iovec
[j
++], core_comm
);
695 core_exe
= strappend("COREDUMP_EXE=", exe
);
697 IOVEC_SET_STRING(iovec
[j
++], core_exe
);
700 if (get_process_cmdline(pid
, 0, false, &t
) >= 0) {
701 core_cmdline
= strappend("COREDUMP_CMDLINE=", t
);
705 IOVEC_SET_STRING(iovec
[j
++], core_cmdline
);
708 if (cg_pid_get_path_shifted(pid
, NULL
, &t
) >= 0) {
709 core_cgroup
= strappend("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
= strappend("COREDUMP_CWD=", t
);
765 IOVEC_SET_STRING(iovec
[j
++], core_cwd
);
768 if (get_process_root(pid
, &t
) >= 0) {
769 core_root
= strappend("COREDUMP_ROOT=", t
);
773 IOVEC_SET_STRING(iovec
[j
++], core_root
);
776 if (get_process_environ(pid
, &t
) >= 0) {
777 core_environ
= strappend("COREDUMP_ENVIRON=", t
);
781 IOVEC_SET_STRING(iovec
[j
++], core_environ
);
784 core_timestamp
= strjoin("COREDUMP_TIMESTAMP=", info
[INFO_TIMESTAMP
], "000000", NULL
);
786 IOVEC_SET_STRING(iovec
[j
++], core_timestamp
);
788 IOVEC_SET_STRING(iovec
[j
++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
789 IOVEC_SET_STRING(iovec
[j
++], "PRIORITY=2");
791 /* Vacuum before we write anything again */
792 coredump_vacuum(-1, arg_keep_free
, arg_max_use
);
794 /* Always stream the coredump to disk, if that's possible */
795 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
797 /* skip whole core dumping part */
800 /* If we don't want to keep the coredump on disk, remove it
801 * now, as later on we will lack the privileges for
802 * it. However, we keep the fd to it, so that we can still
803 * process it and log it. */
804 r
= maybe_remove_external_coredump(filename
, coredump_size
);
808 const char *coredump_filename
;
810 coredump_filename
= strappenda("COREDUMP_FILENAME=", filename
);
811 IOVEC_SET_STRING(iovec
[j
++], coredump_filename
);
814 /* Vacuum again, but exclude the coredump we just created */
815 coredump_vacuum(coredump_fd
, arg_keep_free
, arg_max_use
);
817 /* Now, let's drop privileges to become the user who owns the
818 * segfaulted process and allocate the coredump memory under
819 * the user's uid. This also ensures that the credentials
820 * journald will see are the ones of the coredumping user,
821 * thus making sure the user gets access to the core dump. */
822 if (setresgid(gid
, gid
, gid
) < 0 ||
823 setresuid(uid
, uid
, uid
) < 0) {
824 log_error_errno(errno
, "Failed to drop privileges: %m");
830 /* Try to get a strack trace if we can */
831 if (coredump_size
<= arg_process_size_max
) {
832 _cleanup_free_
char *stacktrace
= NULL
;
834 r
= coredump_make_stack_trace(coredump_fd
, exe
, &stacktrace
);
836 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.\n\n", stacktrace
, NULL
);
837 else if (r
== -EINVAL
)
838 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
840 log_warning_errno(r
, "Failed to generate stack trace: %m");
846 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.", NULL
);
848 IOVEC_SET_STRING(iovec
[j
++], core_message
);
850 /* Optionally store the entire coredump in the journal */
851 if (IN_SET(arg_storage
, COREDUMP_STORAGE_JOURNAL
, COREDUMP_STORAGE_BOTH
) &&
852 coredump_size
<= (off_t
) arg_journal_size_max
) {
855 /* Store the coredump itself in the journal */
857 r
= allocate_journal_field(coredump_fd
, (size_t) coredump_size
, &coredump_data
, &sz
);
859 iovec
[j
].iov_base
= coredump_data
;
860 iovec
[j
].iov_len
= sz
;
865 r
= sd_journal_sendv(iovec
, j
);
867 log_error_errno(r
, "Failed to log coredump: %m");
870 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;