]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journal-send.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / journal / journal-send.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
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
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
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <printf.h>
24 #include <stddef.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <unistd.h>
28
29 #define SD_JOURNAL_SUPPRESS_LOCATION
30
31 #include "sd-journal.h"
32
33 #include "alloc-util.h"
34 #include "fd-util.h"
35 #include "fileio.h"
36 #include "io-util.h"
37 #include "memfd-util.h"
38 #include "socket-util.h"
39 #include "stdio-util.h"
40 #include "string-util.h"
41 #include "util.h"
42
43 #define SNDBUF_SIZE (8*1024*1024)
44
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); \
54 } while (false)
55
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
61 static int journal_fd(void) {
62 int fd;
63 static int fd_plus_one = 0;
64
65 retry:
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
73 fd_inc_sndbuf(fd, SNDBUF_SIZE);
74
75 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
76 safe_close(fd);
77 goto retry;
78 }
79
80 return fd;
81 }
82
83 _public_ int sd_journal_print(int priority, const char *format, ...) {
84 int r;
85 va_list ap;
86
87 va_start(ap, format);
88 r = sd_journal_printv(priority, format, ap);
89 va_end(ap);
90
91 return r;
92 }
93
94 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
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
99 char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
100 struct iovec iov[2];
101
102 assert_return(priority >= 0, -EINVAL);
103 assert_return(priority <= 7, -EINVAL);
104 assert_return(format, -EINVAL);
105
106 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
107
108 memcpy(buffer, "MESSAGE=", 8);
109 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
110
111 /* Strip trailing whitespace, keep prefix whitespace. */
112 (void) strstrip(buffer);
113
114 /* Suppress empty lines */
115 if (isempty(buffer+8))
116 return 0;
117
118 iov[0] = IOVEC_MAKE_STRING(buffer);
119 iov[1] = IOVEC_MAKE_STRING(p);
120
121 return sd_journal_sendv(iov, 2);
122 }
123
124 _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
125 PROTECT_ERRNO;
126 int r, n = 0, i = 0, j;
127 struct iovec *iov = NULL;
128
129 assert(_iov);
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;
140 }
141
142 while (format) {
143 struct iovec *c;
144 char *buffer;
145 va_list aq;
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
158 va_copy(aq, ap);
159 if (vasprintf(&buffer, format, aq) < 0) {
160 va_end(aq);
161 r = -ENOMEM;
162 goto fail;
163 }
164 va_end(aq);
165
166 VA_FORMAT_ADVANCE(format, ap);
167
168 (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */
169
170 iov[i++] = IOVEC_MAKE_STRING(buffer);
171
172 format = va_arg(ap, char *);
173 }
174
175 *_iov = iov;
176
177 return i;
178
179 fail:
180 for (j = 0; j < i; j++)
181 free(iov[j].iov_base);
182
183 free(iov);
184
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);
195 va_end(ap);
196
197 if (_unlikely_(i < 0)) {
198 r = i;
199 goto finish;
200 }
201
202 r = sd_journal_sendv(iov, i);
203
204 finish:
205 for (j = 0; j < i; j++)
206 free(iov[j].iov_base);
207
208 free(iov);
209
210 return r;
211 }
212
213 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
214 PROTECT_ERRNO;
215 int fd, r;
216 _cleanup_close_ int buffer_fd = -1;
217 struct iovec *w;
218 uint64_t *l;
219 int i, j = 0;
220 static const union sockaddr_union sa = {
221 .un.sun_family = AF_UNIX,
222 .un.sun_path = "/run/systemd/journal/socket",
223 };
224 struct msghdr mh = {
225 .msg_name = (struct sockaddr*) &sa.sa,
226 .msg_namelen = SOCKADDR_UN_LEN(sa.un),
227 };
228 ssize_t k;
229 bool have_syslog_identifier = false;
230 bool seal = true;
231
232 assert_return(iov, -EINVAL);
233 assert_return(n > 0, -EINVAL);
234
235 w = newa(struct iovec, n * 5 + 3);
236 l = newa(uint64_t, n);
237
238 for (i = 0; i < n; i++) {
239 char *c, *nl;
240
241 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
242 return -EINVAL;
243
244 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
245 if (_unlikely_(!c || c == iov[i].iov_base))
246 return -EINVAL;
247
248 have_syslog_identifier = have_syslog_identifier ||
249 (c == (char *) iov[i].iov_base + 17 &&
250 startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
251
252 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
253 if (nl) {
254 if (_unlikely_(nl < c))
255 return -EINVAL;
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
262 w[j++] = IOVEC_MAKE(iov[i].iov_base, c - (char*) iov[i].iov_base);
263 w[j++] = IOVEC_MAKE_STRING("\n");
264
265 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
266 w[j++] = IOVEC_MAKE(&l[i], sizeof(uint64_t));
267
268 w[j++] = IOVEC_MAKE(c + 1, iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
269 } else
270 /* Nothing special? Then just add the line and
271 * append a newline */
272 w[j++] = iov[i];
273
274 w[j++] = IOVEC_MAKE_STRING("\n");
275 }
276
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
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");
289 }
290
291 fd = journal_fd();
292 if (_unlikely_(fd < 0))
293 return fd;
294
295 mh.msg_iov = w;
296 mh.msg_iovlen = j;
297
298 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
299 if (k >= 0)
300 return 0;
301
302 /* Fail silently if the journal is not available */
303 if (errno == ENOENT)
304 return 0;
305
306 if (!IN_SET(errno, EMSGSIZE, ENOBUFS))
307 return -errno;
308
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.
312 *
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. */
317 buffer_fd = memfd_new(NULL);
318 if (buffer_fd < 0) {
319 if (buffer_fd == -ENOSYS) {
320 buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC);
321 if (buffer_fd < 0)
322 return buffer_fd;
323
324 seal = false;
325 } else
326 return buffer_fd;
327 }
328
329 n = writev(buffer_fd, w, j);
330 if (n < 0)
331 return -errno;
332
333 if (seal) {
334 r = memfd_set_sealed(buffer_fd);
335 if (r < 0)
336 return r;
337 }
338
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;
344 }
345
346 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
347 PROTECT_ERRNO;
348 size_t n, k;
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;
358 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
359 if (errno == 0) {
360 char error[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
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
372 xsprintf(error, "ERRNO=%i", _saved_errno_);
373
374 assert_cc(3 == LOG_ERR);
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);
378
379 return sd_journal_sendv(iov, skip + 3);
380 }
381
382 if (errno != ERANGE)
383 return -errno;
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
395 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
396 static const union sockaddr_union sa = {
397 .un.sun_family = AF_UNIX,
398 .un.sun_path = "/run/systemd/journal/stdout",
399 };
400 _cleanup_close_ int fd = -1;
401 char *header;
402 size_t l;
403 int r;
404
405 assert_return(priority >= 0, -EINVAL);
406 assert_return(priority <= 7, -EINVAL);
407
408 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
409 if (fd < 0)
410 return -errno;
411
412 r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
413 if (r < 0)
414 return -errno;
415
416 if (shutdown(fd, SHUT_RD) < 0)
417 return -errno;
418
419 fd_inc_sndbuf(fd, SNDBUF_SIZE);
420
421 if (!identifier)
422 identifier = "";
423
424 l = strlen(identifier);
425 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
426
427 memcpy(header, identifier, l);
428 header[l++] = '\n';
429 header[l++] = '\n'; /* unit id */
430 header[l++] = '0' + priority;
431 header[l++] = '\n';
432 header[l++] = '0' + !!level_prefix;
433 header[l++] = '\n';
434 header[l++] = '0';
435 header[l++] = '\n';
436 header[l++] = '0';
437 header[l++] = '\n';
438 header[l++] = '0';
439 header[l++] = '\n';
440
441 r = loop_write(fd, header, l, false);
442 if (r < 0)
443 return r;
444
445 r = fd;
446 fd = -1;
447 return r;
448 }
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) {
462 char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
463 struct iovec iov[5];
464 char *f;
465
466 assert_return(priority >= 0, -EINVAL);
467 assert_return(priority <= 7, -EINVAL);
468 assert_return(format, -EINVAL);
469
470 xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
471
472 memcpy(buffer, "MESSAGE=", 8);
473 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
474
475 /* Strip trailing whitespace, keep prefixing whitespace */
476 (void) strstrip(buffer);
477
478 /* Suppress empty lines */
479 if (isempty(buffer+8))
480 return 0;
481
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. */
485 ALLOCA_CODE_FUNC(f, func);
486
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);
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, ...) {
497 _cleanup_free_ struct iovec *iov = NULL;
498 int r, i, j;
499 va_list ap;
500 char *f;
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
511 ALLOCA_CODE_FUNC(f, func);
512
513 iov[0] = IOVEC_MAKE_STRING(file);
514 iov[1] = IOVEC_MAKE_STRING(line);
515 iov[2] = IOVEC_MAKE_STRING(f);
516
517 r = sd_journal_sendv(iov, i);
518
519 finish:
520 for (j = 3; j < i; j++)
521 free(iov[j].iov_base);
522
523 return r;
524 }
525
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
531 struct iovec *niov;
532 char *f;
533
534 assert_return(iov, -EINVAL);
535 assert_return(n > 0, -EINVAL);
536
537 niov = alloca(sizeof(struct iovec) * (n + 3));
538 memcpy(niov, iov, sizeof(struct iovec) * n);
539
540 ALLOCA_CODE_FUNC(f, func);
541
542 niov[n++] = IOVEC_MAKE_STRING(file);
543 niov[n++] = IOVEC_MAKE_STRING(line);
544 niov[n++] = IOVEC_MAKE_STRING(f);
545
546 return sd_journal_sendv(niov, n);
547 }
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];
555 char *f;
556
557 ALLOCA_CODE_FUNC(f, func);
558
559 iov[0] = IOVEC_MAKE_STRING(file);
560 iov[1] = IOVEC_MAKE_STRING(line);
561 iov[2] = IOVEC_MAKE_STRING(f);
562
563 return fill_iovec_perror_and_send(message, 3, iov);
564 }