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 "sd-daemon.h"
32 #include "socket-util.h"
33 #include "selinux-util.h"
36 #include "journald-server.h"
37 #include "journald-stream.h"
38 #include "journald-syslog.h"
39 #include "journald-kmsg.h"
40 #include "journald-console.h"
41 #include "journald-wall.h"
43 #define STDOUT_STREAMS_MAX 4096
45 typedef enum StdoutStreamState {
46 STDOUT_STREAM_IDENTIFIER,
47 STDOUT_STREAM_UNIT_ID,
48 STDOUT_STREAM_PRIORITY,
49 STDOUT_STREAM_LEVEL_PREFIX,
50 STDOUT_STREAM_FORWARD_TO_SYSLOG,
51 STDOUT_STREAM_FORWARD_TO_KMSG,
52 STDOUT_STREAM_FORWARD_TO_CONSOLE,
58 StdoutStreamState state;
64 security_context_t security_context;
71 bool forward_to_syslog:1;
72 bool forward_to_kmsg:1;
73 bool forward_to_console:1;
77 char buffer[LINE_MAX+1];
80 sd_event_source *event_source;
84 LIST_FIELDS(StdoutStream, stdout_stream);
87 void stdout_stream_free(StdoutStream *s) {
92 assert(s->server->n_stdout_streams > 0);
93 s->server->n_stdout_streams --;
94 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
97 if (s->event_source) {
98 sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF);
99 s->event_source = sd_event_source_unref(s->event_source);
105 if (s->security_context)
106 freecon(s->security_context);
116 DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free);
118 static void stdout_stream_destroy(StdoutStream *s) {
123 unlink(s->state_file);
125 stdout_stream_free(s);
128 static int stdout_stream_save(StdoutStream *s) {
129 _cleanup_free_ char *temp_path = NULL;
130 _cleanup_fclose_ FILE *f = NULL;
135 if (s->state != STDOUT_STREAM_RUNNING)
138 if (!s->state_file) {
141 r = fstat(s->fd, &st);
143 return log_warning_errno(errno, "Failed to stat connected stream: %m");
145 /* We use device and inode numbers as identifier for the stream */
146 if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
150 mkdir_p("/run/systemd/journal/streams", 0755);
152 r = fopen_temporary(s->state_file, &f, &temp_path);
157 "# This is private data. Do not parse\n"
160 "FORWARD_TO_SYSLOG=%i\n"
161 "FORWARD_TO_KMSG=%i\n"
162 "FORWARD_TO_CONSOLE=%i\n",
165 s->forward_to_syslog,
167 s->forward_to_console);
169 if (!isempty(s->identifier)) {
170 _cleanup_free_ char *escaped;
172 escaped = cescape(s->identifier);
178 fprintf(f, "IDENTIFIER=%s\n", escaped);
181 if (!isempty(s->unit_id)) {
182 _cleanup_free_ char *escaped;
184 escaped = cescape(s->unit_id);
190 fprintf(f, "UNIT=%s\n", escaped);
193 r = fflush_and_check(f);
197 if (rename(temp_path, s->state_file) < 0) {
205 /* Store the connection fd in PID 1, so that we get it passed
206 * in again on next start */
208 sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
217 log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
222 static int stdout_stream_log(StdoutStream *s, const char *p) {
223 struct iovec iovec[N_IOVEC_META_FIELDS + 5];
225 char syslog_priority[] = "PRIORITY=\0";
226 char syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(priority)];
227 _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
230 size_t label_len = 0;
238 priority = s->priority;
241 syslog_parse_priority(&p, &priority, false);
243 if (s->forward_to_syslog || s->server->forward_to_syslog)
244 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
246 if (s->forward_to_kmsg || s->server->forward_to_kmsg)
247 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
249 if (s->forward_to_console || s->server->forward_to_console)
250 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
252 if (s->server->forward_to_wall)
253 server_forward_wall(s->server, priority, s->identifier, p, &s->ucred);
255 IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
257 syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
258 IOVEC_SET_STRING(iovec[n++], syslog_priority);
260 if (priority & LOG_FACMASK) {
261 snprintf(syslog_facility, sizeof(syslog_facility), "SYSLOG_FACILITY=%i", LOG_FAC(priority));
262 IOVEC_SET_STRING(iovec[n++], syslog_facility);
266 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
267 if (syslog_identifier)
268 IOVEC_SET_STRING(iovec[n++], syslog_identifier);
271 message = strappend("MESSAGE=", p);
273 IOVEC_SET_STRING(iovec[n++], message);
276 if (s->security_context) {
277 label = (char*) s->security_context;
278 label_len = strlen((char*) s->security_context);
282 server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
286 static int stdout_stream_line(StdoutStream *s, char *p) {
296 case STDOUT_STREAM_IDENTIFIER:
298 s->identifier = NULL;
300 s->identifier = strdup(p);
305 s->state = STDOUT_STREAM_UNIT_ID;
308 case STDOUT_STREAM_UNIT_ID:
309 if (s->ucred.uid == 0) {
313 s->unit_id = strdup(p);
319 s->state = STDOUT_STREAM_PRIORITY;
322 case STDOUT_STREAM_PRIORITY:
323 r = safe_atoi(p, &s->priority);
324 if (r < 0 || s->priority < 0 || s->priority > 999) {
325 log_warning("Failed to parse log priority line.");
329 s->state = STDOUT_STREAM_LEVEL_PREFIX;
332 case STDOUT_STREAM_LEVEL_PREFIX:
333 r = parse_boolean(p);
335 log_warning("Failed to parse level prefix line.");
339 s->level_prefix = !!r;
340 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
343 case STDOUT_STREAM_FORWARD_TO_SYSLOG:
344 r = parse_boolean(p);
346 log_warning("Failed to parse forward to syslog line.");
350 s->forward_to_syslog = !!r;
351 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
354 case STDOUT_STREAM_FORWARD_TO_KMSG:
355 r = parse_boolean(p);
357 log_warning("Failed to parse copy to kmsg line.");
361 s->forward_to_kmsg = !!r;
362 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
365 case STDOUT_STREAM_FORWARD_TO_CONSOLE:
366 r = parse_boolean(p);
368 log_warning("Failed to parse copy to console line.");
372 s->forward_to_console = !!r;
373 s->state = STDOUT_STREAM_RUNNING;
375 /* Try to save the stream, so that journald can be restarted and we can recover */
376 (void) stdout_stream_save(s);
379 case STDOUT_STREAM_RUNNING:
380 return stdout_stream_log(s, p);
383 assert_not_reached("Unknown stream state");
386 static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
394 remaining = s->length;
399 end = memchr(p, '\n', remaining);
402 else if (remaining >= sizeof(s->buffer) - 1) {
403 end = p + sizeof(s->buffer) - 1;
410 r = stdout_stream_line(s, p);
418 if (force_flush && remaining > 0) {
420 r = stdout_stream_line(s, p);
429 memmove(s->buffer, p, remaining);
430 s->length = remaining;
436 static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
437 StdoutStream *s = userdata;
443 if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) {
444 log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents);
448 l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
454 log_warning_errno(errno, "Failed to read from stream: %m");
459 stdout_stream_scan(s, true);
464 r = stdout_stream_scan(s, false);
471 stdout_stream_destroy(s);
475 static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
476 _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL;
482 stream = new0(StdoutStream, 1);
487 stream->priority = LOG_INFO;
489 r = getpeercred(fd, &stream->ucred);
491 return log_error_errno(r, "Failed to determine peer credentials: %m");
494 if (mac_selinux_use()) {
495 if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
496 log_error_errno(errno, "Failed to determine peer security context: %m");
500 (void) shutdown(fd, SHUT_WR);
502 r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
504 return log_error_errno(r, "Failed to add stream to event loop: %m");
506 r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
508 return log_error_errno(r, "Failed to adjust stdout event source priority: %m");
513 LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
514 s->n_stdout_streams ++;
524 static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) {
525 _cleanup_close_ int fd = -1;
526 Server *s = userdata;
531 if (revents != EPOLLIN) {
532 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32, revents);
536 fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
541 log_error_errno(errno, "Failed to accept stdout connection: %m");
545 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
546 log_warning("Too many stdout streams, refusing connection.");
550 r = stdout_stream_install(s, fd, NULL);
558 static int stdout_stream_load(StdoutStream *stream, const char *fname) {
561 *level_prefix = NULL,
562 *forward_to_syslog = NULL,
563 *forward_to_kmsg = NULL,
564 *forward_to_console = NULL;
570 if (!stream->state_file) {
571 stream->state_file = strappend("/run/systemd/journal/streams/", fname);
572 if (!stream->state_file)
576 r = parse_env_file(stream->state_file, NEWLINE,
577 "PRIORITY", &priority,
578 "LEVEL_PREFIX", &level_prefix,
579 "FORWARD_TO_SYSLOG", &forward_to_syslog,
580 "FORWARD_TO_KMSG", &forward_to_kmsg,
581 "FORWARD_TO_CONSOLE", &forward_to_console,
582 "IDENTIFIER", &stream->identifier,
583 "UNIT", &stream->unit_id,
586 return log_error_errno(r, "Failed to read: %s", stream->state_file);
591 p = log_level_from_string(priority);
593 stream->priority = p;
597 r = parse_boolean(level_prefix);
599 stream->level_prefix = r;
602 if (forward_to_syslog) {
603 r = parse_boolean(forward_to_syslog);
605 stream->forward_to_syslog = r;
608 if (forward_to_kmsg) {
609 r = parse_boolean(forward_to_kmsg);
611 stream->forward_to_kmsg = r;
614 if (forward_to_console) {
615 r = parse_boolean(forward_to_console);
617 stream->forward_to_console = r;
623 static int stdout_stream_restore(Server *s, const char *fname, int fd) {
624 StdoutStream *stream;
631 if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
632 log_warning("Too many stdout streams, refusing restoring of stream.");
636 r = stdout_stream_install(s, fd, &stream);
640 stream->state = STDOUT_STREAM_RUNNING;
641 stream->fdstore = true;
643 /* Ignore all parsing errors */
644 (void) stdout_stream_load(stream, fname);
649 static int server_restore_streams(Server *s, FDSet *fds) {
650 _cleanup_closedir_ DIR *d = NULL;
654 d = opendir("/run/systemd/journal/streams");
659 return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m");
662 FOREACH_DIRENT(de, d, goto fail) {
663 unsigned long st_dev, st_ino;
668 if (sscanf(de->d_name, "%lu:%lu", &st_dev, &st_ino) != 2)
671 FDSET_FOREACH(fd, fds, i) {
674 if (fstat(fd, &st) < 0)
675 return log_error_errno(errno, "Failed to stat %s: %m", de->d_name);
677 if (S_ISSOCK(st.st_mode) && st.st_dev == st_dev && st.st_ino == st_ino) {
684 /* No file descriptor? Then let's delete the state file */
685 log_debug("Cannot restore stream file %s", de->d_name);
686 unlinkat(dirfd(d), de->d_name, 0);
690 fdset_remove(fds, fd);
692 r = stdout_stream_restore(s, de->d_name, fd);
700 return log_error_errno(errno, "Failed to read streams directory: %m");
703 int server_open_stdout_socket(Server *s, FDSet *fds) {
708 if (s->stdout_fd < 0) {
709 union sockaddr_union sa = {
710 .un.sun_family = AF_UNIX,
711 .un.sun_path = "/run/systemd/journal/stdout",
714 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
715 if (s->stdout_fd < 0)
716 return log_error_errno(errno, "socket() failed: %m");
718 unlink(sa.un.sun_path);
720 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
722 return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
724 chmod(sa.un.sun_path, 0666);
726 if (listen(s->stdout_fd, SOMAXCONN) < 0)
727 return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
729 fd_nonblock(s->stdout_fd, 1);
731 r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
733 return log_error_errno(r, "Failed to add stdout server fd to event source: %m");
735 r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10);
737 return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
739 /* Try to restore streams, but don't bother if this fails */
740 (void) server_restore_streams(s, fds);