]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/journal/coredump.c
coredumpctl: remove unused variable
[thirdparty/systemd.git] / src / journal / coredump.c
... / ...
CommitLineData
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. */
70assert_cc(JOURNAL_SIZE_MAX <= ENTRY_SIZE_MAX);
71
72enum {
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
83typedef 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
92static 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
99DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
100static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage,
101 CoredumpStorage,
102 "Failed to parse storage setting");
103
104typedef enum CoredumpCompression {
105 COREDUMP_COMPRESSION_NONE,
106 COREDUMP_COMPRESSION_XZ,
107 _COREDUMP_COMPRESSION_MAX,
108 _COREDUMP_COMPRESSION_INVALID = -1
109} CoredumpCompression;
110
111static const char* const coredump_compression_table[_COREDUMP_COMPRESSION_MAX] = {
112 [COREDUMP_COMPRESSION_NONE] = "none",
113 [COREDUMP_COMPRESSION_XZ] = "xz",
114};
115
116DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_compression, CoredumpCompression);
117static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_compression, coredump_compression,
118 CoredumpCompression,
119 "Failed to parse compression setting");
120
121static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
122static CoredumpCompression arg_compression = COREDUMP_COMPRESSION_XZ;
123static unsigned arg_compression_level = LZMA_PRESET_DEFAULT;
124
125static off_t arg_process_size_max = PROCESS_SIZE_MAX;
126static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
127static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
128
129static 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
161static 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
203static 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
237static 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
258static 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
278static 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
405uncompressed:
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
419fail:
420 unlink_noerrno(tmp);
421 return r;
422}
423
424static 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
463int 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 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
469 *exe = NULL, *comm = NULL, *filename = NULL;
470 const char *info[_INFO_LEN];
471
472 _cleanup_close_ int coredump_fd = -1;
473
474 struct iovec iovec[18];
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_compression),
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, &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 /* Always stream the coredump to disk, if that's possible */
650 r = save_external_coredump(info, uid, &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(filename, coredump_size);
660 if (r < 0)
661 goto finish;
662 if (r == 0) {
663 const char *coredump_filename;
664
665 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
666 IOVEC_SET_STRING(iovec[j++], coredump_filename);
667 }
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
695log:
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
719finish:
720 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
721}