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/>.
22 #include <sys/socket.h>
30 #define SD_JOURNAL_SUPPRESS_LOCATION
32 #include "sd-journal.h"
34 #include "socket-util.h"
35 #include "memfd-util.h"
37 #define SNDBUF_SIZE (8*1024*1024)
39 #define ALLOCA_CODE_FUNC(f, func) \
42 const char *_func = (func); \
44 _fl = strlen(_func) + 1; \
45 *_f = alloca(_fl + 10); \
46 memcpy(*_f, "CODE_FUNC=", 10); \
47 memcpy(*_f + 10, _func, _fl); \
50 /* We open a single fd, and we'll share it with the current process,
51 * all its threads, and all its subprocesses. This means we need to
52 * initialize it atomically, and need to operate on it atomically
53 * never assuming we are the only user */
55 static int journal_fd(void) {
57 static int fd_plus_one
= 0;
61 return fd_plus_one
- 1;
63 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
67 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
69 if (!__sync_bool_compare_and_swap(&fd_plus_one
, 0, fd
+1)) {
77 _public_
int sd_journal_print(int priority
, const char *format
, ...) {
82 r
= sd_journal_printv(priority
, format
, ap
);
88 _public_
int sd_journal_printv(int priority
, const char *format
, va_list ap
) {
90 /* FIXME: Instead of limiting things to LINE_MAX we could do a
91 C99 variable-length array on the stack here in a loop. */
93 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
96 assert_return(priority
>= 0, -EINVAL
);
97 assert_return(priority
<= 7, -EINVAL
);
98 assert_return(format
, -EINVAL
);
100 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
102 memcpy(buffer
, "MESSAGE=", 8);
103 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
106 IOVEC_SET_STRING(iov
[0], buffer
);
107 IOVEC_SET_STRING(iov
[1], p
);
109 return sd_journal_sendv(iov
, 2);
112 _printf_(1, 0) static int fill_iovec_sprintf(const char *format
, va_list ap
, int extra
, struct iovec
**_iov
) {
114 int r
, n
= 0, i
= 0, j
;
115 struct iovec
*iov
= NULL
;
120 n
= MAX(extra
* 2, extra
+ 4);
121 iov
= malloc0(n
* sizeof(struct iovec
));
137 c
= realloc(iov
, n
* sizeof(struct iovec
));
147 if (vasprintf(&buffer
, format
, aq
) < 0) {
154 VA_FORMAT_ADVANCE(format
, ap
);
156 IOVEC_SET_STRING(iov
[i
++], buffer
);
158 format
= va_arg(ap
, char *);
166 for (j
= 0; j
< i
; j
++)
167 free(iov
[j
].iov_base
);
174 _public_
int sd_journal_send(const char *format
, ...) {
177 struct iovec
*iov
= NULL
;
179 va_start(ap
, format
);
180 i
= fill_iovec_sprintf(format
, ap
, 0, &iov
);
183 if (_unlikely_(i
< 0)) {
188 r
= sd_journal_sendv(iov
, i
);
191 for (j
= 0; j
< i
; j
++)
192 free(iov
[j
].iov_base
);
199 _public_
int sd_journal_sendv(const struct iovec
*iov
, int n
) {
202 _cleanup_close_
int buffer_fd
= -1;
206 struct sockaddr_un sa
= {
207 .sun_family
= AF_UNIX
,
208 .sun_path
= "/run/systemd/journal/socket",
212 .msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.sun_path
),
215 bool have_syslog_identifier
= false;
218 assert_return(iov
, -EINVAL
);
219 assert_return(n
> 0, -EINVAL
);
221 w
= alloca(sizeof(struct iovec
) * n
* 5 + 3);
222 l
= alloca(sizeof(uint64_t) * n
);
224 for (i
= 0; i
< n
; i
++) {
227 if (_unlikely_(!iov
[i
].iov_base
|| iov
[i
].iov_len
<= 1))
230 c
= memchr(iov
[i
].iov_base
, '=', iov
[i
].iov_len
);
231 if (_unlikely_(!c
|| c
== iov
[i
].iov_base
))
234 have_syslog_identifier
= have_syslog_identifier
||
235 (c
== (char *) iov
[i
].iov_base
+ 17 &&
236 startswith(iov
[i
].iov_base
, "SYSLOG_IDENTIFIER"));
238 nl
= memchr(iov
[i
].iov_base
, '\n', iov
[i
].iov_len
);
240 if (_unlikely_(nl
< c
))
243 /* Already includes a newline? Bummer, then
244 * let's write the variable name, then a
245 * newline, then the size (64bit LE), followed
246 * by the data and a final newline */
248 w
[j
].iov_base
= iov
[i
].iov_base
;
249 w
[j
].iov_len
= c
- (char*) iov
[i
].iov_base
;
252 IOVEC_SET_STRING(w
[j
++], "\n");
254 l
[i
] = htole64(iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1);
255 w
[j
].iov_base
= &l
[i
];
256 w
[j
].iov_len
= sizeof(uint64_t);
259 w
[j
].iov_base
= c
+ 1;
260 w
[j
].iov_len
= iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1;
264 /* Nothing special? Then just add the line and
265 * append a newline */
268 IOVEC_SET_STRING(w
[j
++], "\n");
271 if (!have_syslog_identifier
&&
272 string_is_safe(program_invocation_short_name
)) {
274 /* Implicitly add program_invocation_short_name, if it
275 * is not set explicitly. We only do this for
276 * program_invocation_short_name, and nothing else
277 * since everything else is much nicer to retrieve
278 * from the outside. */
280 IOVEC_SET_STRING(w
[j
++], "SYSLOG_IDENTIFIER=");
281 IOVEC_SET_STRING(w
[j
++], program_invocation_short_name
);
282 IOVEC_SET_STRING(w
[j
++], "\n");
286 if (_unlikely_(fd
< 0))
292 k
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
296 /* Fail silently if the journal is not available */
300 if (errno
!= EMSGSIZE
&& errno
!= ENOBUFS
)
303 /* Message doesn't fit... Let's dump the data in a memfd or
304 * temporary file and just pass a file descriptor of it to the
307 * For the temporary files we use /dev/shm instead of /tmp
308 * here, since we want this to be a tmpfs, and one that is
309 * available from early boot on and where unprivileged users
310 * can create files. */
311 buffer_fd
= memfd_new(NULL
);
313 if (buffer_fd
== -ENOSYS
) {
314 buffer_fd
= open_tmpfile("/dev/shm", O_RDWR
| O_CLOEXEC
);
323 n
= writev(buffer_fd
, w
, j
);
328 r
= memfd_set_sealed(buffer_fd
);
333 return send_one_fd(fd
, buffer_fd
, 0);
336 static int fill_iovec_perror_and_send(const char *message
, int skip
, struct iovec iov
[]) {
340 k
= isempty(message
) ? 0 : strlen(message
) + 2;
348 j
= strerror_r(_saved_errno_
, buffer
+ 8 + k
, n
- 8 - k
);
350 char error
[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
352 if (j
!= buffer
+ 8 + k
)
353 memmove(buffer
+ 8 + k
, j
, strlen(j
)+1);
355 memcpy(buffer
, "MESSAGE=", 8);
358 memcpy(buffer
+ 8, message
, k
- 2);
359 memcpy(buffer
+ 8 + k
- 2, ": ", 2);
362 xsprintf(error
, "ERRNO=%i", _saved_errno_
);
364 IOVEC_SET_STRING(iov
[skip
+0], "PRIORITY=3");
365 IOVEC_SET_STRING(iov
[skip
+1], buffer
);
366 IOVEC_SET_STRING(iov
[skip
+2], error
);
368 return sd_journal_sendv(iov
, skip
+ 3);
378 _public_
int sd_journal_perror(const char *message
) {
379 struct iovec iovec
[3];
381 return fill_iovec_perror_and_send(message
, 0, iovec
);
384 _public_
int sd_journal_stream_fd(const char *identifier
, int priority
, int level_prefix
) {
385 union sockaddr_union sa
= {
386 .un
.sun_family
= AF_UNIX
,
387 .un
.sun_path
= "/run/systemd/journal/stdout",
389 _cleanup_close_
int fd
= -1;
394 assert_return(priority
>= 0, -EINVAL
);
395 assert_return(priority
<= 7, -EINVAL
);
397 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0);
401 r
= connect(fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
405 if (shutdown(fd
, SHUT_RD
) < 0)
408 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
413 l
= strlen(identifier
);
414 header
= alloca(l
+ 1 + 1 + 2 + 2 + 2 + 2 + 2);
416 memcpy(header
, identifier
, l
);
418 header
[l
++] = '\n'; /* unit id */
419 header
[l
++] = '0' + priority
;
421 header
[l
++] = '0' + !!level_prefix
;
430 r
= loop_write(fd
, header
, l
, false);
439 _public_
int sd_journal_print_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, ...) {
443 va_start(ap
, format
);
444 r
= sd_journal_printv_with_location(priority
, file
, line
, func
, format
, ap
);
450 _public_
int sd_journal_printv_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, va_list ap
) {
451 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
455 assert_return(priority
>= 0, -EINVAL
);
456 assert_return(priority
<= 7, -EINVAL
);
457 assert_return(format
, -EINVAL
);
459 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
461 memcpy(buffer
, "MESSAGE=", 8);
462 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
464 /* func is initialized from __func__ which is not a macro, but
465 * a static const char[], hence cannot easily be prefixed with
466 * CODE_FUNC=, hence let's do it manually here. */
467 ALLOCA_CODE_FUNC(f
, func
);
470 IOVEC_SET_STRING(iov
[0], buffer
);
471 IOVEC_SET_STRING(iov
[1], p
);
472 IOVEC_SET_STRING(iov
[2], file
);
473 IOVEC_SET_STRING(iov
[3], line
);
474 IOVEC_SET_STRING(iov
[4], f
);
476 return sd_journal_sendv(iov
, ELEMENTSOF(iov
));
479 _public_
int sd_journal_send_with_location(const char *file
, const char *line
, const char *func
, const char *format
, ...) {
482 struct iovec
*iov
= NULL
;
485 va_start(ap
, format
);
486 i
= fill_iovec_sprintf(format
, ap
, 3, &iov
);
489 if (_unlikely_(i
< 0)) {
494 ALLOCA_CODE_FUNC(f
, func
);
496 IOVEC_SET_STRING(iov
[0], file
);
497 IOVEC_SET_STRING(iov
[1], line
);
498 IOVEC_SET_STRING(iov
[2], f
);
500 r
= sd_journal_sendv(iov
, i
);
503 for (j
= 3; j
< i
; j
++)
504 free(iov
[j
].iov_base
);
511 _public_
int sd_journal_sendv_with_location(
512 const char *file
, const char *line
,
514 const struct iovec
*iov
, int n
) {
519 assert_return(iov
, -EINVAL
);
520 assert_return(n
> 0, -EINVAL
);
522 niov
= alloca(sizeof(struct iovec
) * (n
+ 3));
523 memcpy(niov
, iov
, sizeof(struct iovec
) * n
);
525 ALLOCA_CODE_FUNC(f
, func
);
527 IOVEC_SET_STRING(niov
[n
++], file
);
528 IOVEC_SET_STRING(niov
[n
++], line
);
529 IOVEC_SET_STRING(niov
[n
++], f
);
531 return sd_journal_sendv(niov
, n
);
534 _public_
int sd_journal_perror_with_location(
535 const char *file
, const char *line
,
537 const char *message
) {
542 ALLOCA_CODE_FUNC(f
, func
);
544 IOVEC_SET_STRING(iov
[0], file
);
545 IOVEC_SET_STRING(iov
[1], line
);
546 IOVEC_SET_STRING(iov
[2], f
);
548 return fill_iovec_perror_and_send(message
, 3, iov
);