1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
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.
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.
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/>.
25 #include <sys/socket.h>
29 #define SD_JOURNAL_SUPPRESS_LOCATION
31 #include "sd-journal.h"
33 #include "alloc-util.h"
37 #include "memfd-util.h"
38 #include "socket-util.h"
39 #include "stdio-util.h"
40 #include "string-util.h"
43 #define SNDBUF_SIZE (8*1024*1024)
45 #define ALLOCA_CODE_FUNC(f, func) \
48 const char *_func = (func); \
50 _fl = strlen(_func) + 1; \
51 *_f = alloca(_fl + 10); \
52 memcpy(*_f, "CODE_FUNC=", 10); \
53 memcpy(*_f + 10, _func, _fl); \
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 */
61 static int journal_fd(void) {
63 static int fd_plus_one
= 0;
67 return fd_plus_one
- 1;
69 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
73 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
75 if (!__sync_bool_compare_and_swap(&fd_plus_one
, 0, fd
+1)) {
83 _public_
int sd_journal_print(int priority
, const char *format
, ...) {
88 r
= sd_journal_printv(priority
, format
, ap
);
94 _public_
int sd_journal_printv(int priority
, const char *format
, va_list ap
) {
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. */
99 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
102 assert_return(priority
>= 0, -EINVAL
);
103 assert_return(priority
<= 7, -EINVAL
);
104 assert_return(format
, -EINVAL
);
106 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
108 memcpy(buffer
, "MESSAGE=", 8);
109 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
111 /* Strip trailing whitespace, keep prefix whitespace. */
112 (void) strstrip(buffer
);
114 /* Suppress empty lines */
115 if (isempty(buffer
+8))
118 iov
[0] = IOVEC_MAKE_STRING(buffer
);
119 iov
[1] = IOVEC_MAKE_STRING(p
);
121 return sd_journal_sendv(iov
, 2);
124 _printf_(1, 0) static int fill_iovec_sprintf(const char *format
, va_list ap
, int extra
, struct iovec
**_iov
) {
126 int r
, n
= 0, i
= 0, j
;
127 struct iovec
*iov
= NULL
;
132 n
= MAX(extra
* 2, extra
+ 4);
133 iov
= malloc0(n
* sizeof(struct iovec
));
149 c
= realloc(iov
, n
* sizeof(struct iovec
));
159 if (vasprintf(&buffer
, format
, aq
) < 0) {
166 VA_FORMAT_ADVANCE(format
, ap
);
168 (void) strstrip(buffer
); /* strip trailing whitespace, keep prefixing whitespace */
170 iov
[i
++] = IOVEC_MAKE_STRING(buffer
);
172 format
= va_arg(ap
, char *);
180 for (j
= 0; j
< i
; j
++)
181 free(iov
[j
].iov_base
);
188 _public_
int sd_journal_send(const char *format
, ...) {
191 struct iovec
*iov
= NULL
;
193 va_start(ap
, format
);
194 i
= fill_iovec_sprintf(format
, ap
, 0, &iov
);
197 if (_unlikely_(i
< 0)) {
202 r
= sd_journal_sendv(iov
, i
);
205 for (j
= 0; j
< i
; j
++)
206 free(iov
[j
].iov_base
);
213 _public_
int sd_journal_sendv(const struct iovec
*iov
, int n
) {
216 _cleanup_close_
int buffer_fd
= -1;
220 static const union sockaddr_union sa
= {
221 .un
.sun_family
= AF_UNIX
,
222 .un
.sun_path
= "/run/systemd/journal/socket",
225 .msg_name
= (struct sockaddr
*) &sa
.sa
,
226 .msg_namelen
= SOCKADDR_UN_LEN(sa
.un
),
229 bool have_syslog_identifier
= false;
232 assert_return(iov
, -EINVAL
);
233 assert_return(n
> 0, -EINVAL
);
235 w
= newa(struct iovec
, n
* 5 + 3);
236 l
= newa(uint64_t, n
);
238 for (i
= 0; i
< n
; i
++) {
241 if (_unlikely_(!iov
[i
].iov_base
|| iov
[i
].iov_len
<= 1))
244 c
= memchr(iov
[i
].iov_base
, '=', iov
[i
].iov_len
);
245 if (_unlikely_(!c
|| c
== iov
[i
].iov_base
))
248 have_syslog_identifier
= have_syslog_identifier
||
249 (c
== (char *) iov
[i
].iov_base
+ 17 &&
250 startswith(iov
[i
].iov_base
, "SYSLOG_IDENTIFIER"));
252 nl
= memchr(iov
[i
].iov_base
, '\n', iov
[i
].iov_len
);
254 if (_unlikely_(nl
< c
))
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 */
262 w
[j
++] = IOVEC_MAKE(iov
[i
].iov_base
, c
- (char*) iov
[i
].iov_base
);
263 w
[j
++] = IOVEC_MAKE_STRING("\n");
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));
268 w
[j
++] = IOVEC_MAKE(c
+ 1, iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1);
270 /* Nothing special? Then just add the line and
271 * append a newline */
274 w
[j
++] = IOVEC_MAKE_STRING("\n");
277 if (!have_syslog_identifier
&&
278 string_is_safe(program_invocation_short_name
)) {
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. */
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");
292 if (_unlikely_(fd
< 0))
298 k
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
302 /* Fail silently if the journal is not available */
306 if (!IN_SET(errno
, EMSGSIZE
, ENOBUFS
))
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
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
);
319 if (buffer_fd
== -ENOSYS
) {
320 buffer_fd
= open_tmpfile_unlinkable("/dev/shm", O_RDWR
| O_CLOEXEC
);
329 n
= writev(buffer_fd
, w
, j
);
334 r
= memfd_set_sealed(buffer_fd
);
339 r
= send_one_fd_sa(fd
, buffer_fd
, mh
.msg_name
, mh
.msg_namelen
, 0);
341 /* Fail silently if the journal is not available */
346 static int fill_iovec_perror_and_send(const char *message
, int skip
, struct iovec iov
[]) {
350 k
= isempty(message
) ? 0 : strlen(message
) + 2;
358 j
= strerror_r(_saved_errno_
, buffer
+ 8 + k
, n
- 8 - k
);
360 char error
[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
362 if (j
!= buffer
+ 8 + k
)
363 memmove(buffer
+ 8 + k
, j
, strlen(j
)+1);
365 memcpy(buffer
, "MESSAGE=", 8);
368 memcpy(buffer
+ 8, message
, k
- 2);
369 memcpy(buffer
+ 8 + k
- 2, ": ", 2);
372 xsprintf(error
, "ERRNO=%i", _saved_errno_
);
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
);
379 return sd_journal_sendv(iov
, skip
+ 3);
389 _public_
int sd_journal_perror(const char *message
) {
390 struct iovec iovec
[3];
392 return fill_iovec_perror_and_send(message
, 0, iovec
);
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",
400 _cleanup_close_
int fd
= -1;
405 assert_return(priority
>= 0, -EINVAL
);
406 assert_return(priority
<= 7, -EINVAL
);
408 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0);
412 r
= connect(fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
));
416 if (shutdown(fd
, SHUT_RD
) < 0)
419 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
424 l
= strlen(identifier
);
425 header
= alloca(l
+ 1 + 1 + 2 + 2 + 2 + 2 + 2);
427 memcpy(header
, identifier
, l
);
429 header
[l
++] = '\n'; /* unit id */
430 header
[l
++] = '0' + priority
;
432 header
[l
++] = '0' + !!level_prefix
;
441 r
= loop_write(fd
, header
, l
, false);
450 _public_
int sd_journal_print_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, ...) {
454 va_start(ap
, format
);
455 r
= sd_journal_printv_with_location(priority
, file
, line
, func
, format
, ap
);
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];
466 assert_return(priority
>= 0, -EINVAL
);
467 assert_return(priority
<= 7, -EINVAL
);
468 assert_return(format
, -EINVAL
);
470 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
472 memcpy(buffer
, "MESSAGE=", 8);
473 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
475 /* Strip trailing whitespace, keep prefixing whitespace */
476 (void) strstrip(buffer
);
478 /* Suppress empty lines */
479 if (isempty(buffer
+8))
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
);
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
);
493 return sd_journal_sendv(iov
, ELEMENTSOF(iov
));
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
;
502 va_start(ap
, format
);
503 i
= fill_iovec_sprintf(format
, ap
, 3, &iov
);
506 if (_unlikely_(i
< 0)) {
511 ALLOCA_CODE_FUNC(f
, func
);
513 iov
[0] = IOVEC_MAKE_STRING(file
);
514 iov
[1] = IOVEC_MAKE_STRING(line
);
515 iov
[2] = IOVEC_MAKE_STRING(f
);
517 r
= sd_journal_sendv(iov
, i
);
520 for (j
= 3; j
< i
; j
++)
521 free(iov
[j
].iov_base
);
526 _public_
int sd_journal_sendv_with_location(
527 const char *file
, const char *line
,
529 const struct iovec
*iov
, int n
) {
534 assert_return(iov
, -EINVAL
);
535 assert_return(n
> 0, -EINVAL
);
537 niov
= alloca(sizeof(struct iovec
) * (n
+ 3));
538 memcpy(niov
, iov
, sizeof(struct iovec
) * n
);
540 ALLOCA_CODE_FUNC(f
, func
);
542 niov
[n
++] = IOVEC_MAKE_STRING(file
);
543 niov
[n
++] = IOVEC_MAKE_STRING(line
);
544 niov
[n
++] = IOVEC_MAKE_STRING(f
);
546 return sd_journal_sendv(niov
, n
);
549 _public_
int sd_journal_perror_with_location(
550 const char *file
, const char *line
,
552 const char *message
) {
557 ALLOCA_CODE_FUNC(f
, func
);
559 iov
[0] = IOVEC_MAKE_STRING(file
);
560 iov
[1] = IOVEC_MAKE_STRING(line
);
561 iov
[2] = IOVEC_MAKE_STRING(f
);
563 return fill_iovec_perror_and_send(message
, 3, iov
);