journal-send.c revision d0bbc21caa6e68693a47db60c93e99422bf2a858
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2011 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <sys/socket.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <sys/un.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stddef.h>
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "sd-journal.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* We open a single fd, and we'll share it with the current process,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * all its threads, and all its subprocesses. This means we need to
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * initialize it atomically, and need to operate on it atomically
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * never assuming we are the only user */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int journal_fd(void) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int fd;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering static int fd_plus_one = 0;
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringretry:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (fd_plus_one > 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return fd_plus_one - 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (fd < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -errno;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering close_nointr_nofail(fd);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto retry;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return fd;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint sd_journal_print(int priority, const char *format, ...) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering va_list ap;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering va_start(ap, format);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_journal_printv(priority, format, ap);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering va_end(ap);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint sd_journal_printv(int priority, const char *format, va_list ap) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char buffer[8 + LINE_MAX], p[11];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct iovec iov[2];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char_array_0(p);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen memcpy(buffer, "MESSAGE=", 8);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen char_array_0(buffer);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen zero(iov);
cab5b05903096e1c9cf5575ccc73f89d15c8db69Lennart Poettering IOVEC_SET_STRING(iov[0], buffer);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering IOVEC_SET_STRING(iov[1], p);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return sd_journal_sendv(iov, 2);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint sd_journal_send(const char *format, ...) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering int r, n = 0, i = 0, j;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering va_list ap;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering struct iovec *iov = NULL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering va_start(ap, format);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering while (format) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering struct iovec *c;
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen char *buffer;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (i >= n) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering n = MAX(i*2, 4);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt c = realloc(iov, n * sizeof(struct iovec));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (!c) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = -ENOMEM;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering goto fail;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering iov = c;
db97a66aa69925f7403ba3c433e86320d136567dLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (vasprintf(&buffer, format, ap) < 0) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = -ENOMEM;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt goto fail;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering IOVEC_SET_STRING(iov[i++], buffer);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering format = va_arg(ap, char *);
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering }
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering va_end(ap);
db97a66aa69925f7403ba3c433e86320d136567dLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = sd_journal_sendv(iov, i);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringfail:
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt for (j = 0; j < i; j++)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering free(iov[j].iov_base);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering free(iov);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering}
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poetteringint sd_journal_sendv(const struct iovec *iov, int n) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering int fd;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering struct iovec *w;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering uint64_t *l;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering int i, j = 0;
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen struct msghdr mh;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering struct sockaddr_un sa;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!iov || n <= 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering w = alloca(sizeof(struct iovec) * n * 5);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = alloca(sizeof(uint64_t) * n);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (i = 0; i < n; i++) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char *c, *nl;
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen if (!c)
cc7844e78751916acb639443c119763cafe2c684Lennart Poettering return -EINVAL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (nl) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (nl < c)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return -EINVAL;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Already includes a newline? Bummer, then
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * let's write the variable name, then a
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * newline, then the size (64bit LE), followed
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen * by the data and a final newline */
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen w[j].iov_base = iov[i].iov_base;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering w[j].iov_len = c - (char*) iov[i].iov_base;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen j++;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering IOVEC_SET_STRING(w[j++], "\n");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen w[j].iov_base = &l[i];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering w[j].iov_len = sizeof(uint64_t);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering j++;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering w[j].iov_base = c + 1;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen j++;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen } else
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Nothing special? Then just add the line and
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen * append a newline */
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen w[j++] = iov[i];
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering IOVEC_SET_STRING(w[j++], "\n");
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering fd = journal_fd();
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (fd < 0)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return fd;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering zero(sa);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sa.sun_family = AF_UNIX;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering strncpy(sa.sun_path,"/run/systemd/journal", sizeof(sa.sun_path));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen zero(mh);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen mh.msg_name = &sa;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen mh.msg_iov = w;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen mh.msg_iovlen = j;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -errno;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen return 0;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen}
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen