journald-stream.c revision 14c1025934e709d07948c13ca62b40c35c91d111
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer/***
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer This file is part of systemd.
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer Copyright 2011 Lennart Poettering
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer systemd is free software; you can redistribute it and/or modify it
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer under the terms of the GNU Lesser General Public License as published by
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer the Free Software Foundation; either version 2.1 of the License, or
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer (at your option) any later version.
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer systemd is distributed in the hope that it will be useful, but
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer WITHOUT ANY WARRANTY; without even the implied warranty of
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer Lesser General Public License for more details.
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer You should have received a copy of the GNU Lesser General Public License
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer along with systemd; If not, see <http://www.gnu.org/licenses/>.
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer***/
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include <fcntl.h>
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include <unistd.h>
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include <stddef.h>
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include <sys/epoll.h>
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#ifdef HAVE_SELINUX
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include <selinux/selinux.h>
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#endif
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include "socket-util.h"
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include "selinux-util.h"
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include "journald-server.h"
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include "journald-stream.h"
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include "journald-syslog.h"
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#include "journald-kmsg.h"
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek#include "journald-console.h"
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
1dc2ced4646a78b3dee9e3ea44130f938d6425bcZbigniew Jędrzejewski-Szmek#define STDOUT_STREAMS_MAX 4096
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmertypedef enum StdoutStreamState {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_IDENTIFIER,
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_UNIT_ID,
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_PRIORITY,
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_LEVEL_PREFIX,
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_FORWARD_TO_SYSLOG,
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_FORWARD_TO_KMSG,
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_FORWARD_TO_CONSOLE,
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer STDOUT_STREAM_RUNNING
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer} StdoutStreamState;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmerstruct StdoutStream {
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering Server *server;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer StdoutStreamState state;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer int fd;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer struct ucred ucred;
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering#ifdef HAVE_SELINUX
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer security_context_t security_context;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#endif
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering char *identifier;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer char *unit_id;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer int priority;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer bool level_prefix:1;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer bool forward_to_syslog:1;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer bool forward_to_kmsg:1;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer bool forward_to_console:1;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer char buffer[LINE_MAX+1];
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer size_t length;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering LIST_FIELDS(StdoutStream, stdout_stream);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer};
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poetteringstatic int stdout_stream_log(StdoutStream *s, const char *p) {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer struct iovec iovec[N_IOVEC_META_FIELDS + 5];
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering _cleanup_free_ char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer unsigned n = 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer int priority;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer char *label = NULL;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer size_t label_len = 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer assert(s);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer assert(p);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (isempty(p))
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering priority = s->priority;
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering if (s->level_prefix)
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering syslog_parse_priority((char**) &p, &priority, false);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (s->forward_to_syslog || s->server->forward_to_syslog)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (s->forward_to_kmsg || s->server->forward_to_kmsg)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (s->forward_to_console || s->server->forward_to_console)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer IOVEC_SET_STRING(iovec[n++], syslog_priority);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (priority & LOG_FACMASK)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer IOVEC_SET_STRING(iovec[n++], syslog_facility);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (s->identifier) {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (syslog_identifier)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer IOVEC_SET_STRING(iovec[n++], syslog_identifier);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer }
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer message = strappend("MESSAGE=", p);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (message)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer IOVEC_SET_STRING(iovec[n++], message);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek#ifdef HAVE_SELINUX
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (s->security_context) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek label = (char*) s->security_context;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer label_len = strlen((char*) s->security_context);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer }
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer#endif
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer}
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmekstatic int stdout_stream_line(StdoutStream *s, char *p) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek int r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek assert(s);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer assert(p);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer p = strstrip(p);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
510b857f7d1e7e8d38912890536342dd5dd647ddLennart Poettering switch (s->state) {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer case STDOUT_STREAM_IDENTIFIER:
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (isempty(p))
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer s->identifier = NULL;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer else {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer s->identifier = strdup(p);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (!s->identifier)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return log_oom();
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer }
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer s->state = STDOUT_STREAM_UNIT_ID;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer case STDOUT_STREAM_UNIT_ID:
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (s->ucred.uid == 0) {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (isempty(p))
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer s->unit_id = NULL;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer else {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer s->unit_id = strdup(p);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (!s->unit_id)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return log_oom();
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer }
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer }
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer s->state = STDOUT_STREAM_PRIORITY;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer case STDOUT_STREAM_PRIORITY:
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer r = safe_atoi(p, &s->priority);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (r < 0 || s->priority < 0 || s->priority > 999) {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer log_warning("Failed to parse log priority line.");
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return -EINVAL;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer }
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer s->state = STDOUT_STREAM_LEVEL_PREFIX;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer case STDOUT_STREAM_LEVEL_PREFIX:
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer r = parse_boolean(p);
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (r < 0) {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer log_warning("Failed to parse level prefix line.");
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return -EINVAL;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->level_prefix = !!r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek case STDOUT_STREAM_FORWARD_TO_SYSLOG:
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek r = parse_boolean(p);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (r < 0) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek log_warning("Failed to parse forward to syslog line.");
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return -EINVAL;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->forward_to_syslog = !!r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek case STDOUT_STREAM_FORWARD_TO_KMSG:
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek r = parse_boolean(p);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (r < 0) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek log_warning("Failed to parse copy to kmsg line.");
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return -EINVAL;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->forward_to_kmsg = !!r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek case STDOUT_STREAM_FORWARD_TO_CONSOLE:
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek r = parse_boolean(p);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (r < 0) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek log_warning("Failed to parse copy to console line.");
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return -EINVAL;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->forward_to_console = !!r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->state = STDOUT_STREAM_RUNNING;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek case STDOUT_STREAM_RUNNING:
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return stdout_stream_log(s, p);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek assert_not_reached("Unknown stream state");
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek}
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmekstatic int stdout_stream_scan(StdoutStream *s, bool force_flush) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek char *p;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek size_t remaining;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek int r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek assert(s);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek p = s->buffer;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek remaining = s->length;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek for (;;) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek char *end;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek size_t skip;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek end = memchr(p, '\n', remaining);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (end)
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek skip = end - p + 1;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek else if (remaining >= sizeof(s->buffer) - 1) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek end = p + sizeof(s->buffer) - 1;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek skip = remaining;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek } else
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek break;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek *end = 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek r = stdout_stream_line(s, p);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (r < 0)
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek remaining -= skip;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek p += skip;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (force_flush && remaining > 0) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek p[remaining] = 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek r = stdout_stream_line(s, p);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (r < 0)
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek p += remaining;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek remaining = 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (p > s->buffer) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek memmove(s->buffer, p, remaining);
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek s->length = remaining;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return 0;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek}
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmerint stdout_stream_process(StdoutStream *s) {
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer ssize_t l;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek int r;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
143bfdaf0b890fa7acadf02d1eafacaef1b696bdHolger Hans Peter Freyther assert(s);
143bfdaf0b890fa7acadf02d1eafacaef1b696bdHolger Hans Peter Freyther
143bfdaf0b890fa7acadf02d1eafacaef1b696bdHolger Hans Peter Freyther l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
143bfdaf0b890fa7acadf02d1eafacaef1b696bdHolger Hans Peter Freyther if (l < 0) {
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek if (errno == EAGAIN)
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer return 0;
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer log_warning("Failed to read from stream: %m");
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek return -errno;
5cb24cd32bce87cc618b857c059f1187e03d2b24Zbigniew Jędrzejewski-Szmek }
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer
7a050b54b7c78717d5efb2e380623ccad2a70148Marius Vollmer if (l == 0) {
r = stdout_stream_scan(s, true);
if (r < 0)
return r;
return 0;
}
s->length += l;
r = stdout_stream_scan(s, false);
if (r < 0)
return r;
return 1;
}
void stdout_stream_free(StdoutStream *s) {
assert(s);
if (s->server) {
assert(s->server->n_stdout_streams > 0);
s->server->n_stdout_streams --;
LIST_REMOVE(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->unit_id);
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 (use_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(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) {
int r;
struct epoll_event ev;
assert(s);
if (s->stdout_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
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;
}
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("listen() 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;
}