chiark / gitweb /
182c2b1bad1e0f31d211fa99160067c00b23bc41
[elogind.git] / src / journal / coredump.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <sys/prctl.h>
26 #include <sys/types.h>
27 #include <sys/xattr.h>
28
29 #include <systemd/sd-journal.h>
30 #include <systemd/sd-login.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "strv.h"
35 #include "macro.h"
36 #include "mkdir.h"
37 #include "special.h"
38 #include "cgroup-util.h"
39 #include "journald-native.h"
40 #include "conf-parser.h"
41 #include "copy.h"
42 #include "stacktrace.h"
43 #include "path-util.h"
44 #include "compress.h"
45 #include "coredump-vacuum.h"
46
47 #ifdef HAVE_ACL
48 #  include <sys/acl.h>
49 #  include "acl-util.h"
50 #endif
51
52 /* The maximum size up to which we process coredumps */
53 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
54
55 /* The maximum size up to which we leave the coredump around on
56  * disk */
57 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
58
59 /* The maximum size up to which we store the coredump in the
60  * journal */
61 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
62
63 /* Make sure to not make this larger than the maximum journal entry
64  * size. See DATA_SIZE_MAX in journald-native.c. */
65 assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
66
67 enum {
68         INFO_PID,
69         INFO_UID,
70         INFO_GID,
71         INFO_SIGNAL,
72         INFO_TIMESTAMP,
73         INFO_COMM,
74         INFO_EXE,
75         _INFO_LEN
76 };
77
78 typedef enum CoredumpStorage {
79         COREDUMP_STORAGE_NONE,
80         COREDUMP_STORAGE_EXTERNAL,
81         COREDUMP_STORAGE_JOURNAL,
82         COREDUMP_STORAGE_BOTH,
83         _COREDUMP_STORAGE_MAX,
84         _COREDUMP_STORAGE_INVALID = -1
85 } CoredumpStorage;
86
87 static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
88         [COREDUMP_STORAGE_NONE] = "none",
89         [COREDUMP_STORAGE_EXTERNAL] = "external",
90         [COREDUMP_STORAGE_JOURNAL] = "journal",
91         [COREDUMP_STORAGE_BOTH] = "both",
92 };
93
94 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
95 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
96
97 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
98 static bool arg_compress = true;
99 static off_t arg_process_size_max = PROCESS_SIZE_MAX;
100 static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
101 static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
102 static off_t arg_keep_free = (off_t) -1;
103 static off_t arg_max_use = (off_t) -1;
104
105 static int parse_config(void) {
106         static const ConfigTableItem items[] = {
107                 { "Coredump", "Storage",          config_parse_coredump_storage,  0, &arg_storage           },
108                 { "Coredump", "Compress",         config_parse_bool,              0, &arg_compress          },
109                 { "Coredump", "ProcessSizeMax",   config_parse_iec_off,           0, &arg_process_size_max  },
110                 { "Coredump", "ExternalSizeMax",  config_parse_iec_off,           0, &arg_external_size_max },
111                 { "Coredump", "JournalSizeMax",   config_parse_iec_size,          0, &arg_journal_size_max  },
112                 { "Coredump", "KeepFree",         config_parse_iec_off,           0, &arg_keep_free         },
113                 { "Coredump", "MaxUse",           config_parse_iec_off,           0, &arg_max_use           },
114                 {}
115         };
116
117         return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
118                             "Coredump\0",
119                             config_item_table_lookup, items,
120                             false, false, true, NULL);
121 }
122
123 static int fix_acl(int fd, uid_t uid) {
124
125 #ifdef HAVE_ACL
126         _cleanup_(acl_freep) acl_t acl = NULL;
127         acl_entry_t entry;
128         acl_permset_t permset;
129
130         assert(fd >= 0);
131
132         if (uid <= SYSTEM_UID_MAX)
133                 return 0;
134
135         /* Make sure normal users can read (but not write or delete)
136          * their own coredumps */
137
138         acl = acl_get_fd(fd);
139         if (!acl) {
140                 log_error("Failed to get ACL: %m");
141                 return -errno;
142         }
143
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("Failed to patch ACL: %m");
148                 return -errno;
149         }
150
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("Failed to patch ACL: %m");
155                 return -errno;
156         }
157
158         if (acl_set_fd(fd, acl) < 0) {
159                 log_error("Failed to apply ACL: %m");
160                 return -errno;
161         }
162 #endif
163
164         return 0;
165 }
166
167 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
168
169         static const char * const xattrs[_INFO_LEN] = {
170                 [INFO_PID] = "user.coredump.pid",
171                 [INFO_UID] = "user.coredump.uid",
172                 [INFO_GID] = "user.coredump.gid",
173                 [INFO_SIGNAL] = "user.coredump.signal",
174                 [INFO_TIMESTAMP] = "user.coredump.timestamp",
175                 [INFO_COMM] = "user.coredump.comm",
176                 [INFO_EXE] = "user.coredump.exe",
177         };
178
179         int r = 0;
180         unsigned i;
181
182         assert(fd >= 0);
183
184         /* Attach some metadata to coredumps via extended
185          * attributes. Just because we can. */
186
187         for (i = 0; i < _INFO_LEN; i++) {
188                 int k;
189
190                 if (isempty(info[i]) || !xattrs[i])
191                         continue;
192
193                 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
194                 if (k < 0 && r == 0)
195                         r = -errno;
196         }
197
198         return r;
199 }
200
201 #define filename_escape(s) xescape((s), "./ ")
202
203 static int fix_permissions(
204                 int fd,
205                 const char *filename,
206                 const char *target,
207                 const char *info[_INFO_LEN],
208                 uid_t uid) {
209
210         assert(fd >= 0);
211         assert(filename);
212         assert(target);
213         assert(info);
214
215         /* Ignore errors on these */
216         fchmod(fd, 0640);
217         fix_acl(fd, uid);
218         fix_xattr(fd, info);
219
220         if (fsync(fd) < 0) {
221                 log_error("Failed to sync coredump %s: %m", filename);
222                 return -errno;
223         }
224
225         if (rename(filename, target) < 0) {
226                 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
227                 return -errno;
228         }
229
230         return 0;
231 }
232
233 static int maybe_remove_external_coredump(const char *filename, off_t size) {
234
235         /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
236
237         if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
238             size <= arg_external_size_max)
239                 return 0;
240
241         if (!filename)
242                 return 1;
243
244         if (unlink(filename) < 0 && errno != ENOENT) {
245                 log_error("Failed to unlink %s: %m", filename);
246                 return -errno;
247         }
248
249         return 1;
250 }
251
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;
255         int r;
256
257         assert(info);
258
259         c = filename_escape(info[INFO_COMM]);
260         if (!c)
261                 return -ENOMEM;
262
263         u = filename_escape(info[INFO_UID]);
264         if (!u)
265                 return -ENOMEM;
266
267         r = sd_id128_get_boot(&boot);
268         if (r < 0)
269                 return r;
270
271         p = filename_escape(info[INFO_PID]);
272         if (!p)
273                 return -ENOMEM;
274
275         t = filename_escape(info[INFO_TIMESTAMP]);
276         if (!t)
277                 return -ENOMEM;
278
279         if (asprintf(ret,
280                      "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
281                      c,
282                      u,
283                      SD_ID128_FORMAT_VAL(boot),
284                      p,
285                      t) < 0)
286                 return -ENOMEM;
287
288         return 0;
289 }
290
291 static int save_external_coredump(
292                 const char *info[_INFO_LEN],
293                 uid_t uid,
294                 char **ret_filename,
295                 int *ret_fd,
296                 off_t *ret_size) {
297
298         _cleanup_free_ char *fn = NULL, *tmp = NULL;
299         _cleanup_close_ int fd = -1;
300         struct stat st;
301         int r;
302
303         assert(info);
304         assert(ret_filename);
305         assert(ret_fd);
306         assert(ret_size);
307
308         r = make_filename(info, &fn);
309         if (r < 0) {
310                 log_error("Failed to determine coredump file name: %s", strerror(-r));
311                 return r;
312         }
313
314         tmp = tempfn_random(fn);
315         if (!tmp)
316                 return log_oom();
317
318         mkdir_p_label("/var/lib/systemd/coredump", 0755);
319
320         fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
321         if (fd < 0) {
322                 log_error("Failed to create coredump file %s: %m", tmp);
323                 return -errno;
324         }
325
326         r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
327         if (r == -E2BIG) {
328                 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
329                 goto fail;
330         } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
331                 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
332                 goto fail;
333         } else if (r < 0) {
334                 log_error("Failed to dump coredump to file: %s", strerror(-r));
335                 goto fail;
336         }
337
338         if (fstat(fd, &st) < 0) {
339                 log_error("Failed to fstat coredump %s: %m", tmp);
340                 goto fail;
341         }
342
343         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
344                 log_error("Failed to seek on %s: %m", tmp);
345                 goto fail;
346         }
347
348 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
349         /* If we will remove the coredump anyway, do not compress. */
350         if (maybe_remove_external_coredump(NULL, st.st_size) == 0
351             && arg_compress) {
352
353                 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
354                 _cleanup_close_ int fd_compressed = -1;
355
356                 fn_compressed = strappend(fn, COMPRESSED_EXT);
357                 if (!fn_compressed) {
358                         log_oom();
359                         goto uncompressed;
360                 }
361
362                 tmp_compressed = tempfn_random(fn_compressed);
363                 if (!tmp_compressed) {
364                         log_oom();
365                         goto uncompressed;
366                 }
367
368                 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
369                 if (fd_compressed < 0) {
370                         log_error("Failed to create file %s: %m", tmp_compressed);
371                         goto uncompressed;
372                 }
373
374                 r = compress_stream(fd, fd_compressed, -1);
375                 if (r < 0) {
376                         log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
377                         goto fail_compressed;
378                 }
379
380                 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
381                 if (r < 0)
382                         goto fail_compressed;
383
384                 /* OK, this worked, we can get rid of the uncompressed version now */
385                 unlink_noerrno(tmp);
386
387                 *ret_filename = fn_compressed;    /* compressed */
388                 *ret_fd = fd;                     /* uncompressed */
389                 *ret_size = st.st_size;           /* uncompressed */
390
391                 fn_compressed = NULL;
392                 fd = -1;
393
394                 return 0;
395
396         fail_compressed:
397                 unlink_noerrno(tmp_compressed);
398         }
399
400 uncompressed:
401 #endif
402         r = fix_permissions(fd, tmp, fn, info, uid);
403         if (r < 0)
404                 goto fail;
405
406         *ret_filename = fn;
407         *ret_fd = fd;
408         *ret_size = st.st_size;
409
410         fn = NULL;
411         fd = -1;
412
413         return 0;
414
415 fail:
416         unlink_noerrno(tmp);
417         return r;
418 }
419
420 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
421         _cleanup_free_ char *field = NULL;
422         ssize_t n;
423
424         assert(fd >= 0);
425         assert(ret);
426         assert(ret_size);
427
428         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
429                 log_warning("Failed to seek: %m");
430                 return -errno;
431         }
432
433         field = malloc(9 + size);
434         if (!field) {
435                 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
436                 return -ENOMEM;
437         }
438
439         memcpy(field, "COREDUMP=", 9);
440
441         n = read(fd, field + 9, size);
442         if (n < 0) {
443                 log_error("Failed to read core data: %s", strerror(-n));
444                 return (int) n;
445         }
446         if ((size_t) n < size) {
447                 log_error("Core data too short.");
448                 return -EIO;
449         }
450
451         *ret = field;
452         *ret_size = size + 9;
453
454         field = NULL;
455
456         return 0;
457 }
458
459 int main(int argc, char* argv[]) {
460
461         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
462                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
463                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
464                 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
465                 *exe = NULL, *comm = NULL, *filename = NULL;
466         const char *info[_INFO_LEN];
467
468         _cleanup_close_ int coredump_fd = -1;
469
470         struct iovec iovec[18];
471         off_t coredump_size;
472         int r, j = 0;
473         uid_t uid, owner_uid;
474         gid_t gid;
475         pid_t pid;
476         char *t;
477
478         /* Make sure we never enter a loop */
479         prctl(PR_SET_DUMPABLE, 0);
480
481         /* First, log to a safe place, since we don't know what
482          * crashed and it might be journald which we'd rather not log
483          * to then. */
484         log_set_target(LOG_TARGET_KMSG);
485         log_open();
486
487         if (argc < INFO_COMM + 1) {
488                 log_error("Not enough arguments passed from kernel (%d, expected %d).",
489                           argc - 1, INFO_COMM + 1 - 1);
490                 r = -EINVAL;
491                 goto finish;
492         }
493
494         /* Ignore all parse errors */
495         parse_config();
496
497         log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
498         log_debug("Selected compression %s.", yes_no(arg_compress));
499
500         r = parse_uid(argv[INFO_UID + 1], &uid);
501         if (r < 0) {
502                 log_error("Failed to parse UID.");
503                 goto finish;
504         }
505
506         r = parse_pid(argv[INFO_PID + 1], &pid);
507         if (r < 0) {
508                 log_error("Failed to parse PID.");
509                 goto finish;
510         }
511
512         r = parse_gid(argv[INFO_GID + 1], &gid);
513         if (r < 0) {
514                 log_error("Failed to parse GID.");
515                 goto finish;
516         }
517
518         if (get_process_comm(pid, &comm) < 0) {
519                 log_warning("Failed to get COMM, falling back to the commandline.");
520                 comm = strv_join(argv + INFO_COMM + 1, " ");
521         }
522
523         if (get_process_exe(pid, &exe) < 0)
524                 log_warning("Failed to get EXE.");
525
526         info[INFO_PID] = argv[INFO_PID + 1];
527         info[INFO_UID] = argv[INFO_UID + 1];
528         info[INFO_GID] = argv[INFO_GID + 1];
529         info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
530         info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
531         info[INFO_COMM] = comm;
532         info[INFO_EXE] = exe;
533
534         if (cg_pid_get_unit(pid, &t) >= 0) {
535
536                 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
537
538                         /* If we are journald, we cut things short,
539                          * don't write to the journal, but still
540                          * create a coredump. */
541
542                         if (arg_storage != COREDUMP_STORAGE_NONE)
543                                 arg_storage = COREDUMP_STORAGE_EXTERNAL;
544
545                         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
546                         if (r < 0)
547                                 goto finish;
548
549                         r = maybe_remove_external_coredump(filename, coredump_size);
550                         if (r < 0)
551                                 goto finish;
552
553                         log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
554                         goto finish;
555                 }
556
557                 core_unit = strappend("COREDUMP_UNIT=", t);
558         } else if (cg_pid_get_user_unit(pid, &t) >= 0)
559                 core_unit = strappend("COREDUMP_USER_UNIT=", t);
560
561         if (core_unit)
562                 IOVEC_SET_STRING(iovec[j++], core_unit);
563
564         /* OK, now we know it's not the journal, hence we can make use
565          * of it now. */
566         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
567         log_open();
568
569         core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
570         if (core_pid)
571                 IOVEC_SET_STRING(iovec[j++], core_pid);
572
573         core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
574         if (core_uid)
575                 IOVEC_SET_STRING(iovec[j++], core_uid);
576
577         core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
578         if (core_gid)
579                 IOVEC_SET_STRING(iovec[j++], core_gid);
580
581         core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
582         if (core_signal)
583                 IOVEC_SET_STRING(iovec[j++], core_signal);
584
585         if (sd_pid_get_session(pid, &t) >= 0) {
586                 core_session = strappend("COREDUMP_SESSION=", t);
587                 free(t);
588
589                 if (core_session)
590                         IOVEC_SET_STRING(iovec[j++], core_session);
591         }
592
593         if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
594                 asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
595
596                 if (core_owner_uid)
597                         IOVEC_SET_STRING(iovec[j++], core_owner_uid);
598         }
599
600         if (sd_pid_get_slice(pid, &t) >= 0) {
601                 core_slice = strappend("COREDUMP_SLICE=", t);
602                 free(t);
603
604                 if (core_slice)
605                         IOVEC_SET_STRING(iovec[j++], core_slice);
606         }
607
608         if (comm) {
609                 core_comm = strappend("COREDUMP_COMM=", comm);
610                 if (core_comm)
611                         IOVEC_SET_STRING(iovec[j++], core_comm);
612         }
613
614         if (exe) {
615                 core_exe = strappend("COREDUMP_EXE=", exe);
616                 if (core_exe)
617                         IOVEC_SET_STRING(iovec[j++], core_exe);
618         }
619
620         if (get_process_cmdline(pid, 0, false, &t) >= 0) {
621                 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
622                 free(t);
623
624                 if (core_cmdline)
625                         IOVEC_SET_STRING(iovec[j++], core_cmdline);
626         }
627
628         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
629                 core_cgroup = strappend("COREDUMP_CGROUP=", t);
630                 free(t);
631
632                 if (core_cgroup)
633                         IOVEC_SET_STRING(iovec[j++], core_cgroup);
634         }
635
636         core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
637         if (core_timestamp)
638                 IOVEC_SET_STRING(iovec[j++], core_timestamp);
639
640         IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
641         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
642
643         /* Vacuum before we write anything again */
644         coredump_vacuum(-1, arg_keep_free, arg_max_use);
645
646         /* Always stream the coredump to disk, if that's possible */
647         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
648         if (r < 0)
649                 /* skip whole core dumping part */
650                 goto log;
651
652         /* If we don't want to keep the coredump on disk, remove it
653          * now, as later on we will lack the privileges for
654          * it. However, we keep the fd to it, so that we can still
655          * process it and log it. */
656         r = maybe_remove_external_coredump(filename, coredump_size);
657         if (r < 0)
658                 goto finish;
659         if (r == 0) {
660                 const char *coredump_filename;
661
662                 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
663                 IOVEC_SET_STRING(iovec[j++], coredump_filename);
664         }
665
666         /* Vacuum again, but exclude the coredump we just created */
667         coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
668
669         /* Now, let's drop privileges to become the user who owns the
670          * segfaulted process and allocate the coredump memory under
671          * his uid. This also ensures that the credentials journald
672          * will see are the ones of the coredumping user, thus making
673          * sure the user himself gets access to the core dump. */
674         if (setresgid(gid, gid, gid) < 0 ||
675             setresuid(uid, uid, uid) < 0) {
676                 log_error("Failed to drop privileges: %m");
677                 r = -errno;
678                 goto finish;
679         }
680
681 #ifdef HAVE_ELFUTILS
682         /* Try to get a strack trace if we can */
683         if (coredump_size <= arg_process_size_max) {
684                 _cleanup_free_ char *stacktrace = NULL;
685
686                 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
687                 if (r >= 0)
688                         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
689                 else
690                         log_warning("Failed to generate stack trace: %s", strerror(-r));
691         }
692
693         if (!core_message)
694 #endif
695 log:
696         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
697         if (core_message)
698                 IOVEC_SET_STRING(iovec[j++], core_message);
699
700         /* Optionally store the entire coredump in the journal */
701         if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
702             coredump_size <= (off_t) arg_journal_size_max) {
703                 size_t sz;
704
705                 /* Store the coredump itself in the journal */
706
707                 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
708                 if (r >= 0) {
709                         iovec[j].iov_base = coredump_data;
710                         iovec[j].iov_len = sz;
711                         j++;
712                 }
713         }
714
715         r = sd_journal_sendv(iovec, j);
716         if (r < 0)
717                 log_error("Failed to log coredump: %s", strerror(-r));
718
719 finish:
720         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
721 }