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