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