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>
29 #define SD_JOURNAL_SUPPRESS_LOCATION
31 #include "sd-journal.h"
33 #include "socket-util.h"
35 #define SNDBUF_SIZE (8*1024*1024)
37 /* We open a single fd, and we'll share it with the current process,
38 * all its threads, and all its subprocesses. This means we need to
39 * initialize it atomically, and need to operate on it atomically
40 * never assuming we are the only user */
42 static int journal_fd(void) {
44 static int fd_plus_one = 0;
48 return fd_plus_one - 1;
50 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
54 fd_inc_sndbuf(fd, SNDBUF_SIZE);
56 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
57 close_nointr_nofail(fd);
64 _public_ int sd_journal_print(int priority, const char *format, ...) {
69 r = sd_journal_printv(priority, format, ap);
75 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
77 /* FIXME: Instead of limiting things to LINE_MAX we could do a
78 C99 variable-length array on the stack here in a loop. */
80 char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
82 if (priority < 0 || priority > 7)
88 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
91 memcpy(buffer, "MESSAGE=", 8);
92 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
96 IOVEC_SET_STRING(iov[0], buffer);
97 IOVEC_SET_STRING(iov[1], p);
99 return sd_journal_sendv(iov, 2);
102 static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
103 int r, n = 0, i = 0, j;
104 struct iovec *iov = NULL;
111 n = MAX(extra * 2, extra + 4);
112 iov = malloc0(n * sizeof(struct iovec));
127 c = realloc(iov, n * sizeof(struct iovec));
136 if (vasprintf(&buffer, format, ap) < 0) {
141 IOVEC_SET_STRING(iov[i++], buffer);
143 format = va_arg(ap, char *);
152 for (j = 0; j < i; j++)
153 free(iov[j].iov_base);
161 _public_ int sd_journal_send(const char *format, ...) {
164 struct iovec *iov = NULL;
166 va_start(ap, format);
167 i = fill_iovec_sprintf(format, ap, 0, &iov);
170 if (_unlikely_(i < 0)) {
175 r = sd_journal_sendv(iov, i);
178 for (j = 0; j < i; j++)
179 free(iov[j].iov_base);
186 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
192 struct sockaddr_un sa;
196 struct cmsghdr cmsghdr;
197 uint8_t buf[CMSG_SPACE(sizeof(int))];
199 struct cmsghdr *cmsg;
200 /* We use /dev/shm instead of /tmp here, since we want this to
201 * be a tmpfs, and one that is available from early boot on
202 * and where unprivileged users can create files. */
203 char path[] = "/dev/shm/journal.XXXXXX";
205 if (_unlikely_(!iov))
208 if (_unlikely_(n <= 0))
213 w = alloca(sizeof(struct iovec) * n * 5);
214 l = alloca(sizeof(uint64_t) * n);
216 for (i = 0; i < n; i++) {
219 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
224 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
225 if (_unlikely_(!c || c == iov[i].iov_base)) {
230 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
232 if (_unlikely_(nl < c)) {
237 /* Already includes a newline? Bummer, then
238 * let's write the variable name, then a
239 * newline, then the size (64bit LE), followed
240 * by the data and a final newline */
242 w[j].iov_base = iov[i].iov_base;
243 w[j].iov_len = c - (char*) iov[i].iov_base;
246 IOVEC_SET_STRING(w[j++], "\n");
248 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
249 w[j].iov_base = &l[i];
250 w[j].iov_len = sizeof(uint64_t);
253 w[j].iov_base = c + 1;
254 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
258 /* Nothing special? Then just add the line and
259 * append a newline */
262 IOVEC_SET_STRING(w[j++], "\n");
266 if (_unlikely_(fd < 0)) {
272 sa.sun_family = AF_UNIX;
273 strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
277 mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
281 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
287 if (errno != EMSGSIZE && errno != ENOBUFS) {
292 /* Message doesn't fit... Let's dump the data in a temporary
293 * file and just pass a file descriptor of it to the other
296 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
302 if (unlink(path) < 0) {
303 close_nointr_nofail(buffer_fd);
308 n = writev(buffer_fd, w, j);
310 close_nointr_nofail(buffer_fd);
319 mh.msg_control = &control;
320 mh.msg_controllen = sizeof(control);
322 cmsg = CMSG_FIRSTHDR(&mh);
323 cmsg->cmsg_level = SOL_SOCKET;
324 cmsg->cmsg_type = SCM_RIGHTS;
325 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
326 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
328 mh.msg_controllen = cmsg->cmsg_len;
330 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
331 close_nointr_nofail(buffer_fd);
346 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
352 k = isempty(message) ? 0 : strlen(message) + 2;
360 j = strerror_r(saved_errno, buffer + 8 + k, n - 8 - k);
362 char error[6 + 10 + 1]; /* for a 32bit value */
364 if (j != buffer + 8 + k)
365 memmove(buffer + 8 + k, j, strlen(j)+1);
367 memcpy(buffer, "MESSAGE=", 8);
370 memcpy(buffer + 8, message, k - 2);
371 memcpy(buffer + 8 + k - 2, ": ", 2);
374 snprintf(error, sizeof(error), "ERRNO=%u", saved_errno);
377 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
378 IOVEC_SET_STRING(iov[skip+1], buffer);
379 IOVEC_SET_STRING(iov[skip+2], error);
381 r = sd_journal_sendv(iov, skip + 3);
387 if (errno != ERANGE) {
397 _public_ int sd_journal_perror(const char *message) {
398 struct iovec iovec[3];
400 return fill_iovec_perror_and_send(message, 0, iovec);
403 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
404 union sockaddr_union sa;
410 if (priority < 0 || priority > 7)
413 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
418 sa.un.sun_family = AF_UNIX;
419 strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
421 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
423 close_nointr_nofail(fd);
427 if (shutdown(fd, SHUT_RD) < 0) {
428 close_nointr_nofail(fd);
432 fd_inc_sndbuf(fd, SNDBUF_SIZE);
437 l = strlen(identifier);
438 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
440 memcpy(header, identifier, l);
442 header[l++] = '\n'; /* unit id */
443 header[l++] = '0' + priority;
445 header[l++] = '0' + !!level_prefix;
454 r = loop_write(fd, header, l, false);
456 close_nointr_nofail(fd);
460 if ((size_t) r != l) {
461 close_nointr_nofail(fd);
468 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
472 va_start(ap, format);
473 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
479 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
480 char buffer[8 + LINE_MAX], p[11];
485 if (priority < 0 || priority > 7)
488 if (_unlikely_(!format))
491 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
494 memcpy(buffer, "MESSAGE=", 8);
495 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
496 char_array_0(buffer);
498 /* func is initialized from __func__ which is not a macro, but
499 * a static const char[], hence cannot easily be prefixed with
500 * CODE_FUNC=, hence let's do it manually here. */
503 memcpy(f, "CODE_FUNC=", 10);
504 memcpy(f + 10, func, fl + 1);
507 IOVEC_SET_STRING(iov[0], buffer);
508 IOVEC_SET_STRING(iov[1], p);
509 IOVEC_SET_STRING(iov[2], file);
510 IOVEC_SET_STRING(iov[3], line);
511 IOVEC_SET_STRING(iov[4], f);
513 return sd_journal_sendv(iov, ELEMENTSOF(iov));
516 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
519 struct iovec *iov = NULL;
523 va_start(ap, format);
524 i = fill_iovec_sprintf(format, ap, 3, &iov);
527 if (_unlikely_(i < 0)) {
534 memcpy(f, "CODE_FUNC=", 10);
535 memcpy(f + 10, func, fl + 1);
537 IOVEC_SET_STRING(iov[0], file);
538 IOVEC_SET_STRING(iov[1], line);
539 IOVEC_SET_STRING(iov[2], f);
541 r = sd_journal_sendv(iov, i);
544 for (j = 3; j < i; j++)
545 free(iov[j].iov_base);
552 _public_ int sd_journal_sendv_with_location(
553 const char *file, const char *line,
555 const struct iovec *iov, int n) {
561 if (_unlikely_(!iov))
564 if (_unlikely_(n <= 0))
567 niov = alloca(sizeof(struct iovec) * (n + 3));
568 memcpy(niov, iov, sizeof(struct iovec) * n);
572 memcpy(f, "CODE_FUNC=", 10);
573 memcpy(f + 10, func, fl + 1);
575 IOVEC_SET_STRING(niov[n++], file);
576 IOVEC_SET_STRING(niov[n++], line);
577 IOVEC_SET_STRING(niov[n++], f);
579 return sd_journal_sendv(niov, n);
582 _public_ int sd_journal_perror_with_location(
583 const char *file, const char *line,
585 const char *message) {
593 memcpy(f, "CODE_FUNC=", 10);
594 memcpy(f + 10, func, fl + 1);
596 IOVEC_SET_STRING(iov[0], file);
597 IOVEC_SET_STRING(iov[1], line);
598 IOVEC_SET_STRING(iov[2], f);
600 return fill_iovec_perror_and_send(message, 3, iov);