journald-stream.c revision e14ddf1cac12f91685cbd5dac6c5127f8cf87863
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers/***
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers This file is part of systemd.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers Copyright 2011 Lennart Poettering
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers systemd is free software; you can redistribute it and/or modify it
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers under the terms of the GNU Lesser General Public License as published by
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers the Free Software Foundation; either version 2.1 of the License, or
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers (at your option) any later version.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers systemd is distributed in the hope that it will be useful, but
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers Lesser General Public License for more details.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers You should have received a copy of the GNU Lesser General Public License
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers***/
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2bdbf32183fc6816cf34f4850e9fc5f070a34303Marcel Holtmann#include <fcntl.h>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include <unistd.h>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include <stddef.h>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include <sys/epoll.h>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#ifdef HAVE_SELINUX
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include <selinux/selinux.h>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#endif
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "socket-util.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "journald-server.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "journald-stream.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "journald-syslog.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "journald-kmsg.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "journald-console.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#define STDOUT_STREAMS_MAX 4096
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieverstypedef enum StdoutStreamState {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_IDENTIFIER,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_UNIT_ID,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_PRIORITY,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_LEVEL_PREFIX,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_FORWARD_TO_SYSLOG,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_FORWARD_TO_KMSG,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_FORWARD_TO_CONSOLE,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STDOUT_STREAM_RUNNING
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers} StdoutStreamState;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstruct StdoutStream {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers Server *server;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers StdoutStreamState state;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int fd;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers struct ucred ucred;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#ifdef HAVE_SELINUX
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers security_context_t security_context;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#endif
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char *identifier;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char *unit_id;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int priority;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers bool level_prefix:1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers bool forward_to_syslog:1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers bool forward_to_kmsg:1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers bool forward_to_console:1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char buffer[LINE_MAX+1];
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers size_t length;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers LIST_FIELDS(StdoutStream, stdout_stream);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers};
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic int stdout_stream_log(StdoutStream *s, const char *p) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers struct iovec iovec[N_IOVEC_META_FIELDS + 5];
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers unsigned n = 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int priority;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char *label = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers size_t label_len = 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(s);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (isempty(p))
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers priority = s->priority;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->level_prefix)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers syslog_parse_priority((char**) &p, &priority);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->forward_to_syslog || s->server->forward_to_syslog)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->forward_to_kmsg || s->server->forward_to_kmsg)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
7c5925a448551129ec2e11157c847703def79608Zbigniew Jędrzejewski-Szmek
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->forward_to_console || s->server->forward_to_console)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers IOVEC_SET_STRING(iovec[n++], syslog_priority);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (priority & LOG_FACMASK)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers IOVEC_SET_STRING(iovec[n++], syslog_facility);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->identifier) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (syslog_identifier)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers IOVEC_SET_STRING(iovec[n++], syslog_identifier);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers message = strappend("MESSAGE=", p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (message)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers IOVEC_SET_STRING(iovec[n++], message);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#ifdef HAVE_SELINUX
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->security_context) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers label = (char*) s->security_context;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers label_len = strlen((char*) s->security_context);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#endif
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(message);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(syslog_priority);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(syslog_facility);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(syslog_identifier);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic int stdout_stream_line(StdoutStream *s, char *p) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(s);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers p = strstrip(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers switch (s->state) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_IDENTIFIER:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (isempty(p))
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->identifier = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers else {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->identifier = strdup(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!s->identifier)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return log_oom();
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->state = STDOUT_STREAM_UNIT_ID;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_UNIT_ID:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->ucred.uid == 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (isempty(p))
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->unit_id = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers else {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->unit_id = strdup(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!s->unit_id)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return log_oom();
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->state = STDOUT_STREAM_PRIORITY;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_PRIORITY:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = safe_atoi(p, &s->priority);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0 || s->priority < 0 || s->priority >= 999) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Failed to parse log priority line.");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -EINVAL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->state = STDOUT_STREAM_LEVEL_PREFIX;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_LEVEL_PREFIX:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = parse_boolean(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Failed to parse level prefix line.");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -EINVAL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->level_prefix = !!r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_FORWARD_TO_SYSLOG:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = parse_boolean(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Failed to parse forward to syslog line.");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -EINVAL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->forward_to_syslog = !!r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_FORWARD_TO_KMSG:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = parse_boolean(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Failed to parse copy to kmsg line.");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -EINVAL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->forward_to_kmsg = !!r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_FORWARD_TO_CONSOLE:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = parse_boolean(p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Failed to parse copy to console line.");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -EINVAL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->forward_to_console = !!r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->state = STDOUT_STREAM_RUNNING;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers case STDOUT_STREAM_RUNNING:
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return stdout_stream_log(s, p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert_not_reached("Unknown stream state");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic int stdout_stream_scan(StdoutStream *s, bool force_flush) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char *p;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers size_t remaining;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(s);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers p = s->buffer;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers remaining = s->length;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers for (;;) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char *end;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers size_t skip;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers end = memchr(p, '\n', remaining);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (end)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers skip = end - p + 1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers else if (remaining >= sizeof(s->buffer) - 1) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers end = p + sizeof(s->buffer) - 1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers skip = remaining;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers } else
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers break;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers *end = 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = stdout_stream_line(s, p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers remaining -= skip;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers p += skip;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (force_flush && remaining > 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers p[remaining] = 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = stdout_stream_line(s, p);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers p += remaining;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers remaining = 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (p > s->buffer) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers memmove(s->buffer, p, remaining);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->length = remaining;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversint stdout_stream_process(StdoutStream *s) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers ssize_t l;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(s);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (l < 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (errno == EAGAIN)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Failed to read from stream: %m");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -errno;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (l == 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = stdout_stream_scan(s, true);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s->length += l;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = stdout_stream_scan(s, false);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversvoid stdout_stream_free(StdoutStream *s) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(s);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (s->server) {
assert(s->server->n_stdout_streams > 0);
s->server->n_stdout_streams --;
LIST_REMOVE(StdoutStream, stdout_stream, s->server->stdout_streams, s);
}
if (s->fd >= 0) {
if (s->server)
epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
close_nointr_nofail(s->fd);
}
#ifdef HAVE_SELINUX
if (s->security_context)
freecon(s->security_context);
#endif
free(s->identifier);
free(s);
}
int stdout_stream_new(Server *s) {
StdoutStream *stream;
int fd, r;
socklen_t len;
struct epoll_event ev;
assert(s);
fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (fd < 0) {
if (errno == EAGAIN)
return 0;
log_error("Failed to accept stdout connection: %m");
return -errno;
}
if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
log_warning("Too many stdout streams, refusing connection.");
close_nointr_nofail(fd);
return 0;
}
stream = new0(StdoutStream, 1);
if (!stream) {
close_nointr_nofail(fd);
return log_oom();
}
stream->fd = fd;
len = sizeof(stream->ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
log_error("Failed to determine peer credentials: %m");
r = -errno;
goto fail;
}
#ifdef HAVE_SELINUX
if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
log_error("Failed to determine peer security context: %m");
#endif
if (shutdown(fd, SHUT_WR) < 0) {
log_error("Failed to shutdown writing side of socket: %m");
r = -errno;
goto fail;
}
zero(ev);
ev.data.ptr = stream;
ev.events = EPOLLIN;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
log_error("Failed to add stream to event loop: %m");
r = -errno;
goto fail;
}
stream->server = s;
LIST_PREPEND(StdoutStream, stdout_stream, s->stdout_streams, stream);
s->n_stdout_streams ++;
return 0;
fail:
stdout_stream_free(stream);
return r;
}
int server_open_stdout_socket(Server *s) {
union sockaddr_union sa;
int r;
struct epoll_event ev;
assert(s);
if (s->stdout_fd < 0) {
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0) {
log_error("socket() failed: %m");
return -errno;
}
zero(sa);
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
unlink(sa.un.sun_path);
r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
if (r < 0) {
log_error("bind() failed: %m");
return -errno;
}
chmod(sa.un.sun_path, 0666);
if (listen(s->stdout_fd, SOMAXCONN) < 0) {
log_error("liste() failed: %m");
return -errno;
}
} else
fd_nonblock(s->stdout_fd, 1);
zero(ev);
ev.events = EPOLLIN;
ev.data.fd = s->stdout_fd;
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) {
log_error("Failed to add stdout server fd to epoll object: %m");
return -errno;
}
return 0;
}