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 "selinux-util.h"
33 #include "journald-server.h"
34 #include "journald-stream.h"
35 #include "journald-syslog.h"
36 #include "journald-kmsg.h"
37 #include "journald-console.h"
39 #define STDOUT_STREAMS_MAX 4096
41 typedef enum StdoutStreamState {
42 STDOUT_STREAM_IDENTIFIER,
43 STDOUT_STREAM_UNIT_ID,
44 STDOUT_STREAM_PRIORITY,
45 STDOUT_STREAM_LEVEL_PREFIX,
46 STDOUT_STREAM_FORWARD_TO_SYSLOG,
47 STDOUT_STREAM_FORWARD_TO_KMSG,
48 STDOUT_STREAM_FORWARD_TO_CONSOLE,
54 StdoutStreamState state;
60 security_context_t security_context;
67 bool forward_to_syslog:1;
68 bool forward_to_kmsg:1;
69 bool forward_to_console:1;
71 char buffer[LINE_MAX+1];
74 LIST_FIELDS(StdoutStream, stdout_stream);
77 static int stdout_stream_log(StdoutStream *s, const char *p) {
78 struct iovec iovec[N_IOVEC_META_FIELDS + 5];
79 char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
91 priority = s->priority;
94 syslog_parse_priority((char**) &p, &priority, false);
96 if (s->forward_to_syslog || s->server->forward_to_syslog)
97 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
99 if (s->forward_to_kmsg || s->server->forward_to_kmsg)
100 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
102 if (s->forward_to_console || s->server->forward_to_console)
103 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
105 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
107 if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
108 IOVEC_SET_STRING(iovec[n++], syslog_priority);
110 if (priority & LOG_FACMASK)
111 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
112 IOVEC_SET_STRING(iovec[n++], syslog_facility);
115 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
116 if (syslog_identifier)
117 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
120 message = strappend("MESSAGE=", p);
122 IOVEC_SET_STRING(iovec[n++], message);
125 if (s->security_context) {
126 label = (char*) s->security_context;
127 label_len = strlen((char*) s->security_context);
131 server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
134 free(syslog_priority);
135 free(syslog_facility);
136 free(syslog_identifier);
141 static int stdout_stream_line(StdoutStream *s, char *p) {
151 case STDOUT_STREAM_IDENTIFIER:
153 s->identifier = NULL;
155 s->identifier = strdup(p);
160 s->state = STDOUT_STREAM_UNIT_ID;
163 case STDOUT_STREAM_UNIT_ID:
164 if (s->ucred.uid == 0) {
168 s->unit_id = strdup(p);
174 s->state = STDOUT_STREAM_PRIORITY;
177 case STDOUT_STREAM_PRIORITY:
178 r = safe_atoi(p, &s->priority);
179 if (r < 0 || s->priority < 0 || s->priority > 999) {
180 log_warning("Failed to parse log priority line.");
184 s->state = STDOUT_STREAM_LEVEL_PREFIX;
187 case STDOUT_STREAM_LEVEL_PREFIX:
188 r = parse_boolean(p);
190 log_warning("Failed to parse level prefix line.");
194 s->level_prefix = !!r;
195 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
198 case STDOUT_STREAM_FORWARD_TO_SYSLOG:
199 r = parse_boolean(p);
201 log_warning("Failed to parse forward to syslog line.");
205 s->forward_to_syslog = !!r;
206 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
209 case STDOUT_STREAM_FORWARD_TO_KMSG:
210 r = parse_boolean(p);
212 log_warning("Failed to parse copy to kmsg line.");
216 s->forward_to_kmsg = !!r;
217 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
220 case STDOUT_STREAM_FORWARD_TO_CONSOLE:
221 r = parse_boolean(p);
223 log_warning("Failed to parse copy to console line.");
227 s->forward_to_console = !!r;
228 s->state = STDOUT_STREAM_RUNNING;
231 case STDOUT_STREAM_RUNNING:
232 return stdout_stream_log(s, p);
235 assert_not_reached("Unknown stream state");
238 static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
246 remaining = s->length;
251 end = memchr(p, '\n', remaining);
254 else if (remaining >= sizeof(s->buffer) - 1) {
255 end = p + sizeof(s->buffer) - 1;
262 r = stdout_stream_line(s, p);
270 if (force_flush && remaining > 0) {
272 r = stdout_stream_line(s, p);
281 memmove(s->buffer, p, remaining);
282 s->length = remaining;
288 int stdout_stream_process(StdoutStream *s) {
294 l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
300 log_warning("Failed to read from stream: %m");
305 r = stdout_stream_scan(s, true);
313 r = stdout_stream_scan(s, false);
321 void stdout_stream_free(StdoutStream *s) {
325 assert(s->server->n_stdout_streams > 0);
326 s->server->n_stdout_streams --;
327 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
332 epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
334 close_nointr_nofail(s->fd);
338 if (s->security_context)
339 freecon(s->security_context);
346 int stdout_stream_new(Server *s) {
347 StdoutStream *stream;
350 struct epoll_event ev;
354 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
359 log_error("Failed to accept stdout connection: %m");
363 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
364 log_warning("Too many stdout streams, refusing connection.");
365 close_nointr_nofail(fd);
369 stream = new0(StdoutStream, 1);
371 close_nointr_nofail(fd);
377 len = sizeof(stream->ucred);
378 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
379 log_error("Failed to determine peer credentials: %m");
386 if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
387 log_error("Failed to determine peer security context: %m");
391 if (shutdown(fd, SHUT_WR) < 0) {
392 log_error("Failed to shutdown writing side of socket: %m");
398 ev.data.ptr = stream;
400 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
401 log_error("Failed to add stream to event loop: %m");
407 LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
408 s->n_stdout_streams ++;
413 stdout_stream_free(stream);
417 int server_open_stdout_socket(Server *s) {
419 struct epoll_event ev;
423 if (s->stdout_fd < 0) {
424 union sockaddr_union sa = {
425 .un.sun_family = AF_UNIX,
426 .un.sun_path = "/run/systemd/journal/stdout",
429 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
430 if (s->stdout_fd < 0) {
431 log_error("socket() failed: %m");
435 unlink(sa.un.sun_path);
437 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
439 log_error("bind() failed: %m");
443 chmod(sa.un.sun_path, 0666);
445 if (listen(s->stdout_fd, SOMAXCONN) < 0) {
446 log_error("listen() failed: %m");
450 fd_nonblock(s->stdout_fd, 1);
454 ev.data.fd = s->stdout_fd;
455 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) {
456 log_error("Failed to add stdout server fd to epoll object: %m");