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/>.
24 #include <sys/epoll.h>
27 #include <selinux/selinux.h>
30 #include "socket-util.h"
32 #include "journald-stream.h"
33 #include "journald-syslog.h"
34 #include "journald-kmsg.h"
36 #define STDOUT_STREAMS_MAX 4096
38 typedef enum StdoutStreamState {
39 STDOUT_STREAM_IDENTIFIER,
40 STDOUT_STREAM_UNIT_ID,
41 STDOUT_STREAM_PRIORITY,
42 STDOUT_STREAM_LEVEL_PREFIX,
43 STDOUT_STREAM_FORWARD_TO_SYSLOG,
44 STDOUT_STREAM_FORWARD_TO_KMSG,
45 STDOUT_STREAM_FORWARD_TO_CONSOLE,
51 StdoutStreamState state;
57 security_context_t security_context;
64 bool forward_to_syslog:1;
65 bool forward_to_kmsg:1;
66 bool forward_to_console:1;
68 char buffer[LINE_MAX+1];
71 LIST_FIELDS(StdoutStream, stdout_stream);
74 static int stdout_stream_log(StdoutStream *s, const char *p) {
75 struct iovec iovec[N_IOVEC_META_FIELDS + 5];
76 char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
88 priority = s->priority;
91 syslog_parse_priority((char**) &p, &priority);
93 if (s->forward_to_syslog || s->server->forward_to_syslog)
94 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
96 if (s->forward_to_kmsg || s->server->forward_to_kmsg)
97 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
99 if (s->forward_to_console || s->server->forward_to_console)
100 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
102 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
104 if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
105 IOVEC_SET_STRING(iovec[n++], syslog_priority);
107 if (priority & LOG_FACMASK)
108 if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
109 IOVEC_SET_STRING(iovec[n++], syslog_facility);
112 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
113 if (syslog_identifier)
114 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
117 message = strappend("MESSAGE=", p);
119 IOVEC_SET_STRING(iovec[n++], message);
122 if (s->security_context) {
123 label = (char*) s->security_context;
124 label_len = strlen((char*) s->security_context);
128 server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority);
131 free(syslog_priority);
132 free(syslog_facility);
133 free(syslog_identifier);
138 static int stdout_stream_line(StdoutStream *s, char *p) {
148 case STDOUT_STREAM_IDENTIFIER:
150 s->identifier = NULL;
152 s->identifier = strdup(p);
157 s->state = STDOUT_STREAM_UNIT_ID;
160 case STDOUT_STREAM_UNIT_ID:
161 if (s->ucred.uid == 0) {
165 s->unit_id = strdup(p);
171 s->state = STDOUT_STREAM_PRIORITY;
174 case STDOUT_STREAM_PRIORITY:
175 r = safe_atoi(p, &s->priority);
176 if (r < 0 || s->priority <= 0 || s->priority >= 999) {
177 log_warning("Failed to parse log priority line.");
181 s->state = STDOUT_STREAM_LEVEL_PREFIX;
184 case STDOUT_STREAM_LEVEL_PREFIX:
185 r = parse_boolean(p);
187 log_warning("Failed to parse level prefix line.");
191 s->level_prefix = !!r;
192 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
195 case STDOUT_STREAM_FORWARD_TO_SYSLOG:
196 r = parse_boolean(p);
198 log_warning("Failed to parse forward to syslog line.");
202 s->forward_to_syslog = !!r;
203 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
206 case STDOUT_STREAM_FORWARD_TO_KMSG:
207 r = parse_boolean(p);
209 log_warning("Failed to parse copy to kmsg line.");
213 s->forward_to_kmsg = !!r;
214 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
217 case STDOUT_STREAM_FORWARD_TO_CONSOLE:
218 r = parse_boolean(p);
220 log_warning("Failed to parse copy to console line.");
224 s->forward_to_console = !!r;
225 s->state = STDOUT_STREAM_RUNNING;
228 case STDOUT_STREAM_RUNNING:
229 return stdout_stream_log(s, p);
232 assert_not_reached("Unknown stream state");
235 static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
243 remaining = s->length;
248 end = memchr(p, '\n', remaining);
251 else if (remaining >= sizeof(s->buffer) - 1) {
252 end = p + sizeof(s->buffer) - 1;
259 r = stdout_stream_line(s, p);
267 if (force_flush && remaining > 0) {
269 r = stdout_stream_line(s, p);
278 memmove(s->buffer, p, remaining);
279 s->length = remaining;
285 int stdout_stream_process(StdoutStream *s) {
291 l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
297 log_warning("Failed to read from stream: %m");
302 r = stdout_stream_scan(s, true);
310 r = stdout_stream_scan(s, false);
318 void stdout_stream_free(StdoutStream *s) {
322 assert(s->server->n_stdout_streams > 0);
323 s->server->n_stdout_streams --;
324 LIST_REMOVE(StdoutStream, stdout_stream, s->server->stdout_streams, s);
329 epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL);
331 close_nointr_nofail(s->fd);
335 if (s->security_context)
336 freecon(s->security_context);
343 int stdout_stream_new(Server *s) {
344 StdoutStream *stream;
347 struct epoll_event ev;
351 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
356 log_error("Failed to accept stdout connection: %m");
360 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
361 log_warning("Too many stdout streams, refusing connection.");
362 close_nointr_nofail(fd);
366 stream = new0(StdoutStream, 1);
368 close_nointr_nofail(fd);
374 len = sizeof(stream->ucred);
375 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
376 log_error("Failed to determine peer credentials: %m");
382 if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
383 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(StdoutStream, stdout_stream, s->stdout_streams, stream);
403 s->n_stdout_streams ++;
408 stdout_stream_free(stream);
412 int server_open_stdout_socket(Server *s) {
413 union sockaddr_union sa;
415 struct epoll_event ev;
419 if (s->stdout_fd < 0) {
421 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
422 if (s->stdout_fd < 0) {
423 log_error("socket() failed: %m");
428 sa.un.sun_family = AF_UNIX;
429 strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
431 unlink(sa.un.sun_path);
433 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
435 log_error("bind() failed: %m");
439 chmod(sa.un.sun_path, 0666);
441 if (listen(s->stdout_fd, SOMAXCONN) < 0) {
442 log_error("liste() failed: %m");
446 fd_nonblock(s->stdout_fd, 1);
450 ev.data.fd = s->stdout_fd;
451 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) {
452 log_error("Failed to add stdout server fd to epoll object: %m");