]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/coredump.c
shell-completion: prevent mangling unit names
[thirdparty/systemd.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 }