chiark / gitweb /
Fix build without any compression enabled
[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 ENTRY_SIZE_MAX in journald-native.c. */
65 assert_cc(JOURNAL_SIZE_MAX <= ENTRY_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(
118                         NULL,
119                         "/etc/systemd/coredump.conf",
120                         NULL,
121                         "Coredump\0",
122                         config_item_table_lookup,
123                         (void*) items,
124                         false,
125                         false,
126                         NULL);
127 }
128
129 static int fix_acl(int fd, uid_t uid) {
130
131 #ifdef HAVE_ACL
132         _cleanup_(acl_freep) acl_t acl = NULL;
133         acl_entry_t entry;
134         acl_permset_t permset;
135
136         assert(fd >= 0);
137
138         if (uid <= SYSTEM_UID_MAX)
139                 return 0;
140
141         /* Make sure normal users can read (but not write or delete)
142          * their own coredumps */
143
144         acl = acl_get_fd(fd);
145         if (!acl) {
146                 log_error("Failed to get ACL: %m");
147                 return -errno;
148         }
149
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("Failed to patch ACL: %m");
154                 return -errno;
155         }
156
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("Failed to patch ACL: %m");
161                 return -errno;
162         }
163
164         if (acl_set_fd(fd, acl) < 0) {
165                 log_error("Failed to apply ACL: %m");
166                 return -errno;
167         }
168 #endif
169
170         return 0;
171 }
172
173 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
174
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",
183         };
184
185         int r = 0;
186         unsigned i;
187
188         assert(fd >= 0);
189
190         /* Attach some metadata to coredumps via extended
191          * attributes. Just because we can. */
192
193         for (i = 0; i < _INFO_LEN; i++) {
194                 int k;
195
196                 if (isempty(info[i]) || !xattrs[i])
197                         continue;
198
199                 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
200                 if (k < 0 && r == 0)
201                         r = -errno;
202         }
203
204         return r;
205 }
206
207 #define filename_escape(s) xescape((s), "./ ")
208
209 static int fix_permissions(
210                 int fd,
211                 const char *filename,
212                 const char *target,
213                 const char *info[_INFO_LEN],
214                 uid_t uid) {
215
216         assert(fd >= 0);
217         assert(filename);
218         assert(target);
219         assert(info);
220
221         /* Ignore errors on these */
222         fchmod(fd, 0640);
223         fix_acl(fd, uid);
224         fix_xattr(fd, info);
225
226         if (fsync(fd) < 0) {
227                 log_error("Failed to sync coredump %s: %m", filename);
228                 return -errno;
229         }
230
231         if (rename(filename, target) < 0) {
232                 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
233                 return -errno;
234         }
235
236         return 0;
237 }
238
239 static int maybe_remove_external_coredump(const char *filename, off_t size) {
240
241         /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
242
243         if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
244             size <= arg_external_size_max)
245                 return 0;
246
247         if (!filename)
248                 return 1;
249
250         if (unlink(filename) < 0 && errno != ENOENT) {
251                 log_error("Failed to unlink %s: %m", filename);
252                 return -errno;
253         }
254
255         return 1;
256 }
257
258 static int make_filename(const char *info[_INFO_LEN], char **ret) {
259         _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
260         sd_id128_t boot;
261         int r;
262
263         assert(info);
264
265         c = filename_escape(info[INFO_COMM]);
266         if (!c)
267                 return -ENOMEM;
268
269         u = filename_escape(info[INFO_UID]);
270         if (!u)
271                 return -ENOMEM;
272
273         r = sd_id128_get_boot(&boot);
274         if (r < 0)
275                 return r;
276
277         p = filename_escape(info[INFO_PID]);
278         if (!p)
279                 return -ENOMEM;
280
281         t = filename_escape(info[INFO_TIMESTAMP]);
282         if (!t)
283                 return -ENOMEM;
284
285         if (asprintf(ret,
286                      "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
287                      c,
288                      u,
289                      SD_ID128_FORMAT_VAL(boot),
290                      p,
291                      t) < 0)
292                 return -ENOMEM;
293
294         return 0;
295 }
296
297 static int save_external_coredump(
298                 const char *info[_INFO_LEN],
299                 uid_t uid,
300                 char **ret_filename,
301                 int *ret_fd,
302                 off_t *ret_size) {
303
304         _cleanup_free_ char *fn = NULL, *tmp = NULL;
305         _cleanup_close_ int fd = -1;
306         struct stat st;
307         int r;
308
309         assert(info);
310         assert(ret_filename);
311         assert(ret_fd);
312         assert(ret_size);
313
314         r = make_filename(info, &fn);
315         if (r < 0) {
316                 log_error("Failed to determine coredump file name: %s", strerror(-r));
317                 return r;
318         }
319
320         tmp = tempfn_random(fn);
321         if (!tmp)
322                 return log_oom();
323
324         mkdir_p_label("/var/lib/systemd/coredump", 0755);
325
326         fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
327         if (fd < 0) {
328                 log_error("Failed to create coredump file %s: %m", tmp);
329                 return -errno;
330         }
331
332         r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
333         if (r == -E2BIG) {
334                 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
335                 goto fail;
336         } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
337                 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
338                 goto fail;
339         } else if (r < 0) {
340                 log_error("Failed to dump coredump to file: %s", strerror(-r));
341                 goto fail;
342         }
343
344         if (fstat(fd, &st) < 0) {
345                 log_error("Failed to fstat coredump %s: %m", tmp);
346                 goto fail;
347         }
348
349         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
350                 log_error("Failed to seek on %s: %m", tmp);
351                 goto fail;
352         }
353
354 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
355         /* If we will remove the coredump anyway, do not compress. */
356         if (maybe_remove_external_coredump(NULL, st.st_size) == 0
357             && arg_compress) {
358
359                 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
360                 _cleanup_close_ int fd_compressed = -1;
361
362                 fn_compressed = strappend(fn, COMPRESSED_EXT);
363                 if (!fn_compressed) {
364                         log_oom();
365                         goto uncompressed;
366                 }
367
368                 tmp_compressed = tempfn_random(fn_compressed);
369                 if (!tmp_compressed) {
370                         log_oom();
371                         goto uncompressed;
372                 }
373
374                 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
375                 if (fd_compressed < 0) {
376                         log_error("Failed to create file %s: %m", tmp_compressed);
377                         goto uncompressed;
378                 }
379
380                 r = compress_stream(fd, fd_compressed, -1);
381                 if (r < 0) {
382                         log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
383                         goto fail_compressed;
384                 }
385
386                 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
387                 if (r < 0)
388                         goto fail_compressed;
389
390                 /* OK, this worked, we can get rid of the uncompressed version now */
391                 unlink_noerrno(tmp);
392
393                 *ret_filename = fn_compressed;    /* compressed */
394                 *ret_fd = fd;                     /* uncompressed */
395                 *ret_size = st.st_size;           /* uncompressed */
396
397                 fn_compressed = NULL;
398                 fd = -1;
399
400                 return 0;
401
402         fail_compressed:
403                 unlink_noerrno(tmp_compressed);
404         }
405
406 uncompressed:
407 #endif
408         r = fix_permissions(fd, tmp, fn, info, uid);
409         if (r < 0)
410                 goto fail;
411
412         *ret_filename = fn;
413         *ret_fd = fd;
414         *ret_size = st.st_size;
415
416         fn = NULL;
417         fd = -1;
418
419         return 0;
420
421 fail:
422         unlink_noerrno(tmp);
423         return r;
424 }
425
426 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
427         _cleanup_free_ char *field = NULL;
428         ssize_t n;
429
430         assert(fd >= 0);
431         assert(ret);
432         assert(ret_size);
433
434         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
435                 log_warning("Failed to seek: %m");
436                 return -errno;
437         }
438
439         field = malloc(9 + size);
440         if (!field) {
441                 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
442                 return -ENOMEM;
443         }
444
445         memcpy(field, "COREDUMP=", 9);
446
447         n = read(fd, field + 9, size);
448         if (n < 0) {
449                 log_error("Failed to read core data: %s", strerror(-n));
450                 return (int) n;
451         }
452         if ((size_t) n < size) {
453                 log_error("Core data too short.");
454                 return -EIO;
455         }
456
457         *ret = field;
458         *ret_size = size + 9;
459
460         field = NULL;
461
462         return 0;
463 }
464
465 int main(int argc, char* argv[]) {
466
467         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
468                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
469                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
470                 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
471                 *exe = NULL, *comm = NULL, *filename = NULL;
472         const char *info[_INFO_LEN];
473
474         _cleanup_close_ int coredump_fd = -1;
475
476         struct iovec iovec[18];
477         off_t coredump_size;
478         int r, j = 0;
479         uid_t uid, owner_uid;
480         gid_t gid;
481         pid_t pid;
482         char *t;
483
484         /* Make sure we never enter a loop */
485         prctl(PR_SET_DUMPABLE, 0);
486
487         /* First, log to a safe place, since we don't know what
488          * crashed and it might be journald which we'd rather not log
489          * to then. */
490         log_set_target(LOG_TARGET_KMSG);
491         log_open();
492
493         if (argc < INFO_COMM + 1) {
494                 log_error("Not enough arguments passed from kernel (%d, expected %d).",
495                           argc - 1, INFO_COMM + 1 - 1);
496                 r = -EINVAL;
497                 goto finish;
498         }
499
500         /* Ignore all parse errors */
501         parse_config();
502
503         log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
504         log_debug("Selected compression %s.", yes_no(arg_compress));
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, &filename, &coredump_fd, &coredump_size);
552                         if (r < 0)
553                                 goto finish;
554
555                         r = maybe_remove_external_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.", 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         /* Vacuum before we write anything again */
650         coredump_vacuum(-1, arg_keep_free, arg_max_use);
651
652         /* Always stream the coredump to disk, if that's possible */
653         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
654         if (r < 0)
655                 /* skip whole core dumping part */
656                 goto log;
657
658         /* If we don't want to keep the coredump on disk, remove it
659          * now, as later on we will lack the privileges for
660          * it. However, we keep the fd to it, so that we can still
661          * process it and log it. */
662         r = maybe_remove_external_coredump(filename, coredump_size);
663         if (r < 0)
664                 goto finish;
665         if (r == 0) {
666                 const char *coredump_filename;
667
668                 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
669                 IOVEC_SET_STRING(iovec[j++], coredump_filename);
670         }
671
672         /* Vacuum again, but exclude the coredump we just created */
673         coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
674
675         /* Now, let's drop privileges to become the user who owns the
676          * segfaulted process and allocate the coredump memory under
677          * his uid. This also ensures that the credentials journald
678          * will see are the ones of the coredumping user, thus making
679          * sure the user himself gets access to the core dump. */
680         if (setresgid(gid, gid, gid) < 0 ||
681             setresuid(uid, uid, uid) < 0) {
682                 log_error("Failed to drop privileges: %m");
683                 r = -errno;
684                 goto finish;
685         }
686
687 #ifdef HAVE_ELFUTILS
688         /* Try to get a strack trace if we can */
689         if (coredump_size <= arg_process_size_max) {
690                 _cleanup_free_ char *stacktrace = NULL;
691
692                 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
693                 if (r >= 0)
694                         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
695                 else
696                         log_warning("Failed to generate stack trace: %s", strerror(-r));
697         }
698
699         if (!core_message)
700 #endif
701 log:
702         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
703         if (core_message)
704                 IOVEC_SET_STRING(iovec[j++], core_message);
705
706         /* Optionally store the entire coredump in the journal */
707         if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
708             coredump_size <= (off_t) arg_journal_size_max) {
709                 size_t sz;
710
711                 /* Store the coredump itself in the journal */
712
713                 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
714                 if (r >= 0) {
715                         iovec[j].iov_base = coredump_data;
716                         iovec[j].iov_len = sz;
717                         j++;
718                 }
719         }
720
721         r = sd_journal_sendv(iovec, j);
722         if (r < 0)
723                 log_error("Failed to log coredump: %s", strerror(-r));
724
725 finish:
726         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
727 }