]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journal-send.c
journal: guarantee async-signal-safety in sd_journald_sendv
[thirdparty/systemd.git] / src / journal / journal-send.c
CommitLineData
7f3e6257
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 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
7f3e6257
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.
7f3e6257 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
7f3e6257
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <errno.h>
25#include <stddef.h>
0dad12c1
LP
26#include <unistd.h>
27#include <fcntl.h>
72f1d5a2 28#include <printf.h>
7f3e6257 29
b070e7f3
LP
30#define SD_JOURNAL_SUPPRESS_LOCATION
31
7f3e6257
LP
32#include "sd-journal.h"
33#include "util.h"
fe652127 34#include "socket-util.h"
7f3e6257 35
bb99a35a
LP
36#define SNDBUF_SIZE (8*1024*1024)
37
3ed08c44
LP
38#define ALLOCA_CODE_FUNC(f, func) \
39 do { \
40 size_t _fl; \
41 const char *_func = (func); \
42 char **_f = &(f); \
43 _fl = strlen(_func) + 1; \
44 *_f = alloca(_fl + 10); \
45 memcpy(*_f, "CODE_FUNC=", 10); \
46 memcpy(*_f + 10, _func, _fl); \
47 } while(false)
48
7f3e6257
LP
49/* We open a single fd, and we'll share it with the current process,
50 * all its threads, and all its subprocesses. This means we need to
51 * initialize it atomically, and need to operate on it atomically
52 * never assuming we are the only user */
53
54static int journal_fd(void) {
55 int fd;
56 static int fd_plus_one = 0;
57
58retry:
59 if (fd_plus_one > 0)
60 return fd_plus_one - 1;
61
62 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
63 if (fd < 0)
64 return -errno;
65
bb99a35a
LP
66 fd_inc_sndbuf(fd, SNDBUF_SIZE);
67
7f3e6257
LP
68 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
69 close_nointr_nofail(fd);
70 goto retry;
71 }
72
73 return fd;
74}
75
a5344d2c 76_public_ int sd_journal_print(int priority, const char *format, ...) {
7f3e6257
LP
77 int r;
78 va_list ap;
79
80 va_start(ap, format);
d0bbc21c 81 r = sd_journal_printv(priority, format, ap);
7f3e6257
LP
82 va_end(ap);
83
84 return r;
85}
86
a5344d2c 87_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
18c7ed18
LP
88
89 /* FIXME: Instead of limiting things to LINE_MAX we could do a
90 C99 variable-length array on the stack here in a loop. */
91
92 char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
d0bbc21c 93
1ae464e0
TA
94 assert_return(priority >= 0, -EINVAL);
95 assert_return(priority <= 7, -EINVAL);
96 assert_return(format, -EINVAL);
fe652127 97
d0bbc21c
LP
98 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
99 char_array_0(p);
7f3e6257
LP
100
101 memcpy(buffer, "MESSAGE=", 8);
102 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
7f3e6257
LP
103 char_array_0(buffer);
104
105 zero(iov);
d0bbc21c
LP
106 IOVEC_SET_STRING(iov[0], buffer);
107 IOVEC_SET_STRING(iov[1], p);
7f3e6257 108
d0bbc21c 109 return sd_journal_sendv(iov, 2);
7f3e6257
LP
110}
111
44b601bc 112_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
5c0aa72a 113 PROTECT_ERRNO;
25d042e8 114 int r, n = 0, i = 0, j;
7f3e6257 115 struct iovec *iov = NULL;
b070e7f3
LP
116
117 assert(_iov);
b070e7f3
LP
118
119 if (extra > 0) {
120 n = MAX(extra * 2, extra + 4);
121 iov = malloc0(n * sizeof(struct iovec));
122 if (!iov) {
123 r = -ENOMEM;
124 goto fail;
125 }
126
127 i = extra;
25d042e8 128 }
7f3e6257 129
7f3e6257
LP
130 while (format) {
131 struct iovec *c;
132 char *buffer;
72f1d5a2 133 va_list aq;
7f3e6257
LP
134
135 if (i >= n) {
136 n = MAX(i*2, 4);
137 c = realloc(iov, n * sizeof(struct iovec));
138 if (!c) {
139 r = -ENOMEM;
140 goto fail;
141 }
142
143 iov = c;
144 }
145
72f1d5a2
LP
146 va_copy(aq, ap);
147 if (vasprintf(&buffer, format, aq) < 0) {
148 va_end(aq);
7f3e6257
LP
149 r = -ENOMEM;
150 goto fail;
151 }
72f1d5a2
LP
152 va_end(aq);
153
154 VA_FORMAT_ADVANCE(format, ap);
7f3e6257
LP
155
156 IOVEC_SET_STRING(iov[i++], buffer);
157
158 format = va_arg(ap, char *);
159 }
b070e7f3
LP
160
161 *_iov = iov;
162
b070e7f3
LP
163 return i;
164
165fail:
166 for (j = 0; j < i; j++)
167 free(iov[j].iov_base);
168
169 free(iov);
170
b070e7f3
LP
171 return r;
172}
173
174_public_ int sd_journal_send(const char *format, ...) {
175 int r, i, j;
176 va_list ap;
177 struct iovec *iov = NULL;
178
179 va_start(ap, format);
180 i = fill_iovec_sprintf(format, ap, 0, &iov);
7f3e6257
LP
181 va_end(ap);
182
b070e7f3
LP
183 if (_unlikely_(i < 0)) {
184 r = i;
185 goto finish;
186 }
187
7f3e6257
LP
188 r = sd_journal_sendv(iov, i);
189
b070e7f3 190finish:
7f3e6257
LP
191 for (j = 0; j < i; j++)
192 free(iov[j].iov_base);
193
194 free(iov);
195
196 return r;
197}
198
a5344d2c 199_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
5c0aa72a 200 PROTECT_ERRNO;
0dad12c1 201 int fd, buffer_fd;
7f3e6257
LP
202 struct iovec *w;
203 uint64_t *l;
5c0aa72a 204 int i, j = 0;
6e5abe15
ZJS
205 struct sockaddr_un sa = {
206 .sun_family = AF_UNIX,
207 .sun_path = "/run/systemd/journal/socket",
208 };
209 struct msghdr mh = {
210 .msg_name = &sa,
211 .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
212 };
0dad12c1
LP
213 ssize_t k;
214 union {
215 struct cmsghdr cmsghdr;
216 uint8_t buf[CMSG_SPACE(sizeof(int))];
217 } control;
218 struct cmsghdr *cmsg;
ee55db41 219 bool have_syslog_identifier = false;
7f3e6257 220
1ae464e0
TA
221 assert_return(iov, -EINVAL);
222 assert_return(n > 0, -EINVAL);
7f3e6257 223
ee55db41 224 w = alloca(sizeof(struct iovec) * n * 5 + 3);
7f3e6257
LP
225 l = alloca(sizeof(uint64_t) * n);
226
227 for (i = 0; i < n; i++) {
228 char *c, *nl;
229
5c0aa72a
LP
230 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
231 return -EINVAL;
a5344d2c 232
7f3e6257 233 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
5c0aa72a
LP
234 if (_unlikely_(!c || c == iov[i].iov_base))
235 return -EINVAL;
7f3e6257 236
29abad10
ZJS
237 have_syslog_identifier = have_syslog_identifier ||
238 (c == (char *) iov[i].iov_base + 17 &&
2a0e0692 239 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
ee55db41 240
7f3e6257
LP
241 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
242 if (nl) {
5c0aa72a
LP
243 if (_unlikely_(nl < c))
244 return -EINVAL;
7f3e6257
LP
245
246 /* Already includes a newline? Bummer, then
247 * let's write the variable name, then a
248 * newline, then the size (64bit LE), followed
249 * by the data and a final newline */
250
251 w[j].iov_base = iov[i].iov_base;
252 w[j].iov_len = c - (char*) iov[i].iov_base;
253 j++;
254
255 IOVEC_SET_STRING(w[j++], "\n");
256
257 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
258 w[j].iov_base = &l[i];
259 w[j].iov_len = sizeof(uint64_t);
260 j++;
261
262 w[j].iov_base = c + 1;
263 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
264 j++;
265
266 } else
267 /* Nothing special? Then just add the line and
268 * append a newline */
269 w[j++] = iov[i];
270
271 IOVEC_SET_STRING(w[j++], "\n");
272 }
273
ee55db41
LP
274 if (!have_syslog_identifier &&
275 string_is_safe(program_invocation_short_name)) {
276
277 /* Implicitly add program_invocation_short_name, if it
278 * is not set explicitly. We only do this for
279 * program_invocation_short_name, and nothing else
280 * since everything else is much nicer to retrieve
281 * from the outside. */
282
283 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
284 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
285 IOVEC_SET_STRING(w[j++], "\n");
286 }
287
7f3e6257 288 fd = journal_fd();
5c0aa72a
LP
289 if (_unlikely_(fd < 0))
290 return fd;
7f3e6257 291
7f3e6257
LP
292 mh.msg_iov = w;
293 mh.msg_iovlen = j;
294
0dad12c1 295 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
5c0aa72a
LP
296 if (k >= 0)
297 return 0;
0dad12c1 298
6c045c0b
ZJS
299 /* Fail silently if the journal is not available */
300 if (errno == ENOENT)
301 return 0;
302
5c0aa72a
LP
303 if (errno != EMSGSIZE && errno != ENOBUFS)
304 return -errno;
0dad12c1
LP
305
306 /* Message doesn't fit... Let's dump the data in a temporary
307 * file and just pass a file descriptor of it to the other
8e33886e
ZJS
308 * side.
309 *
310 * We use /dev/shm instead of /tmp here, since we want this to
311 * be a tmpfs, and one that is available from early boot on
312 * and where unprivileged users can create files. */
313 buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
5c0aa72a 314 if (buffer_fd < 0)
8e33886e 315 return buffer_fd;
0dad12c1 316
65b3903f 317 n = writev_safe(buffer_fd, w, j);
b070e7f3 318 if (n < 0) {
0dad12c1 319 close_nointr_nofail(buffer_fd);
5c0aa72a 320 return -errno;
0dad12c1
LP
321 }
322
323 mh.msg_iov = NULL;
324 mh.msg_iovlen = 0;
325
326 zero(control);
327 mh.msg_control = &control;
328 mh.msg_controllen = sizeof(control);
329
330 cmsg = CMSG_FIRSTHDR(&mh);
331 cmsg->cmsg_level = SOL_SOCKET;
332 cmsg->cmsg_type = SCM_RIGHTS;
333 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
334 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
335
336 mh.msg_controllen = cmsg->cmsg_len;
337
338 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
339 close_nointr_nofail(buffer_fd);
340
5c0aa72a
LP
341 if (k < 0)
342 return -errno;
7f3e6257 343
5c0aa72a 344 return 0;
7f3e6257 345}
fe652127 346
18c7ed18 347static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
5c0aa72a
LP
348 PROTECT_ERRNO;
349 size_t n, k;
18c7ed18
LP
350
351 k = isempty(message) ? 0 : strlen(message) + 2;
352 n = 8 + k + 256 + 1;
353
354 for (;;) {
355 char buffer[n];
356 char* j;
357
358 errno = 0;
5c0aa72a 359 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
18c7ed18
LP
360 if (errno == 0) {
361 char error[6 + 10 + 1]; /* for a 32bit value */
362
363 if (j != buffer + 8 + k)
364 memmove(buffer + 8 + k, j, strlen(j)+1);
365
366 memcpy(buffer, "MESSAGE=", 8);
367
368 if (k > 0) {
369 memcpy(buffer + 8, message, k - 2);
370 memcpy(buffer + 8 + k - 2, ": ", 2);
371 }
372
5c0aa72a 373 snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
18c7ed18
LP
374 char_array_0(error);
375
376 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
377 IOVEC_SET_STRING(iov[skip+1], buffer);
378 IOVEC_SET_STRING(iov[skip+2], error);
379
5c0aa72a 380 return sd_journal_sendv(iov, skip + 3);
18c7ed18
LP
381 }
382
5c0aa72a
LP
383 if (errno != ERANGE)
384 return -errno;
18c7ed18
LP
385
386 n *= 2;
387 }
388}
389
390_public_ int sd_journal_perror(const char *message) {
391 struct iovec iovec[3];
392
393 return fill_iovec_perror_and_send(message, 0, iovec);
394}
395
4cd9a9d9 396_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
6e5abe15
ZJS
397 union sockaddr_union sa = {
398 .un.sun_family = AF_UNIX,
399 .un.sun_path = "/run/systemd/journal/stdout",
400 };
fe652127
LP
401 int fd;
402 char *header;
403 size_t l;
404 ssize_t r;
405
1ae464e0
TA
406 assert_return(priority >= 0, -EINVAL);
407 assert_return(priority <= 7, -EINVAL);
fe652127
LP
408
409 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
410 if (fd < 0)
411 return -errno;
412
fe652127
LP
413 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
414 if (r < 0) {
415 close_nointr_nofail(fd);
416 return -errno;
417 }
418
86b9b8e7
LP
419 if (shutdown(fd, SHUT_RD) < 0) {
420 close_nointr_nofail(fd);
421 return -errno;
422 }
423
bb99a35a
LP
424 fd_inc_sndbuf(fd, SNDBUF_SIZE);
425
4cd9a9d9
LP
426 if (!identifier)
427 identifier = "";
fe652127 428
4cd9a9d9 429 l = strlen(identifier);
8b38f3cc 430 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
fe652127 431
4cd9a9d9 432 memcpy(header, identifier, l);
fe652127 433 header[l++] = '\n';
a6e87e90 434 header[l++] = '\n'; /* unit id */
fe652127
LP
435 header[l++] = '0' + priority;
436 header[l++] = '\n';
4cd9a9d9 437 header[l++] = '0' + !!level_prefix;
fe652127
LP
438 header[l++] = '\n';
439 header[l++] = '0';
440 header[l++] = '\n';
224f2ee2
LP
441 header[l++] = '0';
442 header[l++] = '\n';
443 header[l++] = '0';
444 header[l++] = '\n';
fe652127
LP
445
446 r = loop_write(fd, header, l, false);
447 if (r < 0) {
448 close_nointr_nofail(fd);
449 return (int) r;
450 }
451
452 if ((size_t) r != l) {
453 close_nointr_nofail(fd);
454 return -errno;
455 }
456
457 return fd;
458}
b070e7f3
LP
459
460_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
461 int r;
462 va_list ap;
463
464 va_start(ap, format);
465 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
466 va_end(ap);
467
468 return r;
469}
470
471_public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
472 char buffer[8 + LINE_MAX], p[11];
473 struct iovec iov[5];
474 char *f;
b070e7f3 475
1ae464e0
TA
476 assert_return(priority >= 0, -EINVAL);
477 assert_return(priority <= 7, -EINVAL);
478 assert_return(format, -EINVAL);
b070e7f3
LP
479
480 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
481 char_array_0(p);
482
483 memcpy(buffer, "MESSAGE=", 8);
484 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
485 char_array_0(buffer);
486
487 /* func is initialized from __func__ which is not a macro, but
488 * a static const char[], hence cannot easily be prefixed with
489 * CODE_FUNC=, hence let's do it manually here. */
3ed08c44 490 ALLOCA_CODE_FUNC(f, func);
b070e7f3
LP
491
492 zero(iov);
493 IOVEC_SET_STRING(iov[0], buffer);
494 IOVEC_SET_STRING(iov[1], p);
495 IOVEC_SET_STRING(iov[2], file);
496 IOVEC_SET_STRING(iov[3], line);
497 IOVEC_SET_STRING(iov[4], f);
498
499 return sd_journal_sendv(iov, ELEMENTSOF(iov));
500}
501
502_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
503 int r, i, j;
504 va_list ap;
505 struct iovec *iov = NULL;
506 char *f;
b070e7f3
LP
507
508 va_start(ap, format);
509 i = fill_iovec_sprintf(format, ap, 3, &iov);
510 va_end(ap);
511
512 if (_unlikely_(i < 0)) {
513 r = i;
514 goto finish;
515 }
516
3ed08c44 517 ALLOCA_CODE_FUNC(f, func);
b070e7f3
LP
518
519 IOVEC_SET_STRING(iov[0], file);
520 IOVEC_SET_STRING(iov[1], line);
521 IOVEC_SET_STRING(iov[2], f);
522
523 r = sd_journal_sendv(iov, i);
524
525finish:
526 for (j = 3; j < i; j++)
527 free(iov[j].iov_base);
528
529 free(iov);
530
531 return r;
532}
533
18c7ed18
LP
534_public_ int sd_journal_sendv_with_location(
535 const char *file, const char *line,
536 const char *func,
537 const struct iovec *iov, int n) {
538
b070e7f3
LP
539 struct iovec *niov;
540 char *f;
b070e7f3 541
1ae464e0
TA
542 assert_return(iov, -EINVAL);
543 assert_return(n > 0, -EINVAL);
b070e7f3
LP
544
545 niov = alloca(sizeof(struct iovec) * (n + 3));
546 memcpy(niov, iov, sizeof(struct iovec) * n);
547
3ed08c44 548 ALLOCA_CODE_FUNC(f, func);
b070e7f3
LP
549
550 IOVEC_SET_STRING(niov[n++], file);
551 IOVEC_SET_STRING(niov[n++], line);
552 IOVEC_SET_STRING(niov[n++], f);
553
554 return sd_journal_sendv(niov, n);
555}
18c7ed18
LP
556
557_public_ int sd_journal_perror_with_location(
558 const char *file, const char *line,
559 const char *func,
560 const char *message) {
561
562 struct iovec iov[6];
18c7ed18
LP
563 char *f;
564
3ed08c44 565 ALLOCA_CODE_FUNC(f, func);
18c7ed18
LP
566
567 IOVEC_SET_STRING(iov[0], file);
568 IOVEC_SET_STRING(iov[1], line);
569 IOVEC_SET_STRING(iov[2], f);
570
571 return fill_iovec_perror_and_send(message, 3, iov);
572}