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"
36 #define SNDBUF_SIZE (8*1024*1024)
38 #define ALLOCA_CODE_FUNC(f, func) \
41 const char *_func = (func); \
43 _fl = strlen(_func) + 1; \
44 *_f = alloca(_fl + 10); \
45 memcpy(*_f, "CODE_FUNC=", 10); \
46 memcpy(*_f + 10, _func, _fl); \
49 /* We open a single fd, and we'll share it with the current process,
50 * all its threads, and all its subprocesses. This means we need to
51 * initialize it atomically, and need to operate on it atomically
52 * never assuming we are the only user */
54 static int journal_fd(void) {
56 static int fd_plus_one = 0;
60 return fd_plus_one - 1;
62 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
66 fd_inc_sndbuf(fd, SNDBUF_SIZE);
68 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
76 _public_ int sd_journal_print(int priority, const char *format, ...) {
81 r = sd_journal_printv(priority, format, ap);
87 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
89 /* FIXME: Instead of limiting things to LINE_MAX we could do a
90 C99 variable-length array on the stack here in a loop. */
92 char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
94 assert_return(priority >= 0, -EINVAL);
95 assert_return(priority <= 7, -EINVAL);
96 assert_return(format, -EINVAL);
98 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
101 memcpy(buffer, "MESSAGE=", 8);
102 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
103 char_array_0(buffer);
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) {
205 struct sockaddr_un sa = {
206 .sun_family = AF_UNIX,
207 .sun_path = "/run/systemd/journal/socket",
211 .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
215 struct cmsghdr cmsghdr;
216 uint8_t buf[CMSG_SPACE(sizeof(int))];
218 struct cmsghdr *cmsg;
219 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 temporary
307 * file and just pass a file descriptor of it to the other
310 * We use /dev/shm instead of /tmp here, since we want this to
311 * be a tmpfs, and one that is available from early boot on
312 * and where unprivileged users can create files. */
313 buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
317 n = writev(buffer_fd, w, j);
319 safe_close(buffer_fd);
327 mh.msg_control = &control;
328 mh.msg_controllen = sizeof(control);
330 cmsg = CMSG_FIRSTHDR(&mh);
331 cmsg->cmsg_level = SOL_SOCKET;
332 cmsg->cmsg_type = SCM_RIGHTS;
333 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
334 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
336 mh.msg_controllen = cmsg->cmsg_len;
338 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
339 safe_close(buffer_fd);
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[6 + 10 + 1]; /* for a 32bit value */
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 snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
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",
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));
419 if (shutdown(fd, SHUT_RD) < 0) {
424 fd_inc_sndbuf(fd, SNDBUF_SIZE);
429 l = strlen(identifier);
430 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
432 memcpy(header, identifier, l);
434 header[l++] = '\n'; /* unit id */
435 header[l++] = '0' + priority;
437 header[l++] = '0' + !!level_prefix;
446 r = loop_write(fd, header, l, false);
452 if ((size_t) r != l) {
460 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
464 va_start(ap, format);
465 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
471 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
472 char buffer[8 + LINE_MAX], p[11];
476 assert_return(priority >= 0, -EINVAL);
477 assert_return(priority <= 7, -EINVAL);
478 assert_return(format, -EINVAL);
480 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
483 memcpy(buffer, "MESSAGE=", 8);
484 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
485 char_array_0(buffer);
487 /* func is initialized from __func__ which is not a macro, but
488 * a static const char[], hence cannot easily be prefixed with
489 * CODE_FUNC=, hence let's do it manually here. */
490 ALLOCA_CODE_FUNC(f, func);
493 IOVEC_SET_STRING(iov[0], buffer);
494 IOVEC_SET_STRING(iov[1], p);
495 IOVEC_SET_STRING(iov[2], file);
496 IOVEC_SET_STRING(iov[3], line);
497 IOVEC_SET_STRING(iov[4], f);
499 return sd_journal_sendv(iov, ELEMENTSOF(iov));
502 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
505 struct iovec *iov = NULL;
508 va_start(ap, format);
509 i = fill_iovec_sprintf(format, ap, 3, &iov);
512 if (_unlikely_(i < 0)) {
517 ALLOCA_CODE_FUNC(f, func);
519 IOVEC_SET_STRING(iov[0], file);
520 IOVEC_SET_STRING(iov[1], line);
521 IOVEC_SET_STRING(iov[2], f);
523 r = sd_journal_sendv(iov, i);
526 for (j = 3; j < i; j++)
527 free(iov[j].iov_base);
534 _public_ int sd_journal_sendv_with_location(
535 const char *file, const char *line,
537 const struct iovec *iov, int n) {
542 assert_return(iov, -EINVAL);
543 assert_return(n > 0, -EINVAL);
545 niov = alloca(sizeof(struct iovec) * (n + 3));
546 memcpy(niov, iov, sizeof(struct iovec) * n);
548 ALLOCA_CODE_FUNC(f, func);
550 IOVEC_SET_STRING(niov[n++], file);
551 IOVEC_SET_STRING(niov[n++], line);
552 IOVEC_SET_STRING(niov[n++], f);
554 return sd_journal_sendv(niov, n);
557 _public_ int sd_journal_perror_with_location(
558 const char *file, const char *line,
560 const char *message) {
565 ALLOCA_CODE_FUNC(f, func);
567 IOVEC_SET_STRING(iov[0], file);
568 IOVEC_SET_STRING(iov[1], line);
569 IOVEC_SET_STRING(iov[2], f);
571 return fill_iovec_perror_and_send(message, 3, iov);