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/>.
26 #include <selinux/selinux.h>
30 #include "sd-daemon.h"
31 #include "socket-util.h"
32 #include "selinux-util.h"
35 #include "journald-server.h"
36 #include "journald-stream.h"
37 #include "journald-syslog.h"
38 #include "journald-kmsg.h"
39 #include "journald-console.h"
40 #include "journald-wall.h"
42 #define STDOUT_STREAMS_MAX 4096
44 typedef enum StdoutStreamState {
45 STDOUT_STREAM_IDENTIFIER,
46 STDOUT_STREAM_UNIT_ID,
47 STDOUT_STREAM_PRIORITY,
48 STDOUT_STREAM_LEVEL_PREFIX,
49 STDOUT_STREAM_FORWARD_TO_SYSLOG,
50 STDOUT_STREAM_FORWARD_TO_KMSG,
51 STDOUT_STREAM_FORWARD_TO_CONSOLE,
57 StdoutStreamState state;
63 security_context_t security_context;
70 bool forward_to_syslog:1;
71 bool forward_to_kmsg:1;
72 bool forward_to_console:1;
76 char buffer[LINE_MAX+1];
79 sd_event_source *event_source;
83 LIST_FIELDS(StdoutStream, stdout_stream);
86 void stdout_stream_free(StdoutStream *s) {
91 assert(s->server->n_stdout_streams > 0);
92 s->server->n_stdout_streams --;
93 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
96 if (s->event_source) {
97 sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF);
98 s->event_source = sd_event_source_unref(s->event_source);
104 if (s->security_context)
105 freecon(s->security_context);
115 DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free);
117 static void stdout_stream_destroy(StdoutStream *s) {
122 unlink(s->state_file);
124 stdout_stream_free(s);
127 static int stdout_stream_save(StdoutStream *s) {
128 _cleanup_free_ char *temp_path = NULL;
129 _cleanup_fclose_ FILE *f = NULL;
134 if (s->state != STDOUT_STREAM_RUNNING)
137 if (!s->state_file) {
140 r = fstat(s->fd, &st);
142 return log_warning_errno(errno, "Failed to stat connected stream: %m");
144 /* We use device and inode numbers as identifier for the stream */
145 if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
149 mkdir_p("/run/systemd/journal/streams", 0755);
151 r = fopen_temporary(s->state_file, &f, &temp_path);
156 "# This is private data. Do not parse\n"
159 "FORWARD_TO_SYSLOG=%i\n"
160 "FORWARD_TO_KMSG=%i\n"
161 "FORWARD_TO_CONSOLE=%i\n",
164 s->forward_to_syslog,
166 s->forward_to_console);
168 if (!isempty(s->identifier)) {
169 _cleanup_free_ char *escaped;
171 escaped = cescape(s->identifier);
177 fprintf(f, "IDENTIFIER=%s\n", escaped);
180 if (!isempty(s->unit_id)) {
181 _cleanup_free_ char *escaped;
183 escaped = cescape(s->unit_id);
189 fprintf(f, "UNIT=%s\n", escaped);
192 r = fflush_and_check(f);
196 if (rename(temp_path, s->state_file) < 0) {
204 /* Store the connection fd in PID 1, so that we get it passed
205 * in again on next start */
207 sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
216 log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
221 static int stdout_stream_log(StdoutStream *s, const char *p) {
222 struct iovec iovec[N_IOVEC_META_FIELDS + 5];
224 char syslog_priority[] = "PRIORITY=\0";
225 char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
226 _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
229 size_t label_len = 0;
237 priority = s->priority;
240 syslog_parse_priority(&p, &priority, false);
242 if (s->forward_to_syslog || s->server->forward_to_syslog)
243 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
245 if (s->forward_to_kmsg || s->server->forward_to_kmsg)
246 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
248 if (s->forward_to_console || s->server->forward_to_console)
249 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
251 if (s->server->forward_to_wall)
252 server_forward_wall(s->server, priority, s->identifier, p, &s->ucred);
254 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
256 syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
257 IOVEC_SET_STRING(iovec[n++], syslog_priority);
259 if (priority & LOG_FACMASK) {
260 xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
261 IOVEC_SET_STRING(iovec[n++], syslog_facility);
265 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
266 if (syslog_identifier)
267 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
270 message = strappend("MESSAGE=", p);
272 IOVEC_SET_STRING(iovec[n++], message);
275 if (s->security_context) {
276 label = (char*) s->security_context;
277 label_len = strlen((char*) s->security_context);
281 server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
285 static int stdout_stream_line(StdoutStream *s, char *p) {
295 case STDOUT_STREAM_IDENTIFIER:
297 s->identifier = NULL;
299 s->identifier = strdup(p);
304 s->state = STDOUT_STREAM_UNIT_ID;
307 case STDOUT_STREAM_UNIT_ID:
308 if (s->ucred.uid == 0) {
312 s->unit_id = strdup(p);
318 s->state = STDOUT_STREAM_PRIORITY;
321 case STDOUT_STREAM_PRIORITY:
322 r = safe_atoi(p, &s->priority);
323 if (r < 0 || s->priority < 0 || s->priority > 999) {
324 log_warning("Failed to parse log priority line.");
328 s->state = STDOUT_STREAM_LEVEL_PREFIX;
331 case STDOUT_STREAM_LEVEL_PREFIX:
332 r = parse_boolean(p);
334 log_warning("Failed to parse level prefix line.");
338 s->level_prefix = !!r;
339 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
342 case STDOUT_STREAM_FORWARD_TO_SYSLOG:
343 r = parse_boolean(p);
345 log_warning("Failed to parse forward to syslog line.");
349 s->forward_to_syslog = !!r;
350 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
353 case STDOUT_STREAM_FORWARD_TO_KMSG:
354 r = parse_boolean(p);
356 log_warning("Failed to parse copy to kmsg line.");
360 s->forward_to_kmsg = !!r;
361 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
364 case STDOUT_STREAM_FORWARD_TO_CONSOLE:
365 r = parse_boolean(p);
367 log_warning("Failed to parse copy to console line.");
371 s->forward_to_console = !!r;
372 s->state = STDOUT_STREAM_RUNNING;
374 /* Try to save the stream, so that journald can be restarted and we can recover */
375 (void) stdout_stream_save(s);
378 case STDOUT_STREAM_RUNNING:
379 return stdout_stream_log(s, p);
382 assert_not_reached("Unknown stream state");
385 static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
393 remaining = s->length;
398 end = memchr(p, '\n', remaining);
401 else if (remaining >= sizeof(s->buffer) - 1) {
402 end = p + sizeof(s->buffer) - 1;
409 r = stdout_stream_line(s, p);
417 if (force_flush && remaining > 0) {
419 r = stdout_stream_line(s, p);
428 memmove(s->buffer, p, remaining);
429 s->length = remaining;
435 static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
436 StdoutStream *s = userdata;
442 if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) {
443 log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents);
447 l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
453 log_warning_errno(errno, "Failed to read from stream: %m");
458 stdout_stream_scan(s, true);
463 r = stdout_stream_scan(s, false);
470 stdout_stream_destroy(s);
474 static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
475 _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL;
481 stream = new0(StdoutStream, 1);
486 stream->priority = LOG_INFO;
488 r = getpeercred(fd, &stream->ucred);
490 return log_error_errno(r, "Failed to determine peer credentials: %m");
493 if (mac_selinux_use()) {
494 if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
495 log_error_errno(errno, "Failed to determine peer security context: %m");
499 (void) shutdown(fd, SHUT_WR);
501 r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
503 return log_error_errno(r, "Failed to add stream to event loop: %m");
505 r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
507 return log_error_errno(r, "Failed to adjust stdout event source priority: %m");
512 LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
513 s->n_stdout_streams ++;
523 static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) {
524 _cleanup_close_ int fd = -1;
525 Server *s = userdata;
530 if (revents != EPOLLIN) {
531 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32, revents);
535 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
540 log_error_errno(errno, "Failed to accept stdout connection: %m");
544 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
545 log_warning("Too many stdout streams, refusing connection.");
549 r = stdout_stream_install(s, fd, NULL);
557 static int stdout_stream_load(StdoutStream *stream, const char *fname) {
560 *level_prefix = NULL,
561 *forward_to_syslog = NULL,
562 *forward_to_kmsg = NULL,
563 *forward_to_console = NULL;
569 if (!stream->state_file) {
570 stream->state_file = strappend("/run/systemd/journal/streams/", fname);
571 if (!stream->state_file)
575 r = parse_env_file(stream->state_file, NEWLINE,
576 "PRIORITY", &priority,
577 "LEVEL_PREFIX", &level_prefix,
578 "FORWARD_TO_SYSLOG", &forward_to_syslog,
579 "FORWARD_TO_KMSG", &forward_to_kmsg,
580 "FORWARD_TO_CONSOLE", &forward_to_console,
581 "IDENTIFIER", &stream->identifier,
582 "UNIT", &stream->unit_id,
585 return log_error_errno(r, "Failed to read: %s", stream->state_file);
590 p = log_level_from_string(priority);
592 stream->priority = p;
596 r = parse_boolean(level_prefix);
598 stream->level_prefix = r;
601 if (forward_to_syslog) {
602 r = parse_boolean(forward_to_syslog);
604 stream->forward_to_syslog = r;
607 if (forward_to_kmsg) {
608 r = parse_boolean(forward_to_kmsg);
610 stream->forward_to_kmsg = r;
613 if (forward_to_console) {
614 r = parse_boolean(forward_to_console);
616 stream->forward_to_console = r;
622 static int stdout_stream_restore(Server *s, const char *fname, int fd) {
623 StdoutStream *stream;
630 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
631 log_warning("Too many stdout streams, refusing restoring of stream.");
635 r = stdout_stream_install(s, fd, &stream);
639 stream->state = STDOUT_STREAM_RUNNING;
640 stream->fdstore = true;
642 /* Ignore all parsing errors */
643 (void) stdout_stream_load(stream, fname);
648 static int server_restore_streams(Server *s, FDSet *fds) {
649 _cleanup_closedir_ DIR *d = NULL;
653 d = opendir("/run/systemd/journal/streams");
658 return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m");
661 FOREACH_DIRENT(de, d, goto fail) {
662 unsigned long st_dev, st_ino;
667 if (sscanf(de->d_name, "%lu:%lu", &st_dev, &st_ino) != 2)
670 FDSET_FOREACH(fd, fds, i) {
673 if (fstat(fd, &st) < 0)
674 return log_error_errno(errno, "Failed to stat %s: %m", de->d_name);
676 if (S_ISSOCK(st.st_mode) && st.st_dev == st_dev && st.st_ino == st_ino) {
683 /* No file descriptor? Then let's delete the state file */
684 log_debug("Cannot restore stream file %s", de->d_name);
685 unlinkat(dirfd(d), de->d_name, 0);
689 fdset_remove(fds, fd);
691 r = stdout_stream_restore(s, de->d_name, fd);
699 return log_error_errno(errno, "Failed to read streams directory: %m");
702 int server_open_stdout_socket(Server *s, FDSet *fds) {
707 if (s->stdout_fd < 0) {
708 union sockaddr_union sa = {
709 .un.sun_family = AF_UNIX,
710 .un.sun_path = "/run/systemd/journal/stdout",
713 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
714 if (s->stdout_fd < 0)
715 return log_error_errno(errno, "socket() failed: %m");
717 unlink(sa.un.sun_path);
719 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
721 return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
723 chmod(sa.un.sun_path, 0666);
725 if (listen(s->stdout_fd, SOMAXCONN) < 0)
726 return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
728 fd_nonblock(s->stdout_fd, 1);
730 r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
732 return log_error_errno(r, "Failed to add stdout server fd to event source: %m");
734 r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10);
736 return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
738 /* Try to restore streams, but don't bother if this fails */
739 (void) server_restore_streams(s, fds);