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 _cleanup_free_ 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);
135 static int stdout_stream_line(StdoutStream *s, char *p) {
145 case STDOUT_STREAM_IDENTIFIER:
147 s->identifier = NULL;
149 s->identifier = strdup(p);
154 s->state = STDOUT_STREAM_UNIT_ID;
157 case STDOUT_STREAM_UNIT_ID:
158 if (s->ucred.uid == 0) {
162 s->unit_id = strdup(p);
168 s->state = STDOUT_STREAM_PRIORITY;
171 case STDOUT_STREAM_PRIORITY:
172 r = safe_atoi(p, &s->priority);
173 if (r < 0 || s->priority < 0 || s->priority > 999) {
174 log_warning("Failed to parse log priority line.");
178 s->state = STDOUT_STREAM_LEVEL_PREFIX;
181 case STDOUT_STREAM_LEVEL_PREFIX:
182 r = parse_boolean(p);
184 log_warning("Failed to parse level prefix line.");
188 s->level_prefix = !!r;
189 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
192 case STDOUT_STREAM_FORWARD_TO_SYSLOG:
193 r = parse_boolean(p);
195 log_warning("Failed to parse forward to syslog line.");
199 s->forward_to_syslog = !!r;
200 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
203 case STDOUT_STREAM_FORWARD_TO_KMSG:
204 r = parse_boolean(p);
206 log_warning("Failed to parse copy to kmsg line.");
210 s->forward_to_kmsg = !!r;
211 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
214 case STDOUT_STREAM_FORWARD_TO_CONSOLE:
215 r = parse_boolean(p);
217 log_warning("Failed to parse copy to console line.");
221 s->forward_to_console = !!r;
222 s->state = STDOUT_STREAM_RUNNING;
225 case STDOUT_STREAM_RUNNING:
226 return stdout_stream_log(s, p);
229 assert_not_reached("Unknown stream state");
232 static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
240 remaining = s->length;
245 end = memchr(p, '\n', remaining);
248 else if (remaining >= sizeof(s->buffer) - 1) {
249 end = p + sizeof(s->buffer) - 1;
256 r = stdout_stream_line(s, p);
264 if (force_flush && remaining > 0) {
266 r = stdout_stream_line(s, p);
275 memmove(s->buffer, p, remaining);
276 s->length = remaining;
282 int stdout_stream_process(StdoutStream *s) {
288 l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
294 log_warning("Failed to read from stream: %m");
299 r = stdout_stream_scan(s, true);
307 r = stdout_stream_scan(s, false);
315 void stdout_stream_free(StdoutStream *s) {
319 assert(s->server->n_stdout_streams > 0);
320 s->server->n_stdout_streams --;
321 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
326 epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
328 close_nointr_nofail(s->fd);
332 if (s->security_context)
333 freecon(s->security_context);
341 int stdout_stream_new(Server *s) {
342 StdoutStream *stream;
345 struct epoll_event ev;
349 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
354 log_error("Failed to accept stdout connection: %m");
358 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
359 log_warning("Too many stdout streams, refusing connection.");
360 close_nointr_nofail(fd);
364 stream = new0(StdoutStream, 1);
366 close_nointr_nofail(fd);
372 len = sizeof(stream->ucred);
373 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
374 log_error("Failed to determine peer credentials: %m");
381 if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
382 log_error("Failed to determine peer security context: %m");
386 if (shutdown(fd, SHUT_WR) < 0) {
387 log_error("Failed to shutdown writing side of socket: %m");
393 ev.data.ptr = stream;
395 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
396 log_error("Failed to add stream to event loop: %m");
402 LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
403 s->n_stdout_streams ++;
408 stdout_stream_free(stream);
412 int server_open_stdout_socket(Server *s) {
414 struct epoll_event ev;
418 if (s->stdout_fd < 0) {
419 union sockaddr_union sa = {
420 .un.sun_family = AF_UNIX,
421 .un.sun_path = "/run/systemd/journal/stdout",
424 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
425 if (s->stdout_fd < 0) {
426 log_error("socket() failed: %m");
430 unlink(sa.un.sun_path);
432 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
434 log_error("bind() failed: %m");
438 chmod(sa.un.sun_path, 0666);
440 if (listen(s->stdout_fd, SOMAXCONN) < 0) {
441 log_error("listen() failed: %m");
445 fd_nonblock(s->stdout_fd, 1);
449 ev.data.fd = s->stdout_fd;
450 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) {
451 log_error("Failed to add stdout server fd to epoll object: %m");