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];
80 char syslog_priority[] = "PRIORITY=\0";
81 char syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(priority)];
82 _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
93 priority = s->priority;
96 syslog_parse_priority(&p, &priority, false);
98 if (s->forward_to_syslog || s->server->forward_to_syslog)
99 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
101 if (s->forward_to_kmsg || s->server->forward_to_kmsg)
102 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
104 if (s->forward_to_console || s->server->forward_to_console)
105 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
107 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
109 syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
110 IOVEC_SET_STRING(iovec[n++], syslog_priority);
112 if (priority & LOG_FACMASK) {
113 snprintf(syslog_facility, sizeof(syslog_facility), "SYSLOG_FACILITY=%i", LOG_FAC(priority));
114 IOVEC_SET_STRING(iovec[n++], syslog_facility);
118 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
119 if (syslog_identifier)
120 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
123 message = strappend("MESSAGE=", p);
125 IOVEC_SET_STRING(iovec[n++], message);
128 if (s->security_context) {
129 label = (char*) s->security_context;
130 label_len = strlen((char*) s->security_context);
134 server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
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(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);
344 int stdout_stream_new(Server *s) {
345 StdoutStream *stream;
348 struct epoll_event ev;
352 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
357 log_error("Failed to accept stdout connection: %m");
361 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
362 log_warning("Too many stdout streams, refusing connection.");
363 close_nointr_nofail(fd);
367 stream = new0(StdoutStream, 1);
369 close_nointr_nofail(fd);
375 len = sizeof(stream->ucred);
376 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
377 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");
389 if (shutdown(fd, SHUT_WR) < 0) {
390 log_error("Failed to shutdown writing side of socket: %m");
396 ev.data.ptr = stream;
398 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
399 log_error("Failed to add stream to event loop: %m");
405 LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
406 s->n_stdout_streams ++;
411 stdout_stream_free(stream);
415 int server_open_stdout_socket(Server *s) {
417 struct epoll_event ev = { .events = EPOLLIN };
421 if (s->stdout_fd < 0) {
422 union sockaddr_union sa = {
423 .un.sun_family = AF_UNIX,
424 .un.sun_path = "/run/systemd/journal/stdout",
427 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
428 if (s->stdout_fd < 0) {
429 log_error("socket() failed: %m");
433 unlink(sa.un.sun_path);
435 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
437 log_error("bind() failed: %m");
441 chmod(sa.un.sun_path, 0666);
443 if (listen(s->stdout_fd, SOMAXCONN) < 0) {
444 log_error("listen() failed: %m");
448 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");