]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journal-send.c
bus: update bloom filter description a bit
[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;
9058851b
LP
219 /* We use /dev/shm instead of /tmp here, since we want this to
220 * be a tmpfs, and one that is available from early boot on
221 * and where unprivileged users can create files. */
222 char path[] = "/dev/shm/journal.XXXXXX";
ee55db41 223 bool have_syslog_identifier = false;
7f3e6257 224
1ae464e0
TA
225 assert_return(iov, -EINVAL);
226 assert_return(n > 0, -EINVAL);
7f3e6257 227
ee55db41 228 w = alloca(sizeof(struct iovec) * n * 5 + 3);
7f3e6257
LP
229 l = alloca(sizeof(uint64_t) * n);
230
231 for (i = 0; i < n; i++) {
232 char *c, *nl;
233
5c0aa72a
LP
234 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
235 return -EINVAL;
a5344d2c 236
7f3e6257 237 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
5c0aa72a
LP
238 if (_unlikely_(!c || c == iov[i].iov_base))
239 return -EINVAL;
7f3e6257 240
29abad10
ZJS
241 have_syslog_identifier = have_syslog_identifier ||
242 (c == (char *) iov[i].iov_base + 17 &&
2a0e0692 243 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
ee55db41 244
7f3e6257
LP
245 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
246 if (nl) {
5c0aa72a
LP
247 if (_unlikely_(nl < c))
248 return -EINVAL;
7f3e6257
LP
249
250 /* Already includes a newline? Bummer, then
251 * let's write the variable name, then a
252 * newline, then the size (64bit LE), followed
253 * by the data and a final newline */
254
255 w[j].iov_base = iov[i].iov_base;
256 w[j].iov_len = c - (char*) iov[i].iov_base;
257 j++;
258
259 IOVEC_SET_STRING(w[j++], "\n");
260
261 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
262 w[j].iov_base = &l[i];
263 w[j].iov_len = sizeof(uint64_t);
264 j++;
265
266 w[j].iov_base = c + 1;
267 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
268 j++;
269
270 } else
271 /* Nothing special? Then just add the line and
272 * append a newline */
273 w[j++] = iov[i];
274
275 IOVEC_SET_STRING(w[j++], "\n");
276 }
277
ee55db41
LP
278 if (!have_syslog_identifier &&
279 string_is_safe(program_invocation_short_name)) {
280
281 /* Implicitly add program_invocation_short_name, if it
282 * is not set explicitly. We only do this for
283 * program_invocation_short_name, and nothing else
284 * since everything else is much nicer to retrieve
285 * from the outside. */
286
287 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
288 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
289 IOVEC_SET_STRING(w[j++], "\n");
290 }
291
7f3e6257 292 fd = journal_fd();
5c0aa72a
LP
293 if (_unlikely_(fd < 0))
294 return fd;
7f3e6257 295
7f3e6257
LP
296 mh.msg_iov = w;
297 mh.msg_iovlen = j;
298
0dad12c1 299 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
5c0aa72a
LP
300 if (k >= 0)
301 return 0;
0dad12c1 302
6c045c0b
ZJS
303 /* Fail silently if the journal is not available */
304 if (errno == ENOENT)
305 return 0;
306
5c0aa72a
LP
307 if (errno != EMSGSIZE && errno != ENOBUFS)
308 return -errno;
0dad12c1
LP
309
310 /* Message doesn't fit... Let's dump the data in a temporary
311 * file and just pass a file descriptor of it to the other
312 * side */
313
314 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
5c0aa72a
LP
315 if (buffer_fd < 0)
316 return -errno;
0dad12c1
LP
317
318 if (unlink(path) < 0) {
319 close_nointr_nofail(buffer_fd);
5c0aa72a 320 return -errno;
0dad12c1
LP
321 }
322
323 n = writev(buffer_fd, w, j);
b070e7f3 324 if (n < 0) {
0dad12c1 325 close_nointr_nofail(buffer_fd);
5c0aa72a 326 return -errno;
0dad12c1
LP
327 }
328
329 mh.msg_iov = NULL;
330 mh.msg_iovlen = 0;
331
332 zero(control);
333 mh.msg_control = &control;
334 mh.msg_controllen = sizeof(control);
335
336 cmsg = CMSG_FIRSTHDR(&mh);
337 cmsg->cmsg_level = SOL_SOCKET;
338 cmsg->cmsg_type = SCM_RIGHTS;
339 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
340 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
341
342 mh.msg_controllen = cmsg->cmsg_len;
343
344 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
345 close_nointr_nofail(buffer_fd);
346
5c0aa72a
LP
347 if (k < 0)
348 return -errno;
7f3e6257 349
5c0aa72a 350 return 0;
7f3e6257 351}
fe652127 352
18c7ed18 353static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
5c0aa72a
LP
354 PROTECT_ERRNO;
355 size_t n, k;
18c7ed18
LP
356
357 k = isempty(message) ? 0 : strlen(message) + 2;
358 n = 8 + k + 256 + 1;
359
360 for (;;) {
361 char buffer[n];
362 char* j;
363
364 errno = 0;
5c0aa72a 365 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
18c7ed18
LP
366 if (errno == 0) {
367 char error[6 + 10 + 1]; /* for a 32bit value */
368
369 if (j != buffer + 8 + k)
370 memmove(buffer + 8 + k, j, strlen(j)+1);
371
372 memcpy(buffer, "MESSAGE=", 8);
373
374 if (k > 0) {
375 memcpy(buffer + 8, message, k - 2);
376 memcpy(buffer + 8 + k - 2, ": ", 2);
377 }
378
5c0aa72a 379 snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
18c7ed18
LP
380 char_array_0(error);
381
382 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
383 IOVEC_SET_STRING(iov[skip+1], buffer);
384 IOVEC_SET_STRING(iov[skip+2], error);
385
5c0aa72a 386 return sd_journal_sendv(iov, skip + 3);
18c7ed18
LP
387 }
388
5c0aa72a
LP
389 if (errno != ERANGE)
390 return -errno;
18c7ed18
LP
391
392 n *= 2;
393 }
394}
395
396_public_ int sd_journal_perror(const char *message) {
397 struct iovec iovec[3];
398
399 return fill_iovec_perror_and_send(message, 0, iovec);
400}
401
4cd9a9d9 402_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
6e5abe15
ZJS
403 union sockaddr_union sa = {
404 .un.sun_family = AF_UNIX,
405 .un.sun_path = "/run/systemd/journal/stdout",
406 };
fe652127
LP
407 int fd;
408 char *header;
409 size_t l;
410 ssize_t r;
411
1ae464e0
TA
412 assert_return(priority >= 0, -EINVAL);
413 assert_return(priority <= 7, -EINVAL);
fe652127
LP
414
415 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
416 if (fd < 0)
417 return -errno;
418
fe652127
LP
419 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
420 if (r < 0) {
421 close_nointr_nofail(fd);
422 return -errno;
423 }
424
86b9b8e7
LP
425 if (shutdown(fd, SHUT_RD) < 0) {
426 close_nointr_nofail(fd);
427 return -errno;
428 }
429
bb99a35a
LP
430 fd_inc_sndbuf(fd, SNDBUF_SIZE);
431
4cd9a9d9
LP
432 if (!identifier)
433 identifier = "";
fe652127 434
4cd9a9d9 435 l = strlen(identifier);
8b38f3cc 436 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
fe652127 437
4cd9a9d9 438 memcpy(header, identifier, l);
fe652127 439 header[l++] = '\n';
a6e87e90 440 header[l++] = '\n'; /* unit id */
fe652127
LP
441 header[l++] = '0' + priority;
442 header[l++] = '\n';
4cd9a9d9 443 header[l++] = '0' + !!level_prefix;
fe652127
LP
444 header[l++] = '\n';
445 header[l++] = '0';
446 header[l++] = '\n';
224f2ee2
LP
447 header[l++] = '0';
448 header[l++] = '\n';
449 header[l++] = '0';
450 header[l++] = '\n';
fe652127
LP
451
452 r = loop_write(fd, header, l, false);
453 if (r < 0) {
454 close_nointr_nofail(fd);
455 return (int) r;
456 }
457
458 if ((size_t) r != l) {
459 close_nointr_nofail(fd);
460 return -errno;
461 }
462
463 return fd;
464}
b070e7f3
LP
465
466_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
467 int r;
468 va_list ap;
469
470 va_start(ap, format);
471 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
472 va_end(ap);
473
474 return r;
475}
476
477_public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
478 char buffer[8 + LINE_MAX], p[11];
479 struct iovec iov[5];
480 char *f;
b070e7f3 481
1ae464e0
TA
482 assert_return(priority >= 0, -EINVAL);
483 assert_return(priority <= 7, -EINVAL);
484 assert_return(format, -EINVAL);
b070e7f3
LP
485
486 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
487 char_array_0(p);
488
489 memcpy(buffer, "MESSAGE=", 8);
490 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
491 char_array_0(buffer);
492
493 /* func is initialized from __func__ which is not a macro, but
494 * a static const char[], hence cannot easily be prefixed with
495 * CODE_FUNC=, hence let's do it manually here. */
3ed08c44 496 ALLOCA_CODE_FUNC(f, func);
b070e7f3
LP
497
498 zero(iov);
499 IOVEC_SET_STRING(iov[0], buffer);
500 IOVEC_SET_STRING(iov[1], p);
501 IOVEC_SET_STRING(iov[2], file);
502 IOVEC_SET_STRING(iov[3], line);
503 IOVEC_SET_STRING(iov[4], f);
504
505 return sd_journal_sendv(iov, ELEMENTSOF(iov));
506}
507
508_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
509 int r, i, j;
510 va_list ap;
511 struct iovec *iov = NULL;
512 char *f;
b070e7f3
LP
513
514 va_start(ap, format);
515 i = fill_iovec_sprintf(format, ap, 3, &iov);
516 va_end(ap);
517
518 if (_unlikely_(i < 0)) {
519 r = i;
520 goto finish;
521 }
522
3ed08c44 523 ALLOCA_CODE_FUNC(f, func);
b070e7f3
LP
524
525 IOVEC_SET_STRING(iov[0], file);
526 IOVEC_SET_STRING(iov[1], line);
527 IOVEC_SET_STRING(iov[2], f);
528
529 r = sd_journal_sendv(iov, i);
530
531finish:
532 for (j = 3; j < i; j++)
533 free(iov[j].iov_base);
534
535 free(iov);
536
537 return r;
538}
539
18c7ed18
LP
540_public_ int sd_journal_sendv_with_location(
541 const char *file, const char *line,
542 const char *func,
543 const struct iovec *iov, int n) {
544
b070e7f3
LP
545 struct iovec *niov;
546 char *f;
b070e7f3 547
1ae464e0
TA
548 assert_return(iov, -EINVAL);
549 assert_return(n > 0, -EINVAL);
b070e7f3
LP
550
551 niov = alloca(sizeof(struct iovec) * (n + 3));
552 memcpy(niov, iov, sizeof(struct iovec) * n);
553
3ed08c44 554 ALLOCA_CODE_FUNC(f, func);
b070e7f3
LP
555
556 IOVEC_SET_STRING(niov[n++], file);
557 IOVEC_SET_STRING(niov[n++], line);
558 IOVEC_SET_STRING(niov[n++], f);
559
560 return sd_journal_sendv(niov, n);
561}
18c7ed18
LP
562
563_public_ int sd_journal_perror_with_location(
564 const char *file, const char *line,
565 const char *func,
566 const char *message) {
567
568 struct iovec iov[6];
18c7ed18
LP
569 char *f;
570
3ed08c44 571 ALLOCA_CODE_FUNC(f, func);
18c7ed18
LP
572
573 IOVEC_SET_STRING(iov[0], file);
574 IOVEC_SET_STRING(iov[1], line);
575 IOVEC_SET_STRING(iov[2], f);
576
577 return fill_iovec_perror_and_send(message, 3, iov);
578}