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