]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
logs-show: show messages for all unit types in systemctl status
[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>
f5e04665
LP
26
27#include <systemd/sd-journal.h>
ba1261bc
LP
28
29#ifdef HAVE_LOGIND
f5e04665 30#include <systemd/sd-login.h>
ba1261bc 31#endif
f5e04665
LP
32
33#include "log.h"
34#include "util.h"
49e942b2 35#include "mkdir.h"
803a3464 36#include "special.h"
ba1261bc 37#include "cgroup-util.h"
f5e04665 38
de0229ca 39#define COREDUMP_MAX (24*1024*1024)
f5e04665
LP
40
41enum {
42 ARG_PID = 1,
43 ARG_UID,
44 ARG_GID,
45 ARG_SIGNAL,
46 ARG_TIMESTAMP,
47 ARG_COMM,
48 _ARG_MAX
49};
50
803a3464
LP
51static int divert_coredump(void) {
52 FILE *f;
53 int r;
54
55 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
56
d2e54fae 57 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464
LP
58
59 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
60 if (!f) {
61 log_error("Failed to create coredump file: %m");
62 return -errno;
63 }
64
65 for (;;) {
66 uint8_t buffer[4096];
67 size_t l, q;
68
69 l = fread(buffer, 1, sizeof(buffer), stdin);
70 if (l <= 0) {
71 if (ferror(f)) {
72 log_error("Failed to read coredump: %m");
73 r = -errno;
74 goto finish;
75 }
76
77 r = 0;
78 break;
79 }
80
81 q = fwrite(buffer, 1, l, f);
82 if (q != l) {
83 log_error("Failed to write coredump: %m");
84 r = -errno;
85 goto finish;
86 }
87 }
88
89 fflush(f);
90
91 if (ferror(f)) {
92 log_error("Failed to write coredump: %m");
93 r = -errno;
94 }
95
96finish:
97 fclose(f);
98 return r;
99}
100
f5e04665
LP
101int main(int argc, char* argv[]) {
102 int r, j = 0;
103 char *p = NULL;
104 ssize_t n;
105 pid_t pid;
fee80f69
LP
106 uid_t uid;
107 gid_t gid;
f5e04665
LP
108 struct iovec iovec[14];
109 char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
110 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
111 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t;
112
803a3464 113 prctl(PR_SET_DUMPABLE, 0);
f5e04665
LP
114
115 if (argc != _ARG_MAX) {
803a3464
LP
116 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
117 log_open();
118
f5e04665
LP
119 log_error("Invalid number of arguments passed from kernel.");
120 r = -EINVAL;
121 goto finish;
122 }
123
124 r = parse_pid(argv[ARG_PID], &pid);
125 if (r < 0) {
803a3464
LP
126 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
127 log_open();
128
f5e04665 129 log_error("Failed to parse PID.");
f5e04665
LP
130 goto finish;
131 }
132
ba1261bc 133 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
134
135 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
136 /* Make sure we don't make use of the journal,
137 * if it's the journal which is crashing */
138 log_set_target(LOG_TARGET_KMSG);
139 log_open();
140
141 r = divert_coredump();
142 goto finish;
143 }
144
145 core_unit = strappend("COREDUMP_UNIT=", t);
146 free(t);
f9045468
MT
147 } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
148 core_unit = strappend("COREDUMP_USER_UNIT=", t);
149 free(t);
803a3464
LP
150 }
151
f9045468
MT
152 if (core_unit)
153 IOVEC_SET_STRING(iovec[j++], core_unit);
154
803a3464
LP
155 /* OK, now we know it's not the journal, hence make use of
156 * it */
157 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
158 log_open();
159
fee80f69
LP
160 r = parse_uid(argv[ARG_UID], &uid);
161 if (r < 0) {
162 log_error("Failed to parse UID.");
f5e04665
LP
163 goto finish;
164 }
165
fee80f69
LP
166 r = parse_gid(argv[ARG_GID], &gid);
167 if (r < 0) {
168 log_error("Failed to parse GID.");
f5e04665
LP
169 goto finish;
170 }
171
f5e04665
LP
172 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
173 if (core_pid)
174 IOVEC_SET_STRING(iovec[j++], core_pid);
175
176 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
177 if (core_uid)
178 IOVEC_SET_STRING(iovec[j++], core_uid);
179
180 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
181 if (core_gid)
182 IOVEC_SET_STRING(iovec[j++], core_gid);
183
184 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
185 if (core_signal)
186 IOVEC_SET_STRING(iovec[j++], core_signal);
187
188 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
189 if (core_comm)
190 IOVEC_SET_STRING(iovec[j++], core_comm);
191
ba1261bc 192#ifdef HAVE_LOGIND
f5e04665
LP
193 if (sd_pid_get_session(pid, &t) >= 0) {
194 core_session = strappend("COREDUMP_SESSION=", t);
195 free(t);
196
197 if (core_session)
198 IOVEC_SET_STRING(iovec[j++], core_session);
199 }
200
ba1261bc
LP
201#endif
202
f5e04665
LP
203 if (get_process_exe(pid, &t) >= 0) {
204 core_exe = strappend("COREDUMP_EXE=", t);
205 free(t);
206
207 if (core_exe)
208 IOVEC_SET_STRING(iovec[j++], core_exe);
209 }
210
9bdbc2e2 211 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
212 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
213 free(t);
214
215 if (core_cmdline)
216 IOVEC_SET_STRING(iovec[j++], core_cmdline);
217 }
218
b7def684 219 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
f5e04665
LP
220 if (core_timestamp)
221 IOVEC_SET_STRING(iovec[j++], core_timestamp);
222
223 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
224 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
225
b7def684 226 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
f5e04665
LP
227 if (core_message)
228 IOVEC_SET_STRING(iovec[j++], core_message);
229
fee80f69
LP
230 /* Now, let's drop privileges to become the user who owns the
231 * segfaulted process and allocate the coredump memory under
232 * his uid. This also ensures that the credentials journald
233 * will see are the ones of the coredumping user, thus making
234 * sure the user himself gets access to the core dump. */
235
236 if (setresgid(gid, gid, gid) < 0 ||
237 setresuid(uid, uid, uid) < 0) {
238 log_error("Failed to drop privileges: %m");
239 r = -errno;
240 goto finish;
241 }
242
243 p = malloc(9 + COREDUMP_MAX);
244 if (!p) {
0d0f0c50 245 r = log_oom();
fee80f69
LP
246 goto finish;
247 }
248
249 memcpy(p, "COREDUMP=", 9);
250
251 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
252 if (n < 0) {
253 log_error("Failed to read core dump data: %s", strerror(-n));
254 r = (int) n;
255 goto finish;
256 }
257
258 iovec[j].iov_base = p;
259 iovec[j].iov_len = 9 + n;
260 j++;
261
f5e04665
LP
262 r = sd_journal_sendv(iovec, j);
263 if (r < 0)
264 log_error("Failed to send coredump: %s", strerror(-r));
265
266finish:
267 free(p);
268 free(core_pid);
269 free(core_uid);
270 free(core_gid);
271 free(core_signal);
272 free(core_timestamp);
273 free(core_comm);
274 free(core_exe);
275 free(core_cmdline);
276 free(core_unit);
277 free(core_session);
278 free(core_message);
279
280 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
281}