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) {
76 char buffer[8 + LINE_MAX], p[11];
79 if (priority < 0 || priority > 7)
85 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
88 memcpy(buffer, "MESSAGE=", 8);
89 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
93 IOVEC_SET_STRING(iov[0], buffer);
94 IOVEC_SET_STRING(iov[1], p);
96 return sd_journal_sendv(iov, 2);
99 static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
100 int r, n = 0, i = 0, j;
101 struct iovec *iov = NULL;
108 n = MAX(extra * 2, extra + 4);
109 iov = malloc0(n * sizeof(struct iovec));
124 c = realloc(iov, n * sizeof(struct iovec));
133 if (vasprintf(&buffer, format, ap) < 0) {
138 IOVEC_SET_STRING(iov[i++], buffer);
140 format = va_arg(ap, char *);
149 for (j = 0; j < i; j++)
150 free(iov[j].iov_base);
158 _public_ int sd_journal_send(const char *format, ...) {
161 struct iovec *iov = NULL;
163 va_start(ap, format);
164 i = fill_iovec_sprintf(format, ap, 0, &iov);
167 if (_unlikely_(i < 0)) {
172 r = sd_journal_sendv(iov, i);
175 for (j = 0; j < i; j++)
176 free(iov[j].iov_base);
183 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
189 struct sockaddr_un sa;
193 struct cmsghdr cmsghdr;
194 uint8_t buf[CMSG_SPACE(sizeof(int))];
196 struct cmsghdr *cmsg;
197 /* We use /dev/shm instead of /tmp here, since we want this to
198 * be a tmpfs, and one that is available from early boot on
199 * and where unprivileged users can create files. */
200 char path[] = "/dev/shm/journal.XXXXXX";
202 if (_unlikely_(!iov))
205 if (_unlikely_(n <= 0))
210 w = alloca(sizeof(struct iovec) * n * 5);
211 l = alloca(sizeof(uint64_t) * n);
213 for (i = 0; i < n; i++) {
216 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) {
221 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
222 if (_unlikely_(!c || c == iov[i].iov_base)) {
227 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
229 if (_unlikely_(nl < c)) {
234 /* Already includes a newline? Bummer, then
235 * let's write the variable name, then a
236 * newline, then the size (64bit LE), followed
237 * by the data and a final newline */
239 w[j].iov_base = iov[i].iov_base;
240 w[j].iov_len = c - (char*) iov[i].iov_base;
243 IOVEC_SET_STRING(w[j++], "\n");
245 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
246 w[j].iov_base = &l[i];
247 w[j].iov_len = sizeof(uint64_t);
250 w[j].iov_base = c + 1;
251 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
255 /* Nothing special? Then just add the line and
256 * append a newline */
259 IOVEC_SET_STRING(w[j++], "\n");
263 if (_unlikely_(fd < 0)) {
269 sa.sun_family = AF_UNIX;
270 strncpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path));
274 mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
278 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
284 if (errno != EMSGSIZE && errno != ENOBUFS) {
289 /* Message doesn't fit... Let's dump the data in a temporary
290 * file and just pass a file descriptor of it to the other
293 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
299 if (unlink(path) < 0) {
300 close_nointr_nofail(buffer_fd);
305 n = writev(buffer_fd, w, j);
307 close_nointr_nofail(buffer_fd);
316 mh.msg_control = &control;
317 mh.msg_controllen = sizeof(control);
319 cmsg = CMSG_FIRSTHDR(&mh);
320 cmsg->cmsg_level = SOL_SOCKET;
321 cmsg->cmsg_type = SCM_RIGHTS;
322 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
323 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
325 mh.msg_controllen = cmsg->cmsg_len;
327 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
328 close_nointr_nofail(buffer_fd);
343 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
344 union sockaddr_union sa;
350 if (priority < 0 || priority > 7)
353 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
358 sa.un.sun_family = AF_UNIX;
359 strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
361 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
363 close_nointr_nofail(fd);
367 if (shutdown(fd, SHUT_RD) < 0) {
368 close_nointr_nofail(fd);
372 fd_inc_sndbuf(fd, SNDBUF_SIZE);
377 l = strlen(identifier);
378 header = alloca(l + 1 + 2 + 2 + 2 + 2 + 2);
380 memcpy(header, identifier, l);
382 header[l++] = '0' + priority;
384 header[l++] = '0' + !!level_prefix;
393 r = loop_write(fd, header, l, false);
395 close_nointr_nofail(fd);
399 if ((size_t) r != l) {
400 close_nointr_nofail(fd);
407 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
411 va_start(ap, format);
412 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
418 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
419 char buffer[8 + LINE_MAX], p[11];
424 if (priority < 0 || priority > 7)
427 if (_unlikely_(!format))
430 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
433 memcpy(buffer, "MESSAGE=", 8);
434 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
435 char_array_0(buffer);
437 /* func is initialized from __func__ which is not a macro, but
438 * a static const char[], hence cannot easily be prefixed with
439 * CODE_FUNC=, hence let's do it manually here. */
442 memcpy(f, "CODE_FUNC=", 10);
443 memcpy(f + 10, func, fl + 1);
446 IOVEC_SET_STRING(iov[0], buffer);
447 IOVEC_SET_STRING(iov[1], p);
448 IOVEC_SET_STRING(iov[2], file);
449 IOVEC_SET_STRING(iov[3], line);
450 IOVEC_SET_STRING(iov[4], f);
452 return sd_journal_sendv(iov, ELEMENTSOF(iov));
455 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
458 struct iovec *iov = NULL;
462 va_start(ap, format);
463 i = fill_iovec_sprintf(format, ap, 3, &iov);
466 if (_unlikely_(i < 0)) {
473 memcpy(f, "CODE_FUNC=", 10);
474 memcpy(f + 10, func, fl + 1);
476 IOVEC_SET_STRING(iov[0], file);
477 IOVEC_SET_STRING(iov[1], line);
478 IOVEC_SET_STRING(iov[2], f);
480 r = sd_journal_sendv(iov, i);
483 for (j = 3; j < i; j++)
484 free(iov[j].iov_base);
491 _public_ int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n) {
496 if (_unlikely_(!iov))
499 if (_unlikely_(n <= 0))
502 niov = alloca(sizeof(struct iovec) * (n + 3));
503 memcpy(niov, iov, sizeof(struct iovec) * n);
507 memcpy(f, "CODE_FUNC=", 10);
508 memcpy(f + 10, func, fl + 1);
510 IOVEC_SET_STRING(niov[n++], file);
511 IOVEC_SET_STRING(niov[n++], line);
512 IOVEC_SET_STRING(niov[n++], f);
514 return sd_journal_sendv(niov, n);