2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/socket.h>
28 #define SD_JOURNAL_SUPPRESS_LOCATION
30 #include "sd-journal.h"
32 #include "alloc-util.h"
36 #include "memfd-util.h"
37 #include "socket-util.h"
38 #include "stdio-util.h"
39 #include "string-util.h"
42 #define SNDBUF_SIZE (8*1024*1024)
44 #define ALLOCA_CODE_FUNC(f, func) \
47 const char *_func = (func); \
49 _fl = strlen(_func) + 1; \
50 *_f = alloca(_fl + 10); \
51 memcpy(*_f, "CODE_FUNC=", 10); \
52 memcpy(*_f + 10, _func, _fl); \
55 /* We open a single fd, and we'll share it with the current process,
56 * all its threads, and all its subprocesses. This means we need to
57 * initialize it atomically, and need to operate on it atomically
58 * never assuming we are the only user */
60 static int journal_fd(void) {
62 static int fd_plus_one
= 0;
66 return fd_plus_one
- 1;
68 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
72 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
74 if (!__sync_bool_compare_and_swap(&fd_plus_one
, 0, fd
+1)) {
82 _public_
int sd_journal_print(int priority
, const char *format
, ...) {
87 r
= sd_journal_printv(priority
, format
, ap
);
93 _public_
int sd_journal_printv(int priority
, const char *format
, va_list ap
) {
95 /* FIXME: Instead of limiting things to LINE_MAX we could do a
96 C99 variable-length array on the stack here in a loop. */
98 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
101 assert_return(priority
>= 0, -EINVAL
);
102 assert_return(priority
<= 7, -EINVAL
);
103 assert_return(format
, -EINVAL
);
105 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
107 memcpy(buffer
, "MESSAGE=", 8);
108 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
110 /* Strip trailing whitespace, keep prefix whitespace. */
111 (void) strstrip(buffer
);
113 /* Suppress empty lines */
114 if (isempty(buffer
+8))
118 IOVEC_SET_STRING(iov
[0], buffer
);
119 IOVEC_SET_STRING(iov
[1], 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 IOVEC_SET_STRING(iov
[i
++], 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
].iov_base
= iov
[i
].iov_base
;
263 w
[j
].iov_len
= c
- (char*) iov
[i
].iov_base
;
266 IOVEC_SET_STRING(w
[j
++], "\n");
268 l
[i
] = htole64(iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1);
269 w
[j
].iov_base
= &l
[i
];
270 w
[j
].iov_len
= sizeof(uint64_t);
273 w
[j
].iov_base
= c
+ 1;
274 w
[j
].iov_len
= iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1;
278 /* Nothing special? Then just add the line and
279 * append a newline */
282 IOVEC_SET_STRING(w
[j
++], "\n");
285 if (!have_syslog_identifier
&&
286 string_is_safe(program_invocation_short_name
)) {
288 /* Implicitly add program_invocation_short_name, if it
289 * is not set explicitly. We only do this for
290 * program_invocation_short_name, and nothing else
291 * since everything else is much nicer to retrieve
292 * from the outside. */
294 IOVEC_SET_STRING(w
[j
++], "SYSLOG_IDENTIFIER=");
295 IOVEC_SET_STRING(w
[j
++], program_invocation_short_name
);
296 IOVEC_SET_STRING(w
[j
++], "\n");
300 if (_unlikely_(fd
< 0))
306 k
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
310 /* Fail silently if the journal is not available */
314 if (errno
!= EMSGSIZE
&& errno
!= ENOBUFS
)
317 /* Message doesn't fit... Let's dump the data in a memfd or
318 * temporary file and just pass a file descriptor of it to the
321 * For the temporary files we use /dev/shm instead of /tmp
322 * here, since we want this to be a tmpfs, and one that is
323 * available from early boot on and where unprivileged users
324 * can create files. */
325 buffer_fd
= memfd_new(NULL
);
327 if (buffer_fd
== -ENOSYS
) {
328 buffer_fd
= open_tmpfile_unlinkable("/dev/shm", O_RDWR
| O_CLOEXEC
);
337 n
= writev(buffer_fd
, w
, j
);
342 r
= memfd_set_sealed(buffer_fd
);
347 r
= send_one_fd_sa(fd
, buffer_fd
, mh
.msg_name
, mh
.msg_namelen
, 0);
349 /* Fail silently if the journal is not available */
354 static int fill_iovec_perror_and_send(const char *message
, int skip
, struct iovec iov
[]) {
358 k
= isempty(message
) ? 0 : strlen(message
) + 2;
366 j
= strerror_r(_saved_errno_
, buffer
+ 8 + k
, n
- 8 - k
);
368 char error
[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
370 if (j
!= buffer
+ 8 + k
)
371 memmove(buffer
+ 8 + k
, j
, strlen(j
)+1);
373 memcpy(buffer
, "MESSAGE=", 8);
376 memcpy(buffer
+ 8, message
, k
- 2);
377 memcpy(buffer
+ 8 + k
- 2, ": ", 2);
380 xsprintf(error
, "ERRNO=%i", _saved_errno_
);
382 assert_cc(3 == LOG_ERR
);
383 IOVEC_SET_STRING(iov
[skip
+0], "PRIORITY=3");
384 IOVEC_SET_STRING(iov
[skip
+1], buffer
);
385 IOVEC_SET_STRING(iov
[skip
+2], error
);
387 return sd_journal_sendv(iov
, skip
+ 3);
397 _public_
int sd_journal_perror(const char *message
) {
398 struct iovec iovec
[3];
400 return fill_iovec_perror_and_send(message
, 0, iovec
);
403 _public_
int sd_journal_stream_fd(const char *identifier
, int priority
, int level_prefix
) {
404 static const union sockaddr_union sa
= {
405 .un
.sun_family
= AF_UNIX
,
406 .un
.sun_path
= "/run/systemd/journal/stdout",
408 _cleanup_close_
int fd
= -1;
413 assert_return(priority
>= 0, -EINVAL
);
414 assert_return(priority
<= 7, -EINVAL
);
416 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0);
420 r
= connect(fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
));
424 if (shutdown(fd
, SHUT_RD
) < 0)
427 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
432 l
= strlen(identifier
);
433 header
= alloca(l
+ 1 + 1 + 2 + 2 + 2 + 2 + 2);
435 memcpy(header
, identifier
, l
);
437 header
[l
++] = '\n'; /* unit id */
438 header
[l
++] = '0' + priority
;
440 header
[l
++] = '0' + !!level_prefix
;
449 r
= loop_write(fd
, header
, l
, false);
458 _public_
int sd_journal_print_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, ...) {
462 va_start(ap
, format
);
463 r
= sd_journal_printv_with_location(priority
, file
, line
, func
, format
, ap
);
469 _public_
int sd_journal_printv_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, va_list ap
) {
470 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
474 assert_return(priority
>= 0, -EINVAL
);
475 assert_return(priority
<= 7, -EINVAL
);
476 assert_return(format
, -EINVAL
);
478 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
480 memcpy(buffer
, "MESSAGE=", 8);
481 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
483 /* Strip trailing whitespace, keep prefixing whitespace */
484 (void) strstrip(buffer
);
486 /* Suppress empty lines */
487 if (isempty(buffer
+8))
490 /* func is initialized from __func__ which is not a macro, but
491 * a static const char[], hence cannot easily be prefixed with
492 * CODE_FUNC=, hence let's do it manually here. */
493 ALLOCA_CODE_FUNC(f
, func
);
496 IOVEC_SET_STRING(iov
[0], buffer
);
497 IOVEC_SET_STRING(iov
[1], p
);
498 IOVEC_SET_STRING(iov
[2], file
);
499 IOVEC_SET_STRING(iov
[3], line
);
500 IOVEC_SET_STRING(iov
[4], f
);
502 return sd_journal_sendv(iov
, ELEMENTSOF(iov
));
505 _public_
int sd_journal_send_with_location(const char *file
, const char *line
, const char *func
, const char *format
, ...) {
508 struct iovec
*iov
= NULL
;
511 va_start(ap
, format
);
512 i
= fill_iovec_sprintf(format
, ap
, 3, &iov
);
515 if (_unlikely_(i
< 0)) {
520 ALLOCA_CODE_FUNC(f
, func
);
522 IOVEC_SET_STRING(iov
[0], file
);
523 IOVEC_SET_STRING(iov
[1], line
);
524 IOVEC_SET_STRING(iov
[2], f
);
526 r
= sd_journal_sendv(iov
, i
);
529 for (j
= 3; j
< i
; j
++)
530 free(iov
[j
].iov_base
);
537 _public_
int sd_journal_sendv_with_location(
538 const char *file
, const char *line
,
540 const struct iovec
*iov
, int n
) {
545 assert_return(iov
, -EINVAL
);
546 assert_return(n
> 0, -EINVAL
);
548 niov
= alloca(sizeof(struct iovec
) * (n
+ 3));
549 memcpy(niov
, iov
, sizeof(struct iovec
) * n
);
551 ALLOCA_CODE_FUNC(f
, func
);
553 IOVEC_SET_STRING(niov
[n
++], file
);
554 IOVEC_SET_STRING(niov
[n
++], line
);
555 IOVEC_SET_STRING(niov
[n
++], f
);
557 return sd_journal_sendv(niov
, n
);
560 _public_
int sd_journal_perror_with_location(
561 const char *file
, const char *line
,
563 const char *message
) {
568 ALLOCA_CODE_FUNC(f
, func
);
570 IOVEC_SET_STRING(iov
[0], file
);
571 IOVEC_SET_STRING(iov
[1], line
);
572 IOVEC_SET_STRING(iov
[2], f
);
574 return fill_iovec_perror_and_send(message
, 3, iov
);