journal-send.c revision 44b601bc79e46722bc0f0862ee0ce34a2284ef11
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/***
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering This file is part of systemd.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Copyright 2011 Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is free software; you can redistribute it and/or modify it
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering under the terms of the GNU Lesser General Public License as published by
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (at your option) any later version.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is distributed in the hope that it will be useful, but
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Lesser General Public License for more details.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering You should have received a copy of the GNU Lesser General Public License
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering***/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <sys/socket.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <sys/un.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <errno.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <stddef.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <unistd.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <fcntl.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <printf.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#define SD_JOURNAL_SUPPRESS_LOCATION
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "sd-journal.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "socket-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#define SNDBUF_SIZE (8*1024*1024)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#define ALLOCA_CODE_FUNC(f, func) \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering do { \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering size_t _fl; \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering const char *_func = (func); \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering char **_f = &(f); \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering _fl = strlen(_func) + 1; \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering *_f = alloca(_fl + 10); \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering memcpy(*_f, "CODE_FUNC=", 10); \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering memcpy(*_f + 10, _func, _fl); \
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering } while(false)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/* We open a single fd, and we'll share it with the current process,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * all its threads, and all its subprocesses. This means we need to
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * initialize it atomically, and need to operate on it atomically
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * never assuming we are the only user */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic int journal_fd(void) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering int fd;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering static int fd_plus_one = 0;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringretry:
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (fd_plus_one > 0)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return fd_plus_one - 1;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (fd < 0)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return -errno;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering fd_inc_sndbuf(fd, SNDBUF_SIZE);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering close_nointr_nofail(fd);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering goto retry;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return fd;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering}
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering_public_ int sd_journal_print(int priority, const char *format, ...) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering int r;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_list ap;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_start(ap, format);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_journal_printv(priority, format, ap);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_end(ap);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return r;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering}
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering /* FIXME: Instead of limiting things to LINE_MAX we could do a
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering C99 variable-length array on the stack here in a loop. */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (priority < 0 || priority > 7)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return -EINVAL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (!format)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return -EINVAL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering char_array_0(p);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering memcpy(buffer, "MESSAGE=", 8);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering char_array_0(buffer);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering zero(iov);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering IOVEC_SET_STRING(iov[0], buffer);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering IOVEC_SET_STRING(iov[1], p);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return sd_journal_sendv(iov, 2);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering}
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering PROTECT_ERRNO;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering int r, n = 0, i = 0, j;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering struct iovec *iov = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering assert(_iov);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (extra > 0) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering n = MAX(extra * 2, extra + 4);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering iov = malloc0(n * sizeof(struct iovec));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (!iov) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = -ENOMEM;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering goto fail;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering i = extra;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering while (format) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering struct iovec *c;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering char *buffer;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_list aq;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (i >= n) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering n = MAX(i*2, 4);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering c = realloc(iov, n * sizeof(struct iovec));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (!c) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = -ENOMEM;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering goto fail;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering iov = c;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_copy(aq, ap);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (vasprintf(&buffer, format, aq) < 0) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_end(aq);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = -ENOMEM;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering goto fail;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_end(aq);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering VA_FORMAT_ADVANCE(format, ap);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering IOVEC_SET_STRING(iov[i++], buffer);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering format = va_arg(ap, char *);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering *_iov = iov;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return i;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringfail:
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering for (j = 0; j < i; j++)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering free(iov[j].iov_base);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering free(iov);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return r;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering}
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering_public_ int sd_journal_send(const char *format, ...) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering int r, i, j;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_list ap;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering struct iovec *iov = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_start(ap, format);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering i = fill_iovec_sprintf(format, ap, 0, &iov);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering va_end(ap);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (_unlikely_(i < 0)) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = i;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering goto finish;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_journal_sendv(iov, i);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringfinish:
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering for (j = 0; j < i; j++)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering free(iov[j].iov_base);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering free(iov);
return r;
}
_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
PROTECT_ERRNO;
int fd, buffer_fd;
struct iovec *w;
uint64_t *l;
int i, j = 0;
struct sockaddr_un sa = {
.sun_family = AF_UNIX,
.sun_path = "/run/systemd/journal/socket",
};
struct msghdr mh = {
.msg_name = &sa,
.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
};
ssize_t k;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
} control;
struct cmsghdr *cmsg;
/* We use /dev/shm instead of /tmp here, since we want this to
* be a tmpfs, and one that is available from early boot on
* and where unprivileged users can create files. */
char path[] = "/dev/shm/journal.XXXXXX";
bool have_syslog_identifier = false;
if (_unlikely_(!iov))
return -EINVAL;
if (_unlikely_(n <= 0))
return -EINVAL;
w = alloca(sizeof(struct iovec) * n * 5 + 3);
l = alloca(sizeof(uint64_t) * n);
for (i = 0; i < n; i++) {
char *c, *nl;
if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
return -EINVAL;
c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
if (_unlikely_(!c || c == iov[i].iov_base))
return -EINVAL;
have_syslog_identifier = have_syslog_identifier ||
(c == (char *) iov[i].iov_base + 17 &&
startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
if (nl) {
if (_unlikely_(nl < c))
return -EINVAL;
/* Already includes a newline? Bummer, then
* let's write the variable name, then a
* newline, then the size (64bit LE), followed
* by the data and a final newline */
w[j].iov_base = iov[i].iov_base;
w[j].iov_len = c - (char*) iov[i].iov_base;
j++;
IOVEC_SET_STRING(w[j++], "\n");
l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
w[j].iov_base = &l[i];
w[j].iov_len = sizeof(uint64_t);
j++;
w[j].iov_base = c + 1;
w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
j++;
} else
/* Nothing special? Then just add the line and
* append a newline */
w[j++] = iov[i];
IOVEC_SET_STRING(w[j++], "\n");
}
if (!have_syslog_identifier &&
string_is_safe(program_invocation_short_name)) {
/* Implicitly add program_invocation_short_name, if it
* is not set explicitly. We only do this for
* program_invocation_short_name, and nothing else
* since everything else is much nicer to retrieve
* from the outside. */
IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
IOVEC_SET_STRING(w[j++], program_invocation_short_name);
IOVEC_SET_STRING(w[j++], "\n");
}
fd = journal_fd();
if (_unlikely_(fd < 0))
return fd;
mh.msg_iov = w;
mh.msg_iovlen = j;
k = sendmsg(fd, &mh, MSG_NOSIGNAL);
if (k >= 0)
return 0;
if (errno != EMSGSIZE && errno != ENOBUFS)
return -errno;
/* Message doesn't fit... Let's dump the data in a temporary
* file and just pass a file descriptor of it to the other
* side */
buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
if (buffer_fd < 0)
return -errno;
if (unlink(path) < 0) {
close_nointr_nofail(buffer_fd);
return -errno;
}
n = writev(buffer_fd, w, j);
if (n < 0) {
close_nointr_nofail(buffer_fd);
return -errno;
}
mh.msg_iov = NULL;
mh.msg_iovlen = 0;
zero(control);
mh.msg_control = &control;
mh.msg_controllen = sizeof(control);
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
mh.msg_controllen = cmsg->cmsg_len;
k = sendmsg(fd, &mh, MSG_NOSIGNAL);
close_nointr_nofail(buffer_fd);
if (k < 0)
return -errno;
return 0;
}
static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
PROTECT_ERRNO;
size_t n, k;
k = isempty(message) ? 0 : strlen(message) + 2;
n = 8 + k + 256 + 1;
for (;;) {
char buffer[n];
char* j;
errno = 0;
j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
if (errno == 0) {
char error[6 + 10 + 1]; /* for a 32bit value */
if (j != buffer + 8 + k)
memmove(buffer + 8 + k, j, strlen(j)+1);
memcpy(buffer, "MESSAGE=", 8);
if (k > 0) {
memcpy(buffer + 8, message, k - 2);
memcpy(buffer + 8 + k - 2, ": ", 2);
}
snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
char_array_0(error);
IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
IOVEC_SET_STRING(iov[skip+1], buffer);
IOVEC_SET_STRING(iov[skip+2], error);
return sd_journal_sendv(iov, skip + 3);
}
if (errno != ERANGE)
return -errno;
n *= 2;
}
}
_public_ int sd_journal_perror(const char *message) {
struct iovec iovec[3];
return fill_iovec_perror_and_send(message, 0, iovec);
}
_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
int fd;
char *header;
size_t l;
ssize_t r;
if (priority < 0 || priority > 7)
return -EINVAL;
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
if (r < 0) {
close_nointr_nofail(fd);
return -errno;
}
if (shutdown(fd, SHUT_RD) < 0) {
close_nointr_nofail(fd);
return -errno;
}
fd_inc_sndbuf(fd, SNDBUF_SIZE);
if (!identifier)
identifier = "";
l = strlen(identifier);
header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
memcpy(header, identifier, l);
header[l++] = '\n';
header[l++] = '\n'; /* unit id */
header[l++] = '0' + priority;
header[l++] = '\n';
header[l++] = '0' + !!level_prefix;
header[l++] = '\n';
header[l++] = '0';
header[l++] = '\n';
header[l++] = '0';
header[l++] = '\n';
header[l++] = '0';
header[l++] = '\n';
r = loop_write(fd, header, l, false);
if (r < 0) {
close_nointr_nofail(fd);
return (int) r;
}
if ((size_t) r != l) {
close_nointr_nofail(fd);
return -errno;
}
return fd;
}
_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
int r;
va_list ap;
va_start(ap, format);
r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
va_end(ap);
return r;
}
_public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
char buffer[8 + LINE_MAX], p[11];
struct iovec iov[5];
char *f;
if (priority < 0 || priority > 7)
return -EINVAL;
if (_unlikely_(!format))
return -EINVAL;
snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
char_array_0(p);
memcpy(buffer, "MESSAGE=", 8);
vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
char_array_0(buffer);
/* func is initialized from __func__ which is not a macro, but
* a static const char[], hence cannot easily be prefixed with
* CODE_FUNC=, hence let's do it manually here. */
ALLOCA_CODE_FUNC(f, func);
zero(iov);
IOVEC_SET_STRING(iov[0], buffer);
IOVEC_SET_STRING(iov[1], p);
IOVEC_SET_STRING(iov[2], file);
IOVEC_SET_STRING(iov[3], line);
IOVEC_SET_STRING(iov[4], f);
return sd_journal_sendv(iov, ELEMENTSOF(iov));
}
_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
int r, i, j;
va_list ap;
struct iovec *iov = NULL;
char *f;
va_start(ap, format);
i = fill_iovec_sprintf(format, ap, 3, &iov);
va_end(ap);
if (_unlikely_(i < 0)) {
r = i;
goto finish;
}
ALLOCA_CODE_FUNC(f, func);
IOVEC_SET_STRING(iov[0], file);
IOVEC_SET_STRING(iov[1], line);
IOVEC_SET_STRING(iov[2], f);
r = sd_journal_sendv(iov, i);
finish:
for (j = 3; j < i; j++)
free(iov[j].iov_base);
free(iov);
return r;
}
_public_ int sd_journal_sendv_with_location(
const char *file, const char *line,
const char *func,
const struct iovec *iov, int n) {
struct iovec *niov;
char *f;
if (_unlikely_(!iov))
return -EINVAL;
if (_unlikely_(n <= 0))
return -EINVAL;
niov = alloca(sizeof(struct iovec) * (n + 3));
memcpy(niov, iov, sizeof(struct iovec) * n);
ALLOCA_CODE_FUNC(f, func);
IOVEC_SET_STRING(niov[n++], file);
IOVEC_SET_STRING(niov[n++], line);
IOVEC_SET_STRING(niov[n++], f);
return sd_journal_sendv(niov, n);
}
_public_ int sd_journal_perror_with_location(
const char *file, const char *line,
const char *func,
const char *message) {
struct iovec iov[6];
char *f;
ALLOCA_CODE_FUNC(f, func);
IOVEC_SET_STRING(iov[0], file);
IOVEC_SET_STRING(iov[1], line);
IOVEC_SET_STRING(iov[2], f);
return fill_iovec_perror_and_send(message, 3, iov);
}