1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/epoll.h>
28 #include <selinux/selinux.h>
31 #include "socket-util.h"
32 #include "journald-server.h"
33 #include "journald-stream.h"
34 #include "journald-syslog.h"
35 #include "journald-kmsg.h"
36 #include "journald-console.h"
38 #define STDOUT_STREAMS_MAX 4096
40 typedef enum StdoutStreamState {
41 STDOUT_STREAM_IDENTIFIER,
42 STDOUT_STREAM_UNIT_ID,
43 STDOUT_STREAM_PRIORITY,
44 STDOUT_STREAM_LEVEL_PREFIX,
45 STDOUT_STREAM_FORWARD_TO_SYSLOG,
46 STDOUT_STREAM_FORWARD_TO_KMSG,
47 STDOUT_STREAM_FORWARD_TO_CONSOLE,
53 StdoutStreamState state;
59 security_context_t security_context;
66 bool forward_to_syslog:1;
67 bool forward_to_kmsg:1;
68 bool forward_to_console:1;
70 char buffer[LINE_MAX+1];
73 LIST_FIELDS(StdoutStream, stdout_stream);
76 static int stdout_stream_log(StdoutStream *s, const char *p) {
77 struct iovec iovec[N_IOVEC_META_FIELDS + 5];
78 char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
90 priority = s->priority;
93 syslog_parse_priority((char**) &p, &priority, false);
95 if (s->forward_to_syslog || s->server->forward_to_syslog)
96 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
98 if (s->forward_to_kmsg || s->server->forward_to_kmsg)
99 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
101 if (s->forward_to_console || s->server->forward_to_console)
102 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
104 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
106 if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
107 IOVEC_SET_STRING(iovec[n++], syslog_priority);
109 if (priority & LOG_FACMASK)
110 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
111 IOVEC_SET_STRING(iovec[n++], syslog_facility);
114 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
115 if (syslog_identifier)
116 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
119 message = strappend("MESSAGE=", p);
121 IOVEC_SET_STRING(iovec[n++], message);
124 if (s->security_context) {
125 label = (char*) s->security_context;
126 label_len = strlen((char*) s->security_context);
130 server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
133 free(syslog_priority);
134 free(syslog_facility);
135 free(syslog_identifier);
140 static int stdout_stream_line(StdoutStream *s, char *p) {
150 case STDOUT_STREAM_IDENTIFIER:
152 s->identifier = NULL;
154 s->identifier = strdup(p);
159 s->state = STDOUT_STREAM_UNIT_ID;
162 case STDOUT_STREAM_UNIT_ID:
163 if (s->ucred.uid == 0) {
167 s->unit_id = strdup(p);
173 s->state = STDOUT_STREAM_PRIORITY;
176 case STDOUT_STREAM_PRIORITY:
177 r = safe_atoi(p, &s->priority);
178 if (r < 0 || s->priority < 0 || s->priority > 999) {
179 log_warning("Failed to parse log priority line.");
183 s->state = STDOUT_STREAM_LEVEL_PREFIX;
186 case STDOUT_STREAM_LEVEL_PREFIX:
187 r = parse_boolean(p);
189 log_warning("Failed to parse level prefix line.");
193 s->level_prefix = !!r;
194 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
197 case STDOUT_STREAM_FORWARD_TO_SYSLOG:
198 r = parse_boolean(p);
200 log_warning("Failed to parse forward to syslog line.");
204 s->forward_to_syslog = !!r;
205 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
208 case STDOUT_STREAM_FORWARD_TO_KMSG:
209 r = parse_boolean(p);
211 log_warning("Failed to parse copy to kmsg line.");
215 s->forward_to_kmsg = !!r;
216 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
219 case STDOUT_STREAM_FORWARD_TO_CONSOLE:
220 r = parse_boolean(p);
222 log_warning("Failed to parse copy to console line.");
226 s->forward_to_console = !!r;
227 s->state = STDOUT_STREAM_RUNNING;
230 case STDOUT_STREAM_RUNNING:
231 return stdout_stream_log(s, p);
234 assert_not_reached("Unknown stream state");
237 static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
245 remaining = s->length;
250 end = memchr(p, '\n', remaining);
253 else if (remaining >= sizeof(s->buffer) - 1) {
254 end = p + sizeof(s->buffer) - 1;
261 r = stdout_stream_line(s, p);
269 if (force_flush && remaining > 0) {
271 r = stdout_stream_line(s, p);
280 memmove(s->buffer, p, remaining);
281 s->length = remaining;
287 int stdout_stream_process(StdoutStream *s) {
293 l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
299 log_warning("Failed to read from stream: %m");
304 r = stdout_stream_scan(s, true);
312 r = stdout_stream_scan(s, false);
320 void stdout_stream_free(StdoutStream *s) {
324 assert(s->server->n_stdout_streams > 0);
325 s->server->n_stdout_streams --;
326 LIST_REMOVE(StdoutStream, stdout_stream, s->server->stdout_streams, s);
331 epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
333 close_nointr_nofail(s->fd);
337 if (s->security_context)
338 freecon(s->security_context);
345 int stdout_stream_new(Server *s) {
346 StdoutStream *stream;
349 struct epoll_event ev;
353 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
358 log_error("Failed to accept stdout connection: %m");
362 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
363 log_warning("Too many stdout streams, refusing connection.");
364 close_nointr_nofail(fd);
368 stream = new0(StdoutStream, 1);
370 close_nointr_nofail(fd);
376 len = sizeof(stream->ucred);
377 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
378 log_error("Failed to determine peer credentials: %m");
384 if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
385 log_error("Failed to determine peer security context: %m");
388 if (shutdown(fd, SHUT_WR) < 0) {
389 log_error("Failed to shutdown writing side of socket: %m");
395 ev.data.ptr = stream;
397 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
398 log_error("Failed to add stream to event loop: %m");
404 LIST_PREPEND(StdoutStream, stdout_stream, s->stdout_streams, stream);
405 s->n_stdout_streams ++;
410 stdout_stream_free(stream);
414 int server_open_stdout_socket(Server *s) {
416 struct epoll_event ev;
420 if (s->stdout_fd < 0) {
421 union sockaddr_union sa = {
422 .un.sun_family = AF_UNIX,
423 .un.sun_path = "/run/systemd/journal/stdout",
426 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
427 if (s->stdout_fd < 0) {
428 log_error("socket() failed: %m");
432 unlink(sa.un.sun_path);
434 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
436 log_error("bind() failed: %m");
440 chmod(sa.un.sun_path, 0666);
442 if (listen(s->stdout_fd, SOMAXCONN) < 0) {
443 log_error("listen() failed: %m");
447 fd_nonblock(s->stdout_fd, 1);
451 ev.data.fd = s->stdout_fd;
452 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) {
453 log_error("Failed to add stdout server fd to epoll object: %m");