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/>.
27 #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"
38 #include "journald-wall.h"
40 #define STDOUT_STREAMS_MAX 4096
42 typedef enum StdoutStreamState {
43 STDOUT_STREAM_IDENTIFIER,
44 STDOUT_STREAM_UNIT_ID,
45 STDOUT_STREAM_PRIORITY,
46 STDOUT_STREAM_LEVEL_PREFIX,
47 STDOUT_STREAM_FORWARD_TO_SYSLOG,
48 STDOUT_STREAM_FORWARD_TO_KMSG,
49 STDOUT_STREAM_FORWARD_TO_CONSOLE,
55 StdoutStreamState state;
61 security_context_t security_context;
68 bool forward_to_syslog:1;
69 bool forward_to_kmsg:1;
70 bool forward_to_console:1;
72 char buffer[LINE_MAX+1];
75 sd_event_source *event_source;
77 LIST_FIELDS(StdoutStream, stdout_stream);
80 static int stdout_stream_log(StdoutStream *s, const char *p) {
81 struct iovec iovec[N_IOVEC_META_FIELDS + 5];
83 char syslog_priority[] = "PRIORITY=\0";
84 char syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(priority)];
85 _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
96 priority = s->priority;
99 syslog_parse_priority(&p, &priority, false);
101 if (s->forward_to_syslog || s->server->forward_to_syslog)
102 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
104 if (s->forward_to_kmsg || s->server->forward_to_kmsg)
105 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
107 if (s->forward_to_console || s->server->forward_to_console)
108 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
110 if (s->server->forward_to_wall)
111 server_forward_wall(s->server, priority, s->identifier, p, &s->ucred);
113 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
115 syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
116 IOVEC_SET_STRING(iovec[n++], syslog_priority);
118 if (priority & LOG_FACMASK) {
119 snprintf(syslog_facility, sizeof(syslog_facility), "SYSLOG_FACILITY=%i", LOG_FAC(priority));
120 IOVEC_SET_STRING(iovec[n++], syslog_facility);
124 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
125 if (syslog_identifier)
126 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
129 message = strappend("MESSAGE=", p);
131 IOVEC_SET_STRING(iovec[n++], message);
134 if (s->security_context) {
135 label = (char*) s->security_context;
136 label_len = strlen((char*) s->security_context);
140 server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
144 static int stdout_stream_line(StdoutStream *s, char *p) {
154 case STDOUT_STREAM_IDENTIFIER:
156 s->identifier = NULL;
158 s->identifier = strdup(p);
163 s->state = STDOUT_STREAM_UNIT_ID;
166 case STDOUT_STREAM_UNIT_ID:
167 if (s->ucred.uid == 0) {
171 s->unit_id = strdup(p);
177 s->state = STDOUT_STREAM_PRIORITY;
180 case STDOUT_STREAM_PRIORITY:
181 r = safe_atoi(p, &s->priority);
182 if (r < 0 || s->priority < 0 || s->priority > 999) {
183 log_warning("Failed to parse log priority line.");
187 s->state = STDOUT_STREAM_LEVEL_PREFIX;
190 case STDOUT_STREAM_LEVEL_PREFIX:
191 r = parse_boolean(p);
193 log_warning("Failed to parse level prefix line.");
197 s->level_prefix = !!r;
198 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
201 case STDOUT_STREAM_FORWARD_TO_SYSLOG:
202 r = parse_boolean(p);
204 log_warning("Failed to parse forward to syslog line.");
208 s->forward_to_syslog = !!r;
209 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
212 case STDOUT_STREAM_FORWARD_TO_KMSG:
213 r = parse_boolean(p);
215 log_warning("Failed to parse copy to kmsg line.");
219 s->forward_to_kmsg = !!r;
220 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
223 case STDOUT_STREAM_FORWARD_TO_CONSOLE:
224 r = parse_boolean(p);
226 log_warning("Failed to parse copy to console line.");
230 s->forward_to_console = !!r;
231 s->state = STDOUT_STREAM_RUNNING;
234 case STDOUT_STREAM_RUNNING:
235 return stdout_stream_log(s, p);
238 assert_not_reached("Unknown stream state");
241 static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
249 remaining = s->length;
254 end = memchr(p, '\n', remaining);
257 else if (remaining >= sizeof(s->buffer) - 1) {
258 end = p + sizeof(s->buffer) - 1;
265 r = stdout_stream_line(s, p);
273 if (force_flush && remaining > 0) {
275 r = stdout_stream_line(s, p);
284 memmove(s->buffer, p, remaining);
285 s->length = remaining;
291 static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
292 StdoutStream *s = userdata;
298 if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) {
299 log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents);
303 l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
309 log_warning_errno(errno, "Failed to read from stream: %m");
314 stdout_stream_scan(s, true);
319 r = stdout_stream_scan(s, false);
326 stdout_stream_free(s);
330 void stdout_stream_free(StdoutStream *s) {
334 assert(s->server->n_stdout_streams > 0);
335 s->server->n_stdout_streams --;
336 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
339 if (s->event_source) {
340 sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF);
341 s->event_source = sd_event_source_unref(s->event_source);
347 if (s->security_context)
348 freecon(s->security_context);
356 static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) {
357 Server *s = userdata;
358 StdoutStream *stream;
363 if (revents != EPOLLIN) {
364 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32, revents);
368 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
373 log_error_errno(errno, "Failed to accept stdout connection: %m");
377 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
378 log_warning("Too many stdout streams, refusing connection.");
383 stream = new0(StdoutStream, 1);
391 r = getpeercred(fd, &stream->ucred);
393 log_error_errno(errno, "Failed to determine peer credentials: %m");
398 if (mac_selinux_use()) {
399 if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
400 log_error_errno(errno, "Failed to determine peer security context: %m");
404 if (shutdown(fd, SHUT_WR) < 0) {
405 log_error_errno(errno, "Failed to shutdown writing side of socket: %m");
409 r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
411 log_error_errno(r, "Failed to add stream to event loop: %m");
415 r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
417 log_error_errno(r, "Failed to adjust stdout event source priority: %m");
422 LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
423 s->n_stdout_streams ++;
428 stdout_stream_free(stream);
432 int server_open_stdout_socket(Server *s) {
437 if (s->stdout_fd < 0) {
438 union sockaddr_union sa = {
439 .un.sun_family = AF_UNIX,
440 .un.sun_path = "/run/systemd/journal/stdout",
443 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
444 if (s->stdout_fd < 0)
445 return log_error_errno(errno, "socket() failed: %m");
447 unlink(sa.un.sun_path);
449 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
451 return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
453 chmod(sa.un.sun_path, 0666);
455 if (listen(s->stdout_fd, SOMAXCONN) < 0)
456 return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
458 fd_nonblock(s->stdout_fd, 1);
460 r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
462 return log_error_errno(r, "Failed to add stdout server fd to event source: %m");
464 r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10);
466 return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");