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 /* We open a single fd, and we'll share it with the current process,
39 * all its threads, and all its subprocesses. This means we need to
40 * initialize it atomically, and need to operate on it atomically
41 * never assuming we are the only user */
43 static int journal_fd(void) {
45 static int fd_plus_one = 0;
49 return fd_plus_one - 1;
51 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
55 fd_inc_sndbuf(fd, SNDBUF_SIZE);
57 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
58 close_nointr_nofail(fd);
65 _public_ int sd_journal_print(int priority, const char *format, ...) {
70 r = sd_journal_printv(priority, format, ap);
76 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
78 /* FIXME: Instead of limiting things to LINE_MAX we could do a
79 C99 variable-length array on the stack here in a loop. */
81 char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
83 if (priority < 0 || priority > 7)
89 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
92 memcpy(buffer, "MESSAGE=", 8);
93 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
97 IOVEC_SET_STRING(iov[0], buffer);
98 IOVEC_SET_STRING(iov[1], p);
100 return sd_journal_sendv(iov, 2);
103 static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
104 int r, n = 0, i = 0, j;
105 struct iovec *iov = NULL;
112 n = MAX(extra * 2, extra + 4);
113 iov = malloc0(n * sizeof(struct iovec));
129 c = realloc(iov, n * sizeof(struct iovec));
139 if (vasprintf(&buffer, format, aq) < 0) {
146 VA_FORMAT_ADVANCE(format, ap);
148 IOVEC_SET_STRING(iov[i++], buffer);
150 format = va_arg(ap, char *);
159 for (j = 0; j < i; j++)
160 free(iov[j].iov_base);
168 _public_ int sd_journal_send(const char *format, ...) {
171 struct iovec *iov = NULL;
173 va_start(ap, format);
174 i = fill_iovec_sprintf(format, ap, 0, &iov);
177 if (_unlikely_(i < 0)) {
182 r = sd_journal_sendv(iov, i);
185 for (j = 0; j < i; j++)
186 free(iov[j].iov_base);
193 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
199 struct sockaddr_un sa;
203 struct cmsghdr cmsghdr;
204 uint8_t buf[CMSG_SPACE(sizeof(int))];
206 struct cmsghdr *cmsg;
207 /* We use /dev/shm instead of /tmp here, since we want this to
208 * be a tmpfs, and one that is available from early boot on
209 * and where unprivileged users can create files. */
210 char path[] = "/dev/shm/journal.XXXXXX";
212 if (_unlikely_(!iov))
215 if (_unlikely_(n <= 0))
220 w = alloca(sizeof(struct iovec) * n * 5);
221 l = alloca(sizeof(uint64_t) * n);
223 for (i = 0; i < n; i++) {
226 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
231 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
232 if (_unlikely_(!c || c == iov[i].iov_base)) {
237 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
239 if (_unlikely_(nl < c)) {
244 /* Already includes a newline? Bummer, then
245 * let's write the variable name, then a
246 * newline, then the size (64bit LE), followed
247 * by the data and a final newline */
249 w[j].iov_base = iov[i].iov_base;
250 w[j].iov_len = c - (char*) iov[i].iov_base;
253 IOVEC_SET_STRING(w[j++], "\n");
255 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
256 w[j].iov_base = &l[i];
257 w[j].iov_len = sizeof(uint64_t);
260 w[j].iov_base = c + 1;
261 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
265 /* Nothing special? Then just add the line and
266 * append a newline */
269 IOVEC_SET_STRING(w[j++], "\n");
273 if (_unlikely_(fd < 0)) {
279 sa.sun_family = AF_UNIX;
280 strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
284 mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
288 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
294 if (errno != EMSGSIZE && errno != ENOBUFS) {
299 /* Message doesn't fit... Let's dump the data in a temporary
300 * file and just pass a file descriptor of it to the other
303 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
309 if (unlink(path) < 0) {
310 close_nointr_nofail(buffer_fd);
315 n = writev(buffer_fd, w, j);
317 close_nointr_nofail(buffer_fd);
326 mh.msg_control = &control;
327 mh.msg_controllen = sizeof(control);
329 cmsg = CMSG_FIRSTHDR(&mh);
330 cmsg->cmsg_level = SOL_SOCKET;
331 cmsg->cmsg_type = SCM_RIGHTS;
332 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
333 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
335 mh.msg_controllen = cmsg->cmsg_len;
337 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
338 close_nointr_nofail(buffer_fd);
353 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
359 k = isempty(message) ? 0 : strlen(message) + 2;
367 j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
369 char error[6 + 10 + 1]; /* for a 32bit value */
371 if (j != buffer + 8 + k)
372 memmove(buffer + 8 + k, j, strlen(j)+1);
374 memcpy(buffer, "MESSAGE=", 8);
377 memcpy(buffer + 8, message, k - 2);
378 memcpy(buffer + 8 + k - 2, ": ", 2);
381 snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
384 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
385 IOVEC_SET_STRING(iov[skip+1], buffer);
386 IOVEC_SET_STRING(iov[skip+2], error);
388 r = sd_journal_sendv(iov, skip + 3);
394 if (errno != ERANGE) {
404 _public_ int sd_journal_perror(const char *message) {
405 struct iovec iovec[3];
407 return fill_iovec_perror_and_send(message, 0, iovec);
410 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
411 union sockaddr_union sa;
417 if (priority < 0 || priority > 7)
420 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
425 sa.un.sun_family = AF_UNIX;
426 strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
428 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
430 close_nointr_nofail(fd);
434 if (shutdown(fd, SHUT_RD) < 0) {
435 close_nointr_nofail(fd);
439 fd_inc_sndbuf(fd, SNDBUF_SIZE);
444 l = strlen(identifier);
445 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
447 memcpy(header, identifier, l);
449 header[l++] = '\n'; /* unit id */
450 header[l++] = '0' + priority;
452 header[l++] = '0' + !!level_prefix;
461 r = loop_write(fd, header, l, false);
463 close_nointr_nofail(fd);
467 if ((size_t) r != l) {
468 close_nointr_nofail(fd);
475 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
479 va_start(ap, format);
480 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
486 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
487 char buffer[8 + LINE_MAX], p[11];
492 if (priority < 0 || priority > 7)
495 if (_unlikely_(!format))
498 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
501 memcpy(buffer, "MESSAGE=", 8);
502 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
503 char_array_0(buffer);
505 /* func is initialized from __func__ which is not a macro, but
506 * a static const char[], hence cannot easily be prefixed with
507 * CODE_FUNC=, hence let's do it manually here. */
508 fl = strlen(func) + 1;
510 memcpy(f, "CODE_FUNC=", 10);
511 memcpy(f + 10, func, fl);
514 IOVEC_SET_STRING(iov[0], buffer);
515 IOVEC_SET_STRING(iov[1], p);
516 IOVEC_SET_STRING(iov[2], file);
517 IOVEC_SET_STRING(iov[3], line);
518 IOVEC_SET_STRING(iov[4], f);
520 return sd_journal_sendv(iov, ELEMENTSOF(iov));
523 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
526 struct iovec *iov = NULL;
530 va_start(ap, format);
531 i = fill_iovec_sprintf(format, ap, 3, &iov);
534 if (_unlikely_(i < 0)) {
539 fl = strlen(func) + 1;
541 memcpy(f, "CODE_FUNC=", 10);
542 memcpy(f + 10, func, fl);
544 IOVEC_SET_STRING(iov[0], file);
545 IOVEC_SET_STRING(iov[1], line);
546 IOVEC_SET_STRING(iov[2], f);
548 r = sd_journal_sendv(iov, i);
551 for (j = 3; j < i; j++)
552 free(iov[j].iov_base);
559 _public_ int sd_journal_sendv_with_location(
560 const char *file, const char *line,
562 const struct iovec *iov, int n) {
568 if (_unlikely_(!iov))
571 if (_unlikely_(n <= 0))
574 niov = alloca(sizeof(struct iovec) * (n + 3));
575 memcpy(niov, iov, sizeof(struct iovec) * n);
577 fl = strlen(func) + 1;
579 memcpy(f, "CODE_FUNC=", 10);
580 memcpy(f + 10, func, fl);
582 IOVEC_SET_STRING(niov[n++], file);
583 IOVEC_SET_STRING(niov[n++], line);
584 IOVEC_SET_STRING(niov[n++], f);
586 return sd_journal_sendv(niov, n);
589 _public_ int sd_journal_perror_with_location(
590 const char *file, const char *line,
592 const char *message) {
598 fl = strlen(func) + 1;
600 memcpy(f, "CODE_FUNC=", 10);
601 memcpy(f + 10, func, fl);
603 IOVEC_SET_STRING(iov[0], file);
604 IOVEC_SET_STRING(iov[1], line);
605 IOVEC_SET_STRING(iov[2], f);
607 return fill_iovec_perror_and_send(message, 3, iov);