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