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 "memfd-util.h"
35 #include "socket-util.h"
36 #include "string-util.h"
39 #define SNDBUF_SIZE (8*1024*1024)
41 #define ALLOCA_CODE_FUNC(f, func) \
44 const char *_func = (func); \
46 _fl = strlen(_func) + 1; \
47 *_f = alloca(_fl + 10); \
48 memcpy(*_f, "CODE_FUNC=", 10); \
49 memcpy(*_f + 10, _func, _fl); \
52 /* We open a single fd, and we'll share it with the current process,
53 * all its threads, and all its subprocesses. This means we need to
54 * initialize it atomically, and need to operate on it atomically
55 * never assuming we are the only user */
57 static int journal_fd(void) {
59 static int fd_plus_one
= 0;
63 return fd_plus_one
- 1;
65 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
69 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
71 if (!__sync_bool_compare_and_swap(&fd_plus_one
, 0, fd
+1)) {
79 _public_
int sd_journal_print(int priority
, const char *format
, ...) {
84 r
= sd_journal_printv(priority
, format
, ap
);
90 _public_
int sd_journal_printv(int priority
, const char *format
, va_list ap
) {
92 /* FIXME: Instead of limiting things to LINE_MAX we could do a
93 C99 variable-length array on the stack here in a loop. */
95 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
98 assert_return(priority
>= 0, -EINVAL
);
99 assert_return(priority
<= 7, -EINVAL
);
100 assert_return(format
, -EINVAL
);
102 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
104 memcpy(buffer
, "MESSAGE=", 8);
105 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
108 IOVEC_SET_STRING(iov
[0], buffer
);
109 IOVEC_SET_STRING(iov
[1], p
);
111 return sd_journal_sendv(iov
, 2);
114 _printf_(1, 0) static int fill_iovec_sprintf(const char *format
, va_list ap
, int extra
, struct iovec
**_iov
) {
116 int r
, n
= 0, i
= 0, j
;
117 struct iovec
*iov
= NULL
;
122 n
= MAX(extra
* 2, extra
+ 4);
123 iov
= malloc0(n
* sizeof(struct iovec
));
139 c
= realloc(iov
, n
* sizeof(struct iovec
));
149 if (vasprintf(&buffer
, format
, aq
) < 0) {
156 VA_FORMAT_ADVANCE(format
, ap
);
158 IOVEC_SET_STRING(iov
[i
++], buffer
);
160 format
= va_arg(ap
, char *);
168 for (j
= 0; j
< i
; j
++)
169 free(iov
[j
].iov_base
);
176 _public_
int sd_journal_send(const char *format
, ...) {
179 struct iovec
*iov
= NULL
;
181 va_start(ap
, format
);
182 i
= fill_iovec_sprintf(format
, ap
, 0, &iov
);
185 if (_unlikely_(i
< 0)) {
190 r
= sd_journal_sendv(iov
, i
);
193 for (j
= 0; j
< i
; j
++)
194 free(iov
[j
].iov_base
);
201 _public_
int sd_journal_sendv(const struct iovec
*iov
, int n
) {
204 _cleanup_close_
int buffer_fd
= -1;
208 struct sockaddr_un sa
= {
209 .sun_family
= AF_UNIX
,
210 .sun_path
= "/run/systemd/journal/socket",
214 .msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(sa
.sun_path
),
217 bool have_syslog_identifier
= false;
220 assert_return(iov
, -EINVAL
);
221 assert_return(n
> 0, -EINVAL
);
223 w
= alloca(sizeof(struct iovec
) * n
* 5 + 3);
224 l
= alloca(sizeof(uint64_t) * n
);
226 for (i
= 0; i
< n
; i
++) {
229 if (_unlikely_(!iov
[i
].iov_base
|| iov
[i
].iov_len
<= 1))
232 c
= memchr(iov
[i
].iov_base
, '=', iov
[i
].iov_len
);
233 if (_unlikely_(!c
|| c
== iov
[i
].iov_base
))
236 have_syslog_identifier
= have_syslog_identifier
||
237 (c
== (char *) iov
[i
].iov_base
+ 17 &&
238 startswith(iov
[i
].iov_base
, "SYSLOG_IDENTIFIER"));
240 nl
= memchr(iov
[i
].iov_base
, '\n', iov
[i
].iov_len
);
242 if (_unlikely_(nl
< c
))
245 /* Already includes a newline? Bummer, then
246 * let's write the variable name, then a
247 * newline, then the size (64bit LE), followed
248 * by the data and a final newline */
250 w
[j
].iov_base
= iov
[i
].iov_base
;
251 w
[j
].iov_len
= c
- (char*) iov
[i
].iov_base
;
254 IOVEC_SET_STRING(w
[j
++], "\n");
256 l
[i
] = htole64(iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1);
257 w
[j
].iov_base
= &l
[i
];
258 w
[j
].iov_len
= sizeof(uint64_t);
261 w
[j
].iov_base
= c
+ 1;
262 w
[j
].iov_len
= iov
[i
].iov_len
- (c
- (char*) iov
[i
].iov_base
) - 1;
266 /* Nothing special? Then just add the line and
267 * append a newline */
270 IOVEC_SET_STRING(w
[j
++], "\n");
273 if (!have_syslog_identifier
&&
274 string_is_safe(program_invocation_short_name
)) {
276 /* Implicitly add program_invocation_short_name, if it
277 * is not set explicitly. We only do this for
278 * program_invocation_short_name, and nothing else
279 * since everything else is much nicer to retrieve
280 * from the outside. */
282 IOVEC_SET_STRING(w
[j
++], "SYSLOG_IDENTIFIER=");
283 IOVEC_SET_STRING(w
[j
++], program_invocation_short_name
);
284 IOVEC_SET_STRING(w
[j
++], "\n");
288 if (_unlikely_(fd
< 0))
294 k
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
298 /* Fail silently if the journal is not available */
302 if (errno
!= EMSGSIZE
&& errno
!= ENOBUFS
)
305 /* Message doesn't fit... Let's dump the data in a memfd or
306 * temporary file and just pass a file descriptor of it to the
309 * For the temporary files we use /dev/shm instead of /tmp
310 * here, since we want this to be a tmpfs, and one that is
311 * available from early boot on and where unprivileged users
312 * can create files. */
313 buffer_fd
= memfd_new(NULL
);
315 if (buffer_fd
== -ENOSYS
) {
316 buffer_fd
= open_tmpfile("/dev/shm", O_RDWR
| O_CLOEXEC
);
325 n
= writev(buffer_fd
, w
, j
);
330 r
= memfd_set_sealed(buffer_fd
);
335 return send_one_fd(fd
, buffer_fd
, 0);
338 static int fill_iovec_perror_and_send(const char *message
, int skip
, struct iovec iov
[]) {
342 k
= isempty(message
) ? 0 : strlen(message
) + 2;
350 j
= strerror_r(_saved_errno_
, buffer
+ 8 + k
, n
- 8 - k
);
352 char error
[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1];
354 if (j
!= buffer
+ 8 + k
)
355 memmove(buffer
+ 8 + k
, j
, strlen(j
)+1);
357 memcpy(buffer
, "MESSAGE=", 8);
360 memcpy(buffer
+ 8, message
, k
- 2);
361 memcpy(buffer
+ 8 + k
- 2, ": ", 2);
364 xsprintf(error
, "ERRNO=%i", _saved_errno_
);
366 IOVEC_SET_STRING(iov
[skip
+0], "PRIORITY=3");
367 IOVEC_SET_STRING(iov
[skip
+1], buffer
);
368 IOVEC_SET_STRING(iov
[skip
+2], error
);
370 return sd_journal_sendv(iov
, skip
+ 3);
380 _public_
int sd_journal_perror(const char *message
) {
381 struct iovec iovec
[3];
383 return fill_iovec_perror_and_send(message
, 0, iovec
);
386 _public_
int sd_journal_stream_fd(const char *identifier
, int priority
, int level_prefix
) {
387 union sockaddr_union sa
= {
388 .un
.sun_family
= AF_UNIX
,
389 .un
.sun_path
= "/run/systemd/journal/stdout",
391 _cleanup_close_
int fd
= -1;
396 assert_return(priority
>= 0, -EINVAL
);
397 assert_return(priority
<= 7, -EINVAL
);
399 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0);
403 r
= connect(fd
, &sa
.sa
, offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
));
407 if (shutdown(fd
, SHUT_RD
) < 0)
410 fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
415 l
= strlen(identifier
);
416 header
= alloca(l
+ 1 + 1 + 2 + 2 + 2 + 2 + 2);
418 memcpy(header
, identifier
, l
);
420 header
[l
++] = '\n'; /* unit id */
421 header
[l
++] = '0' + priority
;
423 header
[l
++] = '0' + !!level_prefix
;
432 r
= loop_write(fd
, header
, l
, false);
441 _public_
int sd_journal_print_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, ...) {
445 va_start(ap
, format
);
446 r
= sd_journal_printv_with_location(priority
, file
, line
, func
, format
, ap
);
452 _public_
int sd_journal_printv_with_location(int priority
, const char *file
, const char *line
, const char *func
, const char *format
, va_list ap
) {
453 char buffer
[8 + LINE_MAX
], p
[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1];
457 assert_return(priority
>= 0, -EINVAL
);
458 assert_return(priority
<= 7, -EINVAL
);
459 assert_return(format
, -EINVAL
);
461 xsprintf(p
, "PRIORITY=%i", priority
& LOG_PRIMASK
);
463 memcpy(buffer
, "MESSAGE=", 8);
464 vsnprintf(buffer
+8, sizeof(buffer
) - 8, format
, ap
);
466 /* func is initialized from __func__ which is not a macro, but
467 * a static const char[], hence cannot easily be prefixed with
468 * CODE_FUNC=, hence let's do it manually here. */
469 ALLOCA_CODE_FUNC(f
, func
);
472 IOVEC_SET_STRING(iov
[0], buffer
);
473 IOVEC_SET_STRING(iov
[1], p
);
474 IOVEC_SET_STRING(iov
[2], file
);
475 IOVEC_SET_STRING(iov
[3], line
);
476 IOVEC_SET_STRING(iov
[4], f
);
478 return sd_journal_sendv(iov
, ELEMENTSOF(iov
));
481 _public_
int sd_journal_send_with_location(const char *file
, const char *line
, const char *func
, const char *format
, ...) {
484 struct iovec
*iov
= NULL
;
487 va_start(ap
, format
);
488 i
= fill_iovec_sprintf(format
, ap
, 3, &iov
);
491 if (_unlikely_(i
< 0)) {
496 ALLOCA_CODE_FUNC(f
, func
);
498 IOVEC_SET_STRING(iov
[0], file
);
499 IOVEC_SET_STRING(iov
[1], line
);
500 IOVEC_SET_STRING(iov
[2], f
);
502 r
= sd_journal_sendv(iov
, i
);
505 for (j
= 3; j
< i
; j
++)
506 free(iov
[j
].iov_base
);
513 _public_
int sd_journal_sendv_with_location(
514 const char *file
, const char *line
,
516 const struct iovec
*iov
, int n
) {
521 assert_return(iov
, -EINVAL
);
522 assert_return(n
> 0, -EINVAL
);
524 niov
= alloca(sizeof(struct iovec
) * (n
+ 3));
525 memcpy(niov
, iov
, sizeof(struct iovec
) * n
);
527 ALLOCA_CODE_FUNC(f
, func
);
529 IOVEC_SET_STRING(niov
[n
++], file
);
530 IOVEC_SET_STRING(niov
[n
++], line
);
531 IOVEC_SET_STRING(niov
[n
++], f
);
533 return sd_journal_sendv(niov
, n
);
536 _public_
int sd_journal_perror_with_location(
537 const char *file
, const char *line
,
539 const char *message
) {
544 ALLOCA_CODE_FUNC(f
, func
);
546 IOVEC_SET_STRING(iov
[0], file
);
547 IOVEC_SET_STRING(iov
[1], line
);
548 IOVEC_SET_STRING(iov
[2], f
);
550 return fill_iovec_perror_and_send(message
, 3, iov
);