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 + 1 + 2 + 2 + 2 + 2 + 2);
380 memcpy(header, identifier, l);
383 header[l++] = '0' + priority;
385 header[l++] = '0' + !!level_prefix;
394 r = loop_write(fd, header, l, false);
396 close_nointr_nofail(fd);
400 if ((size_t) r != l) {
401 close_nointr_nofail(fd);
408 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
412 va_start(ap, format);
413 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
419 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
420 char buffer[8 + LINE_MAX], p[11];
425 if (priority < 0 || priority > 7)
428 if (_unlikely_(!format))
431 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
434 memcpy(buffer, "MESSAGE=", 8);
435 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
436 char_array_0(buffer);
438 /* func is initialized from __func__ which is not a macro, but
439 * a static const char[], hence cannot easily be prefixed with
440 * CODE_FUNC=, hence let's do it manually here. */
443 memcpy(f, "CODE_FUNC=", 10);
444 memcpy(f + 10, func, fl + 1);
447 IOVEC_SET_STRING(iov[0], buffer);
448 IOVEC_SET_STRING(iov[1], p);
449 IOVEC_SET_STRING(iov[2], file);
450 IOVEC_SET_STRING(iov[3], line);
451 IOVEC_SET_STRING(iov[4], f);
453 return sd_journal_sendv(iov, ELEMENTSOF(iov));
456 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
459 struct iovec *iov = NULL;
463 va_start(ap, format);
464 i = fill_iovec_sprintf(format, ap, 3, &iov);
467 if (_unlikely_(i < 0)) {
474 memcpy(f, "CODE_FUNC=", 10);
475 memcpy(f + 10, func, fl + 1);
477 IOVEC_SET_STRING(iov[0], file);
478 IOVEC_SET_STRING(iov[1], line);
479 IOVEC_SET_STRING(iov[2], f);
481 r = sd_journal_sendv(iov, i);
484 for (j = 3; j < i; j++)
485 free(iov[j].iov_base);
492 _public_ int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n) {
497 if (_unlikely_(!iov))
500 if (_unlikely_(n <= 0))
503 niov = alloca(sizeof(struct iovec) * (n + 3));
504 memcpy(niov, iov, sizeof(struct iovec) * n);
508 memcpy(f, "CODE_FUNC=", 10);
509 memcpy(f + 10, func, fl + 1);
511 IOVEC_SET_STRING(niov[n++], file);
512 IOVEC_SET_STRING(niov[n++], line);
513 IOVEC_SET_STRING(niov[n++], f);
515 return sd_journal_sendv(niov, n);