1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/socket.h>
30 #define SD_JOURNAL_SUPPRESS_LOCATION
32 #include "sd-journal.h"
34 #include "alloc-util.h"
38 #include "memfd-util.h"
39 #include "socket-util.h"
40 #include "stdio-util.h"
41 #include "string-util.h"
44 #define SNDBUF_SIZE (8*1024*1024)
46 #define ALLOCA_CODE_FUNC(f, func) \
49 const char *_func = (func); \
51 _fl = strlen(_func) + 1; \
52 *_f = alloca(_fl + 10); \
53 memcpy(*_f, "CODE_FUNC=", 10); \
54 memcpy(*_f + 10, _func, _fl); \
57 /* We open a single fd, and we'll share it with the current process,
58 * all its threads, and all its subprocesses. This means we need to
59 * initialize it atomically, and need to operate on it atomically
60 * never assuming we are the only user */
62 static int journal_fd(void) {
64 static int fd_plus_one
= 0;
68 return fd_plus_one
- 1;
70 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
74 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
76 if (!__sync_bool_compare_and_swap(&fd_plus_one
, 0, fd
+1)) {
84 _public_
int sd_journal_print(int priority
, const char *format
, ...) {
89 r
= sd_journal_printv(priority
, format
, ap
);
95 _public_
int sd_journal_printv(int priority
, const char *format
, va_list ap
) {
97 /* FIXME: Instead of limiting things to LINE_MAX we could do a
98 C99 variable-length array on the stack here in a loop. */
100 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
103 assert_return(priority
>= 0, -EINVAL
);
104 assert_return(priority
<= 7, -EINVAL
);
105 assert_return(format
, -EINVAL
);
107 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
109 memcpy(buffer
, "MESSAGE=", 8);
110 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
113 IOVEC_SET_STRING(iov
[0], buffer
);
114 IOVEC_SET_STRING(iov
[1], p
);
116 return sd_journal_sendv(iov
, 2);
119 _printf_(1, 0) static int fill_iovec_sprintf(const char *format
, va_list ap
, int extra
, struct iovec
**_iov
) {
121 int r
, n
= 0, i
= 0, j
;
122 struct iovec
*iov
= NULL
;
127 n
= MAX(extra
* 2, extra
+ 4);
128 iov
= malloc0(n
* sizeof(struct iovec
));
144 c
= realloc(iov
, n
* sizeof(struct iovec
));
154 if (vasprintf(&buffer
, format
, aq
) < 0) {
161 VA_FORMAT_ADVANCE(format
, ap
);
163 IOVEC_SET_STRING(iov
[i
++], buffer
);
165 format
= va_arg(ap
, char *);
173 for (j
= 0; j
< i
; j
++)
174 free(iov
[j
].iov_base
);
181 _public_
int sd_journal_send(const char *format
, ...) {
184 struct iovec
*iov
= NULL
;
186 va_start(ap
, format
);
187 i
= fill_iovec_sprintf(format
, ap
, 0, &iov
);
190 if (_unlikely_(i
< 0)) {
195 r
= sd_journal_sendv(iov
, i
);
198 for (j
= 0; j
< i
; j
++)
199 free(iov
[j
].iov_base
);
206 _public_
int sd_journal_sendv(const struct iovec
*iov
, int n
) {
209 _cleanup_close_
int buffer_fd
= -1;
213 struct sockaddr_un sa
= {
214 .sun_family
= AF_UNIX
,
215 .sun_path
= "/run/systemd/journal/socket",
219 .msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.sun_path
),
222 bool have_syslog_identifier
= false;
225 assert_return(iov
, -EINVAL
);
226 assert_return(n
> 0, -EINVAL
);
228 w
= newa(struct iovec
, n
* 5 + 3);
229 l
= newa(uint64_t, n
);
231 for (i
= 0; i
< n
; i
++) {
234 if (_unlikely_(!iov
[i
].iov_base
|| iov
[i
].iov_len
<= 1))
237 c
= memchr(iov
[i
].iov_base
, '=', iov
[i
].iov_len
);
238 if (_unlikely_(!c
|| c
== iov
[i
].iov_base
))
241 have_syslog_identifier
= have_syslog_identifier
||
242 (c
== (char *) iov
[i
].iov_base
+ 17 &&
243 startswith(iov
[i
].iov_base
, "SYSLOG_IDENTIFIER"));
245 nl
= memchr(iov
[i
].iov_base
, '\n', iov
[i
].iov_len
);
247 if (_unlikely_(nl
< c
))
250 /* Already includes a newline? Bummer, then
251 * let's write the variable name, then a
252 * newline, then the size (64bit LE), followed
253 * by the data and a final newline */
255 w
[j
].iov_base
= iov
[i
].iov_base
;
256 w
[j
].iov_len
= c
- (char*) iov
[i
].iov_base
;
259 IOVEC_SET_STRING(w
[j
++], "\n");
261 l
[i
] = htole64(iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1);
262 w
[j
].iov_base
= &l
[i
];
263 w
[j
].iov_len
= sizeof(uint64_t);
266 w
[j
].iov_base
= c
+ 1;
267 w
[j
].iov_len
= iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1;
271 /* Nothing special? Then just add the line and
272 * append a newline */
275 IOVEC_SET_STRING(w
[j
++], "\n");
278 if (!have_syslog_identifier
&&
279 string_is_safe(program_invocation_short_name
)) {
281 /* Implicitly add program_invocation_short_name, if it
282 * is not set explicitly. We only do this for
283 * program_invocation_short_name, and nothing else
284 * since everything else is much nicer to retrieve
285 * from the outside. */
287 IOVEC_SET_STRING(w
[j
++], "SYSLOG_IDENTIFIER=");
288 IOVEC_SET_STRING(w
[j
++], program_invocation_short_name
);
289 IOVEC_SET_STRING(w
[j
++], "\n");
293 if (_unlikely_(fd
< 0))
299 k
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
303 /* Fail silently if the journal is not available */
307 if (errno
!= EMSGSIZE
&& errno
!= ENOBUFS
)
310 /* Message doesn't fit... Let's dump the data in a memfd or
311 * temporary file and just pass a file descriptor of it to the
314 * For the temporary files we use /dev/shm instead of /tmp
315 * here, since we want this to be a tmpfs, and one that is
316 * available from early boot on and where unprivileged users
317 * can create files. */
318 buffer_fd
= memfd_new(NULL
);
320 if (buffer_fd
== -ENOSYS
) {
321 buffer_fd
= open_tmpfile("/dev/shm", O_RDWR
| O_CLOEXEC
);
330 n
= writev(buffer_fd
, w
, j
);
335 r
= memfd_set_sealed(buffer_fd
);
340 r
= send_one_fd_sa(fd
, buffer_fd
, mh
.msg_name
, mh
.msg_namelen
, 0);
342 /* Fail silently if the journal is not available */
347 static int fill_iovec_perror_and_send(const char *message
, int skip
, struct iovec iov
[]) {
351 k
= isempty(message
) ? 0 : strlen(message
) + 2;
359 j
= strerror_r(_saved_errno_
, buffer
+ 8 + k
, n
- 8 - k
);
361 char error
[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
363 if (j
!= buffer
+ 8 + k
)
364 memmove(buffer
+ 8 + k
, j
, strlen(j
)+1);
366 memcpy(buffer
, "MESSAGE=", 8);
369 memcpy(buffer
+ 8, message
, k
- 2);
370 memcpy(buffer
+ 8 + k
- 2, ": ", 2);
373 xsprintf(error
, "ERRNO=%i", _saved_errno_
);
375 assert_cc(3 == LOG_ERR
);
376 IOVEC_SET_STRING(iov
[skip
+0], "PRIORITY=3");
377 IOVEC_SET_STRING(iov
[skip
+1], buffer
);
378 IOVEC_SET_STRING(iov
[skip
+2], error
);
380 return sd_journal_sendv(iov
, skip
+ 3);
390 _public_
int sd_journal_perror(const char *message
) {
391 struct iovec iovec
[3];
393 return fill_iovec_perror_and_send(message
, 0, iovec
);
396 _public_
int sd_journal_stream_fd(const char *identifier
, int priority
, int level_prefix
) {
397 union sockaddr_union sa
= {
398 .un
.sun_family
= AF_UNIX
,
399 .un
.sun_path
= "/run/systemd/journal/stdout",
401 _cleanup_close_
int fd
= -1;
406 assert_return(priority
>= 0, -EINVAL
);
407 assert_return(priority
<= 7, -EINVAL
);
409 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0);
413 r
= connect(fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
417 if (shutdown(fd
, SHUT_RD
) < 0)
420 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
425 l
= strlen(identifier
);
426 header
= alloca(l
+ 1 + 1 + 2 + 2 + 2 + 2 + 2);
428 memcpy(header
, identifier
, l
);
430 header
[l
++] = '\n'; /* unit id */
431 header
[l
++] = '0' + priority
;
433 header
[l
++] = '0' + !!level_prefix
;
442 r
= loop_write(fd
, header
, l
, false);
451 _public_
int sd_journal_print_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, ...) {
455 va_start(ap
, format
);
456 r
= sd_journal_printv_with_location(priority
, file
, line
, func
, format
, ap
);
462 _public_
int sd_journal_printv_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, va_list ap
) {
463 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
467 assert_return(priority
>= 0, -EINVAL
);
468 assert_return(priority
<= 7, -EINVAL
);
469 assert_return(format
, -EINVAL
);
471 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
473 memcpy(buffer
, "MESSAGE=", 8);
474 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
476 /* func is initialized from __func__ which is not a macro, but
477 * a static const char[], hence cannot easily be prefixed with
478 * CODE_FUNC=, hence let's do it manually here. */
479 ALLOCA_CODE_FUNC(f
, func
);
482 IOVEC_SET_STRING(iov
[0], buffer
);
483 IOVEC_SET_STRING(iov
[1], p
);
484 IOVEC_SET_STRING(iov
[2], file
);
485 IOVEC_SET_STRING(iov
[3], line
);
486 IOVEC_SET_STRING(iov
[4], f
);
488 return sd_journal_sendv(iov
, ELEMENTSOF(iov
));
491 _public_
int sd_journal_send_with_location(const char *file
, const char *line
, const char *func
, const char *format
, ...) {
494 struct iovec
*iov
= NULL
;
497 va_start(ap
, format
);
498 i
= fill_iovec_sprintf(format
, ap
, 3, &iov
);
501 if (_unlikely_(i
< 0)) {
506 ALLOCA_CODE_FUNC(f
, func
);
508 IOVEC_SET_STRING(iov
[0], file
);
509 IOVEC_SET_STRING(iov
[1], line
);
510 IOVEC_SET_STRING(iov
[2], f
);
512 r
= sd_journal_sendv(iov
, i
);
515 for (j
= 3; j
< i
; j
++)
516 free(iov
[j
].iov_base
);
523 _public_
int sd_journal_sendv_with_location(
524 const char *file
, const char *line
,
526 const struct iovec
*iov
, int n
) {
531 assert_return(iov
, -EINVAL
);
532 assert_return(n
> 0, -EINVAL
);
534 niov
= alloca(sizeof(struct iovec
) * (n
+ 3));
535 memcpy(niov
, iov
, sizeof(struct iovec
) * n
);
537 ALLOCA_CODE_FUNC(f
, func
);
539 IOVEC_SET_STRING(niov
[n
++], file
);
540 IOVEC_SET_STRING(niov
[n
++], line
);
541 IOVEC_SET_STRING(niov
[n
++], f
);
543 return sd_journal_sendv(niov
, n
);
546 _public_
int sd_journal_perror_with_location(
547 const char *file
, const char *line
,
549 const char *message
) {
554 ALLOCA_CODE_FUNC(f
, func
);
556 IOVEC_SET_STRING(iov
[0], file
);
557 IOVEC_SET_STRING(iov
[1], line
);
558 IOVEC_SET_STRING(iov
[2], f
);
560 return fill_iovec_perror_and_send(message
, 3, iov
);