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 "alloc-util.h"
38 #include "capability-util.h"
39 #include "cgroup-util.h"
41 #include "conf-parser.h"
43 #include "coredump-vacuum.h"
44 #include "dirent-util.h"
50 #include "journald-native.h"
54 #include "parse-util.h"
55 #include "process-util.h"
57 #include "stacktrace.h"
58 #include "string-table.h"
59 #include "string-util.h"
61 #include "user-util.h"
64 /* The maximum size up to which we process coredumps */
65 #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
67 /* The maximum size up to which we leave the coredump around on
69 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
71 /* The maximum size up to which we store the coredump in the
73 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
75 /* Make sure to not make this larger than the maximum journal entry
76 * size. See DATA_SIZE_MAX in journald-native.c. */
77 assert_cc(JOURNAL_SIZE_MAX
<= DATA_SIZE_MAX
);
90 typedef enum CoredumpStorage
{
91 COREDUMP_STORAGE_NONE
,
92 COREDUMP_STORAGE_EXTERNAL
,
93 COREDUMP_STORAGE_JOURNAL
,
94 COREDUMP_STORAGE_BOTH
,
95 _COREDUMP_STORAGE_MAX
,
96 _COREDUMP_STORAGE_INVALID
= -1
99 static const char* const coredump_storage_table
[_COREDUMP_STORAGE_MAX
] = {
100 [COREDUMP_STORAGE_NONE
] = "none",
101 [COREDUMP_STORAGE_EXTERNAL
] = "external",
102 [COREDUMP_STORAGE_JOURNAL
] = "journal",
103 [COREDUMP_STORAGE_BOTH
] = "both",
106 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage
, CoredumpStorage
);
107 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage
, coredump_storage
, CoredumpStorage
, "Failed to parse storage setting");
109 static CoredumpStorage arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
110 static bool arg_compress
= true;
111 static uint64_t arg_process_size_max
= PROCESS_SIZE_MAX
;
112 static uint64_t arg_external_size_max
= EXTERNAL_SIZE_MAX
;
113 static size_t arg_journal_size_max
= JOURNAL_SIZE_MAX
;
114 static uint64_t arg_keep_free
= (uint64_t) -1;
115 static uint64_t arg_max_use
= (uint64_t) -1;
117 static int parse_config(void) {
118 static const ConfigTableItem items
[] = {
119 { "Coredump", "Storage", config_parse_coredump_storage
, 0, &arg_storage
},
120 { "Coredump", "Compress", config_parse_bool
, 0, &arg_compress
},
121 { "Coredump", "ProcessSizeMax", config_parse_iec_uint64
, 0, &arg_process_size_max
},
122 { "Coredump", "ExternalSizeMax", config_parse_iec_uint64
, 0, &arg_external_size_max
},
123 { "Coredump", "JournalSizeMax", config_parse_iec_size
, 0, &arg_journal_size_max
},
124 { "Coredump", "KeepFree", config_parse_iec_uint64
, 0, &arg_keep_free
},
125 { "Coredump", "MaxUse", config_parse_iec_uint64
, 0, &arg_max_use
},
129 return config_parse_many("/etc/systemd/coredump.conf",
130 CONF_DIRS_NULSTR("systemd/coredump.conf"),
132 config_item_table_lookup
, items
,
136 static int fix_acl(int fd
, uid_t uid
) {
139 _cleanup_(acl_freep
) acl_t acl
= NULL
;
141 acl_permset_t permset
;
146 if (uid
<= SYSTEM_UID_MAX
)
149 /* Make sure normal users can read (but not write or delete)
150 * their own coredumps */
152 acl
= acl_get_fd(fd
);
154 return log_error_errno(errno
, "Failed to get ACL: %m");
156 if (acl_create_entry(&acl
, &entry
) < 0 ||
157 acl_set_tag_type(entry
, ACL_USER
) < 0 ||
158 acl_set_qualifier(entry
, &uid
) < 0) {
159 log_error_errno(errno
, "Failed to patch ACL: %m");
163 if (acl_get_permset(entry
, &permset
) < 0 ||
164 acl_add_perm(permset
, ACL_READ
) < 0)
165 return log_warning_errno(errno
, "Failed to patch ACL: %m");
167 r
= calc_acl_mask_if_needed(&acl
);
169 return log_warning_errno(r
, "Failed to patch ACL: %m");
171 if (acl_set_fd(fd
, acl
) < 0)
172 return log_error_errno(errno
, "Failed to apply ACL: %m");
178 static int fix_xattr(int fd
, const char *info
[_INFO_LEN
]) {
180 static const char * const xattrs
[_INFO_LEN
] = {
181 [INFO_PID
] = "user.coredump.pid",
182 [INFO_UID
] = "user.coredump.uid",
183 [INFO_GID
] = "user.coredump.gid",
184 [INFO_SIGNAL
] = "user.coredump.signal",
185 [INFO_TIMESTAMP
] = "user.coredump.timestamp",
186 [INFO_COMM
] = "user.coredump.comm",
187 [INFO_EXE
] = "user.coredump.exe",
195 /* Attach some metadata to coredumps via extended
196 * attributes. Just because we can. */
198 for (i
= 0; i
< _INFO_LEN
; i
++) {
201 if (isempty(info
[i
]) || !xattrs
[i
])
204 k
= fsetxattr(fd
, xattrs
[i
], info
[i
], strlen(info
[i
]), XATTR_CREATE
);
212 #define filename_escape(s) xescape((s), "./ ")
214 static int fix_permissions(
216 const char *filename
,
218 const char *info
[_INFO_LEN
],
226 /* Ignore errors on these */
232 return log_error_errno(errno
, "Failed to sync coredump %s: %m", filename
);
234 if (rename(filename
, target
) < 0)
235 return log_error_errno(errno
, "Failed to rename coredump %s -> %s: %m", filename
, target
);
240 static int maybe_remove_external_coredump(const char *filename
, uint64_t size
) {
242 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
244 if (IN_SET(arg_storage
, COREDUMP_STORAGE_EXTERNAL
, COREDUMP_STORAGE_BOTH
) &&
245 size
<= arg_external_size_max
)
251 if (unlink(filename
) < 0 && errno
!= ENOENT
)
252 return log_error_errno(errno
, "Failed to unlink %s: %m", filename
);
257 static int make_filename(const char *info
[_INFO_LEN
], char **ret
) {
258 _cleanup_free_
char *c
= NULL
, *u
= NULL
, *p
= NULL
, *t
= NULL
;
259 sd_id128_t boot
= {};
264 c
= filename_escape(info
[INFO_COMM
]);
268 u
= filename_escape(info
[INFO_UID
]);
272 r
= sd_id128_get_boot(&boot
);
276 p
= filename_escape(info
[INFO_PID
]);
280 t
= filename_escape(info
[INFO_TIMESTAMP
]);
285 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR
".%s.%s000000",
288 SD_ID128_FORMAT_VAL(boot
),
296 static int save_external_coredump(
297 const char *info
[_INFO_LEN
],
301 uint64_t *ret_size
) {
303 _cleanup_free_
char *fn
= NULL
, *tmp
= NULL
;
304 _cleanup_close_
int fd
= -1;
309 assert(ret_filename
);
313 r
= make_filename(info
, &fn
);
315 return log_error_errno(r
, "Failed to determine coredump file name: %m");
317 r
= tempfn_random(fn
, NULL
, &tmp
);
319 return log_error_errno(r
, "Failed to determine temporary file name: %m");
321 mkdir_p_label("/var/lib/systemd/coredump", 0755);
323 fd
= open(tmp
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
325 return log_error_errno(errno
, "Failed to create coredump file %s: %m", tmp
);
327 r
= copy_bytes(STDIN_FILENO
, fd
, arg_process_size_max
, false);
329 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
331 } else if (IN_SET(r
, -EDQUOT
, -ENOSPC
)) {
332 log_error("Not enough disk space for coredump of %s (%s), refusing.", info
[INFO_PID
], info
[INFO_COMM
]);
335 log_error_errno(r
, "Failed to dump coredump to file: %m");
339 if (fstat(fd
, &st
) < 0) {
340 log_error_errno(errno
, "Failed to fstat coredump %s: %m", tmp
);
344 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1) {
345 log_error_errno(errno
, "Failed to seek on %s: %m", tmp
);
349 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
350 /* If we will remove the coredump anyway, do not compress. */
351 if (maybe_remove_external_coredump(NULL
, st
.st_size
) == 0
354 _cleanup_free_
char *fn_compressed
= NULL
, *tmp_compressed
= NULL
;
355 _cleanup_close_
int fd_compressed
= -1;
357 fn_compressed
= strappend(fn
, COMPRESSED_EXT
);
358 if (!fn_compressed
) {
363 r
= tempfn_random(fn_compressed
, NULL
, &tmp_compressed
);
365 log_error_errno(r
, "Failed to determine temporary file name for %s: %m", fn_compressed
);
369 fd_compressed
= open(tmp_compressed
, O_CREAT
|O_EXCL
|O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
, 0640);
370 if (fd_compressed
< 0) {
371 log_error_errno(errno
, "Failed to create file %s: %m", tmp_compressed
);
375 r
= compress_stream(fd
, fd_compressed
, -1);
377 log_error_errno(r
, "Failed to compress %s: %m", tmp_compressed
);
378 goto fail_compressed
;
381 r
= fix_permissions(fd_compressed
, tmp_compressed
, fn_compressed
, info
, uid
);
383 goto fail_compressed
;
385 /* OK, this worked, we can get rid of the uncompressed version now */
388 *ret_filename
= fn_compressed
; /* compressed */
389 *ret_fd
= fd
; /* uncompressed */
390 *ret_size
= (uint64_t) st
.st_size
; /* uncompressed */
392 fn_compressed
= NULL
;
398 unlink_noerrno(tmp_compressed
);
403 r
= fix_permissions(fd
, tmp
, fn
, info
, uid
);
409 *ret_size
= (uint64_t) st
.st_size
;
421 static int allocate_journal_field(int fd
, size_t size
, char **ret
, size_t *ret_size
) {
422 _cleanup_free_
char *field
= NULL
;
429 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
430 return log_warning_errno(errno
, "Failed to seek: %m");
432 field
= malloc(9 + size
);
434 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
438 memcpy(field
, "COREDUMP=", 9);
440 n
= read(fd
, field
+ 9, size
);
442 return log_error_errno((int) n
, "Failed to read core data: %m");
443 if ((size_t) n
< size
) {
444 log_error("Core data too short.");
449 *ret_size
= size
+ 9;
456 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
470 static int compose_open_fds(pid_t pid
, char **open_fds
) {
471 _cleanup_closedir_
DIR *proc_fd_dir
= NULL
;
472 _cleanup_close_
int proc_fdinfo_fd
= -1;
473 _cleanup_free_
char *buffer
= NULL
;
474 _cleanup_fclose_
FILE *stream
= NULL
;
475 const char *fddelim
= "", *path
;
476 struct dirent
*dent
= NULL
;
481 assert(open_fds
!= NULL
);
483 path
= procfs_file_alloca(pid
, "fd");
484 proc_fd_dir
= opendir(path
);
488 proc_fdinfo_fd
= openat(dirfd(proc_fd_dir
), "../fdinfo", O_DIRECTORY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
489 if (proc_fdinfo_fd
< 0)
492 stream
= open_memstream(&buffer
, &size
);
496 FOREACH_DIRENT(dent
, proc_fd_dir
, return -errno
) {
497 _cleanup_fclose_
FILE *fdinfo
= NULL
;
498 _cleanup_free_
char *fdname
= NULL
;
502 r
= readlinkat_malloc(dirfd(proc_fd_dir
), dent
->d_name
, &fdname
);
506 fprintf(stream
, "%s%s:%s\n", fddelim
, dent
->d_name
, fdname
);
509 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
510 fd
= openat(proc_fdinfo_fd
, dent
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_RDONLY
);
514 fdinfo
= fdopen(fd
, "re");
515 if (fdinfo
== NULL
) {
520 FOREACH_LINE(line
, fdinfo
, break) {
522 if (!endswith(line
, "\n"))
528 stream
= safe_fclose(stream
);
539 int main(int argc
, char* argv
[]) {
541 /* The small core field we allocate on the stack, to keep things simple */
543 *core_pid
= NULL
, *core_uid
= NULL
, *core_gid
= NULL
, *core_signal
= NULL
,
544 *core_session
= NULL
, *core_exe
= NULL
, *core_comm
= NULL
, *core_cmdline
= NULL
,
545 *core_cgroup
= NULL
, *core_cwd
= NULL
, *core_root
= NULL
, *core_unit
= NULL
,
548 /* The larger ones we allocate on the heap */
550 *core_timestamp
= NULL
, *core_message
= NULL
, *coredump_data
= NULL
, *core_owner_uid
= NULL
,
551 *core_open_fds
= NULL
, *core_proc_status
= NULL
, *core_proc_maps
= NULL
, *core_proc_limits
= NULL
,
552 *core_proc_cgroup
= NULL
, *core_environ
= NULL
;
554 _cleanup_free_
char *exe
= NULL
, *comm
= NULL
, *filename
= NULL
;
555 const char *info
[_INFO_LEN
];
557 _cleanup_close_
int coredump_fd
= -1;
559 struct iovec iovec
[26];
560 uint64_t coredump_size
;
562 uid_t uid
, owner_uid
;
568 /* Make sure we never enter a loop */
569 prctl(PR_SET_DUMPABLE
, 0);
571 /* First, log to a safe place, since we don't know what
572 * crashed and it might be journald which we'd rather not log
574 log_set_target(LOG_TARGET_KMSG
);
577 if (argc
< INFO_COMM
+ 1) {
578 log_error("Not enough arguments passed from kernel (%d, expected %d).",
579 argc
- 1, INFO_COMM
+ 1 - 1);
584 /* Ignore all parse errors */
587 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage
));
588 log_debug("Selected compression %s.", yes_no(arg_compress
));
590 r
= parse_uid(argv
[INFO_UID
+ 1], &uid
);
592 log_error("Failed to parse UID.");
596 r
= parse_pid(argv
[INFO_PID
+ 1], &pid
);
598 log_error("Failed to parse PID.");
602 r
= parse_gid(argv
[INFO_GID
+ 1], &gid
);
604 log_error("Failed to parse GID.");
608 if (get_process_comm(pid
, &comm
) < 0) {
609 log_warning("Failed to get COMM, falling back to the command line.");
610 comm
= strv_join(argv
+ INFO_COMM
+ 1, " ");
613 if (get_process_exe(pid
, &exe
) < 0)
614 log_warning("Failed to get EXE.");
616 info
[INFO_PID
] = argv
[INFO_PID
+ 1];
617 info
[INFO_UID
] = argv
[INFO_UID
+ 1];
618 info
[INFO_GID
] = argv
[INFO_GID
+ 1];
619 info
[INFO_SIGNAL
] = argv
[INFO_SIGNAL
+ 1];
620 info
[INFO_TIMESTAMP
] = argv
[INFO_TIMESTAMP
+ 1];
621 info
[INFO_COMM
] = comm
;
622 info
[INFO_EXE
] = exe
;
624 if (cg_pid_get_unit(pid
, &t
) >= 0) {
626 if (streq(t
, SPECIAL_JOURNALD_SERVICE
)) {
629 /* If we are journald, we cut things short,
630 * don't write to the journal, but still
631 * create a coredump. */
633 if (arg_storage
!= COREDUMP_STORAGE_NONE
)
634 arg_storage
= COREDUMP_STORAGE_EXTERNAL
;
636 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
640 r
= maybe_remove_external_coredump(filename
, coredump_size
);
644 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename
);
648 core_unit
= strjoina("COREDUMP_UNIT=", t
);
651 } else if (cg_pid_get_user_unit(pid
, &t
) >= 0) {
652 core_unit
= strjoina("COREDUMP_USER_UNIT=", t
);
657 IOVEC_SET_STRING(iovec
[j
++], core_unit
);
659 /* OK, now we know it's not the journal, hence we can make use
661 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
);
664 core_pid
= strjoina("COREDUMP_PID=", info
[INFO_PID
]);
665 IOVEC_SET_STRING(iovec
[j
++], core_pid
);
667 core_uid
= strjoina("COREDUMP_UID=", info
[INFO_UID
]);
668 IOVEC_SET_STRING(iovec
[j
++], core_uid
);
670 core_gid
= strjoina("COREDUMP_GID=", info
[INFO_GID
]);
671 IOVEC_SET_STRING(iovec
[j
++], core_gid
);
673 core_signal
= strjoina("COREDUMP_SIGNAL=", info
[INFO_SIGNAL
]);
674 IOVEC_SET_STRING(iovec
[j
++], core_signal
);
676 if (sd_pid_get_session(pid
, &t
) >= 0) {
677 core_session
= strjoina("COREDUMP_SESSION=", t
);
680 IOVEC_SET_STRING(iovec
[j
++], core_session
);
683 if (sd_pid_get_owner_uid(pid
, &owner_uid
) >= 0) {
684 r
= asprintf(&core_owner_uid
,
685 "COREDUMP_OWNER_UID=" UID_FMT
, owner_uid
);
687 IOVEC_SET_STRING(iovec
[j
++], core_owner_uid
);
690 if (sd_pid_get_slice(pid
, &t
) >= 0) {
691 core_slice
= strjoina("COREDUMP_SLICE=", t
);
694 IOVEC_SET_STRING(iovec
[j
++], core_slice
);
698 core_comm
= strjoina("COREDUMP_COMM=", comm
);
699 IOVEC_SET_STRING(iovec
[j
++], core_comm
);
703 core_exe
= strjoina("COREDUMP_EXE=", exe
);
704 IOVEC_SET_STRING(iovec
[j
++], core_exe
);
707 if (get_process_cmdline(pid
, 0, false, &t
) >= 0) {
708 core_cmdline
= strjoina("COREDUMP_CMDLINE=", t
);
711 IOVEC_SET_STRING(iovec
[j
++], core_cmdline
);
714 if (cg_pid_get_path_shifted(pid
, NULL
, &t
) >= 0) {
715 core_cgroup
= strjoina("COREDUMP_CGROUP=", t
);
718 IOVEC_SET_STRING(iovec
[j
++], core_cgroup
);
721 if (compose_open_fds(pid
, &t
) >= 0) {
722 core_open_fds
= strappend("COREDUMP_OPEN_FDS=", t
);
726 IOVEC_SET_STRING(iovec
[j
++], core_open_fds
);
729 p
= procfs_file_alloca(pid
, "status");
730 if (read_full_file(p
, &t
, NULL
) >= 0) {
731 core_proc_status
= strappend("COREDUMP_PROC_STATUS=", t
);
734 if (core_proc_status
)
735 IOVEC_SET_STRING(iovec
[j
++], core_proc_status
);
738 p
= procfs_file_alloca(pid
, "maps");
739 if (read_full_file(p
, &t
, NULL
) >= 0) {
740 core_proc_maps
= strappend("COREDUMP_PROC_MAPS=", t
);
744 IOVEC_SET_STRING(iovec
[j
++], core_proc_maps
);
747 p
= procfs_file_alloca(pid
, "limits");
748 if (read_full_file(p
, &t
, NULL
) >= 0) {
749 core_proc_limits
= strappend("COREDUMP_PROC_LIMITS=", t
);
752 if (core_proc_limits
)
753 IOVEC_SET_STRING(iovec
[j
++], core_proc_limits
);
756 p
= procfs_file_alloca(pid
, "cgroup");
757 if (read_full_file(p
, &t
, NULL
) >=0) {
758 core_proc_cgroup
= strappend("COREDUMP_PROC_CGROUP=", t
);
761 if (core_proc_cgroup
)
762 IOVEC_SET_STRING(iovec
[j
++], core_proc_cgroup
);
765 if (get_process_cwd(pid
, &t
) >= 0) {
766 core_cwd
= strjoina("COREDUMP_CWD=", t
);
769 IOVEC_SET_STRING(iovec
[j
++], core_cwd
);
772 if (get_process_root(pid
, &t
) >= 0) {
773 core_root
= strjoina("COREDUMP_ROOT=", t
);
776 IOVEC_SET_STRING(iovec
[j
++], core_root
);
779 if (get_process_environ(pid
, &t
) >= 0) {
780 core_environ
= strappend("COREDUMP_ENVIRON=", t
);
784 IOVEC_SET_STRING(iovec
[j
++], core_environ
);
787 core_timestamp
= strjoin("COREDUMP_TIMESTAMP=", info
[INFO_TIMESTAMP
], "000000", NULL
);
789 IOVEC_SET_STRING(iovec
[j
++], core_timestamp
);
791 IOVEC_SET_STRING(iovec
[j
++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
792 IOVEC_SET_STRING(iovec
[j
++], "PRIORITY=2");
794 /* Vacuum before we write anything again */
795 coredump_vacuum(-1, arg_keep_free
, arg_max_use
);
797 /* Always stream the coredump to disk, if that's possible */
798 r
= save_external_coredump(info
, uid
, &filename
, &coredump_fd
, &coredump_size
);
800 /* skip whole core dumping part */
803 /* If we don't want to keep the coredump on disk, remove it
804 * now, as later on we will lack the privileges for
805 * it. However, we keep the fd to it, so that we can still
806 * process it and log it. */
807 r
= maybe_remove_external_coredump(filename
, coredump_size
);
811 const char *coredump_filename
;
813 coredump_filename
= strjoina("COREDUMP_FILENAME=", filename
);
814 IOVEC_SET_STRING(iovec
[j
++], coredump_filename
);
817 /* Vacuum again, but exclude the coredump we just created */
818 coredump_vacuum(coredump_fd
, arg_keep_free
, arg_max_use
);
820 /* Now, let's drop privileges to become the user who owns the
821 * segfaulted process and allocate the coredump memory under
822 * the user's uid. This also ensures that the credentials
823 * journald will see are the ones of the coredumping user,
824 * thus making sure the user gets access to the core
825 * dump. Let's also get rid of all capabilities, if we run as
826 * root, we won't need them anymore. */
827 r
= drop_privileges(uid
, gid
, 0);
829 log_error_errno(r
, "Failed to drop privileges: %m");
834 /* Try to get a strack trace if we can */
835 if (coredump_size
<= arg_process_size_max
) {
836 _cleanup_free_
char *stacktrace
= NULL
;
838 r
= coredump_make_stack_trace(coredump_fd
, exe
, &stacktrace
);
840 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.\n\n", stacktrace
, NULL
);
841 else if (r
== -EINVAL
)
842 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
844 log_warning_errno(r
, "Failed to generate stack trace: %m");
850 core_message
= strjoin("MESSAGE=Process ", info
[INFO_PID
], " (", comm
, ") of user ", info
[INFO_UID
], " dumped core.", NULL
);
852 IOVEC_SET_STRING(iovec
[j
++], core_message
);
854 /* Optionally store the entire coredump in the journal */
855 if (IN_SET(arg_storage
, COREDUMP_STORAGE_JOURNAL
, COREDUMP_STORAGE_BOTH
) &&
856 coredump_size
<= arg_journal_size_max
) {
859 /* Store the coredump itself in the journal */
861 r
= allocate_journal_field(coredump_fd
, (size_t) coredump_size
, &coredump_data
, &sz
);
863 iovec
[j
].iov_base
= coredump_data
;
864 iovec
[j
].iov_len
= sz
;
869 r
= sd_journal_sendv(iovec
, j
);
871 log_error_errno(r
, "Failed to log coredump: %m");
874 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;