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