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"
35 #include "memfd-util.h"
36 #include "socket-util.h"
37 #include "string-util.h"
40 #define SNDBUF_SIZE (8*1024*1024)
42 #define ALLOCA_CODE_FUNC(f, func) \
45 const char *_func = (func); \
47 _fl = strlen(_func) + 1; \
48 *_f = alloca(_fl + 10); \
49 memcpy(*_f, "CODE_FUNC=", 10); \
50 memcpy(*_f + 10, _func, _fl); \
53 /* We open a single fd, and we'll share it with the current process,
54 * all its threads, and all its subprocesses. This means we need to
55 * initialize it atomically, and need to operate on it atomically
56 * never assuming we are the only user */
58 static int journal_fd(void) {
60 static int fd_plus_one
= 0;
64 return fd_plus_one
- 1;
66 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
70 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
72 if (!__sync_bool_compare_and_swap(&fd_plus_one
, 0, fd
+1)) {
80 _public_
int sd_journal_print(int priority
, const char *format
, ...) {
85 r
= sd_journal_printv(priority
, format
, ap
);
91 _public_
int sd_journal_printv(int priority
, const char *format
, va_list ap
) {
93 /* FIXME: Instead of limiting things to LINE_MAX we could do a
94 C99 variable-length array on the stack here in a loop. */
96 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
99 assert_return(priority
>= 0, -EINVAL
);
100 assert_return(priority
<= 7, -EINVAL
);
101 assert_return(format
, -EINVAL
);
103 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
105 memcpy(buffer
, "MESSAGE=", 8);
106 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
109 IOVEC_SET_STRING(iov
[0], buffer
);
110 IOVEC_SET_STRING(iov
[1], p
);
112 return sd_journal_sendv(iov
, 2);
115 _printf_(1, 0) static int fill_iovec_sprintf(const char *format
, va_list ap
, int extra
, struct iovec
**_iov
) {
117 int r
, n
= 0, i
= 0, j
;
118 struct iovec
*iov
= NULL
;
123 n
= MAX(extra
* 2, extra
+ 4);
124 iov
= malloc0(n
* sizeof(struct iovec
));
140 c
= realloc(iov
, n
* sizeof(struct iovec
));
150 if (vasprintf(&buffer
, format
, aq
) < 0) {
157 VA_FORMAT_ADVANCE(format
, ap
);
159 IOVEC_SET_STRING(iov
[i
++], buffer
);
161 format
= va_arg(ap
, char *);
169 for (j
= 0; j
< i
; j
++)
170 free(iov
[j
].iov_base
);
177 _public_
int sd_journal_send(const char *format
, ...) {
180 struct iovec
*iov
= NULL
;
182 va_start(ap
, format
);
183 i
= fill_iovec_sprintf(format
, ap
, 0, &iov
);
186 if (_unlikely_(i
< 0)) {
191 r
= sd_journal_sendv(iov
, i
);
194 for (j
= 0; j
< i
; j
++)
195 free(iov
[j
].iov_base
);
202 _public_
int sd_journal_sendv(const struct iovec
*iov
, int n
) {
205 _cleanup_close_
int buffer_fd
= -1;
209 struct sockaddr_un sa
= {
210 .sun_family
= AF_UNIX
,
211 .sun_path
= "/run/systemd/journal/socket",
215 .msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.sun_path
),
218 bool have_syslog_identifier
= false;
221 assert_return(iov
, -EINVAL
);
222 assert_return(n
> 0, -EINVAL
);
224 w
= alloca(sizeof(struct iovec
) * n
* 5 + 3);
225 l
= alloca(sizeof(uint64_t) * n
);
227 for (i
= 0; i
< n
; i
++) {
230 if (_unlikely_(!iov
[i
].iov_base
|| iov
[i
].iov_len
<= 1))
233 c
= memchr(iov
[i
].iov_base
, '=', iov
[i
].iov_len
);
234 if (_unlikely_(!c
|| c
== iov
[i
].iov_base
))
237 have_syslog_identifier
= have_syslog_identifier
||
238 (c
== (char *) iov
[i
].iov_base
+ 17 &&
239 startswith(iov
[i
].iov_base
, "SYSLOG_IDENTIFIER"));
241 nl
= memchr(iov
[i
].iov_base
, '\n', iov
[i
].iov_len
);
243 if (_unlikely_(nl
< c
))
246 /* Already includes a newline? Bummer, then
247 * let's write the variable name, then a
248 * newline, then the size (64bit LE), followed
249 * by the data and a final newline */
251 w
[j
].iov_base
= iov
[i
].iov_base
;
252 w
[j
].iov_len
= c
- (char*) iov
[i
].iov_base
;
255 IOVEC_SET_STRING(w
[j
++], "\n");
257 l
[i
] = htole64(iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1);
258 w
[j
].iov_base
= &l
[i
];
259 w
[j
].iov_len
= sizeof(uint64_t);
262 w
[j
].iov_base
= c
+ 1;
263 w
[j
].iov_len
= iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1;
267 /* Nothing special? Then just add the line and
268 * append a newline */
271 IOVEC_SET_STRING(w
[j
++], "\n");
274 if (!have_syslog_identifier
&&
275 string_is_safe(program_invocation_short_name
)) {
277 /* Implicitly add program_invocation_short_name, if it
278 * is not set explicitly. We only do this for
279 * program_invocation_short_name, and nothing else
280 * since everything else is much nicer to retrieve
281 * from the outside. */
283 IOVEC_SET_STRING(w
[j
++], "SYSLOG_IDENTIFIER=");
284 IOVEC_SET_STRING(w
[j
++], program_invocation_short_name
);
285 IOVEC_SET_STRING(w
[j
++], "\n");
289 if (_unlikely_(fd
< 0))
295 k
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
299 /* Fail silently if the journal is not available */
303 if (errno
!= EMSGSIZE
&& errno
!= ENOBUFS
)
306 /* Message doesn't fit... Let's dump the data in a memfd or
307 * temporary file and just pass a file descriptor of it to the
310 * For the temporary files we use /dev/shm instead of /tmp
311 * here, since we want this to be a tmpfs, and one that is
312 * available from early boot on and where unprivileged users
313 * can create files. */
314 buffer_fd
= memfd_new(NULL
);
316 if (buffer_fd
== -ENOSYS
) {
317 buffer_fd
= open_tmpfile("/dev/shm", O_RDWR
| O_CLOEXEC
);
326 n
= writev(buffer_fd
, w
, j
);
331 r
= memfd_set_sealed(buffer_fd
);
336 return send_one_fd(fd
, buffer_fd
, 0);
339 static int fill_iovec_perror_and_send(const char *message
, int skip
, struct iovec iov
[]) {
343 k
= isempty(message
) ? 0 : strlen(message
) + 2;
351 j
= strerror_r(_saved_errno_
, buffer
+ 8 + k
, n
- 8 - k
);
353 char error
[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
355 if (j
!= buffer
+ 8 + k
)
356 memmove(buffer
+ 8 + k
, j
, strlen(j
)+1);
358 memcpy(buffer
, "MESSAGE=", 8);
361 memcpy(buffer
+ 8, message
, k
- 2);
362 memcpy(buffer
+ 8 + k
- 2, ": ", 2);
365 xsprintf(error
, "ERRNO=%i", _saved_errno_
);
367 IOVEC_SET_STRING(iov
[skip
+0], "PRIORITY=3");
368 IOVEC_SET_STRING(iov
[skip
+1], buffer
);
369 IOVEC_SET_STRING(iov
[skip
+2], error
);
371 return sd_journal_sendv(iov
, skip
+ 3);
381 _public_
int sd_journal_perror(const char *message
) {
382 struct iovec iovec
[3];
384 return fill_iovec_perror_and_send(message
, 0, iovec
);
387 _public_
int sd_journal_stream_fd(const char *identifier
, int priority
, int level_prefix
) {
388 union sockaddr_union sa
= {
389 .un
.sun_family
= AF_UNIX
,
390 .un
.sun_path
= "/run/systemd/journal/stdout",
392 _cleanup_close_
int fd
= -1;
397 assert_return(priority
>= 0, -EINVAL
);
398 assert_return(priority
<= 7, -EINVAL
);
400 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0);
404 r
= connect(fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
408 if (shutdown(fd
, SHUT_RD
) < 0)
411 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
416 l
= strlen(identifier
);
417 header
= alloca(l
+ 1 + 1 + 2 + 2 + 2 + 2 + 2);
419 memcpy(header
, identifier
, l
);
421 header
[l
++] = '\n'; /* unit id */
422 header
[l
++] = '0' + priority
;
424 header
[l
++] = '0' + !!level_prefix
;
433 r
= loop_write(fd
, header
, l
, false);
442 _public_
int sd_journal_print_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, ...) {
446 va_start(ap
, format
);
447 r
= sd_journal_printv_with_location(priority
, file
, line
, func
, format
, ap
);
453 _public_
int sd_journal_printv_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, va_list ap
) {
454 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
458 assert_return(priority
>= 0, -EINVAL
);
459 assert_return(priority
<= 7, -EINVAL
);
460 assert_return(format
, -EINVAL
);
462 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
464 memcpy(buffer
, "MESSAGE=", 8);
465 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
467 /* func is initialized from __func__ which is not a macro, but
468 * a static const char[], hence cannot easily be prefixed with
469 * CODE_FUNC=, hence let's do it manually here. */
470 ALLOCA_CODE_FUNC(f
, func
);
473 IOVEC_SET_STRING(iov
[0], buffer
);
474 IOVEC_SET_STRING(iov
[1], p
);
475 IOVEC_SET_STRING(iov
[2], file
);
476 IOVEC_SET_STRING(iov
[3], line
);
477 IOVEC_SET_STRING(iov
[4], f
);
479 return sd_journal_sendv(iov
, ELEMENTSOF(iov
));
482 _public_
int sd_journal_send_with_location(const char *file
, const char *line
, const char *func
, const char *format
, ...) {
485 struct iovec
*iov
= NULL
;
488 va_start(ap
, format
);
489 i
= fill_iovec_sprintf(format
, ap
, 3, &iov
);
492 if (_unlikely_(i
< 0)) {
497 ALLOCA_CODE_FUNC(f
, func
);
499 IOVEC_SET_STRING(iov
[0], file
);
500 IOVEC_SET_STRING(iov
[1], line
);
501 IOVEC_SET_STRING(iov
[2], f
);
503 r
= sd_journal_sendv(iov
, i
);
506 for (j
= 3; j
< i
; j
++)
507 free(iov
[j
].iov_base
);
514 _public_
int sd_journal_sendv_with_location(
515 const char *file
, const char *line
,
517 const struct iovec
*iov
, int n
) {
522 assert_return(iov
, -EINVAL
);
523 assert_return(n
> 0, -EINVAL
);
525 niov
= alloca(sizeof(struct iovec
) * (n
+ 3));
526 memcpy(niov
, iov
, sizeof(struct iovec
) * n
);
528 ALLOCA_CODE_FUNC(f
, func
);
530 IOVEC_SET_STRING(niov
[n
++], file
);
531 IOVEC_SET_STRING(niov
[n
++], line
);
532 IOVEC_SET_STRING(niov
[n
++], f
);
534 return sd_journal_sendv(niov
, n
);
537 _public_
int sd_journal_perror_with_location(
538 const char *file
, const char *line
,
540 const char *message
) {
545 ALLOCA_CODE_FUNC(f
, func
);
547 IOVEC_SET_STRING(iov
[0], file
);
548 IOVEC_SET_STRING(iov
[1], line
);
549 IOVEC_SET_STRING(iov
[2], f
);
551 return fill_iovec_perror_and_send(message
, 3, iov
);