journald-stream.c revision 2de56f70941eaf91a4520bf33de47a87ebd8b2cb
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering This file is part of systemd.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering Copyright 2011 Lennart Poettering
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering systemd is free software; you can redistribute it and/or modify it
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering under the terms of the GNU Lesser General Public License as published by
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering (at your option) any later version.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering systemd is distributed in the hope that it will be useful, but
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering Lesser General Public License for more details.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering You should have received a copy of the GNU Lesser General Public License
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering LIST_FIELDS(StdoutStream, stdout_stream);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringvoid stdout_stream_free(StdoutStream *s) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering s->event_source = sd_event_source_unref(s->event_source);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic void stdout_stream_destroy(StdoutStream *s) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_save(StdoutStream *s) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return log_warning_errno(errno, "Failed to stat connected stream: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* We use device and inode numbers as identifier for the stream */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering mkdir_p("/run/systemd/journal/streams", 0755);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = fopen_temporary(s->state_file, &f, &temp_path);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering "# This is private data. Do not parse\n"
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering "PRIORITY=%i\n"
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering "LEVEL_PREFIX=%i\n"
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering "FORWARD_TO_SYSLOG=%i\n"
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering "FORWARD_TO_KMSG=%i\n"
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering "FORWARD_TO_CONSOLE=%i\n",
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (rename(temp_path, s->state_file) < 0) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* Store the connection fd in PID 1, so that we get it passed
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering * in again on next start */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_log(StdoutStream *s, const char *p) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering struct iovec iovec[N_IOVEC_META_FIELDS + 5];
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering unsigned n = 0;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering syslog_parse_priority(&p, &priority, false);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (s->forward_to_syslog || s->server->forward_to_syslog)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (s->forward_to_kmsg || s->server->forward_to_kmsg)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (s->forward_to_console || s->server->forward_to_console)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server_forward_wall(s->server, priority, s->identifier, p, &s->ucred);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering IOVEC_SET_STRING(iovec[n++], syslog_priority);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering IOVEC_SET_STRING(iovec[n++], syslog_facility);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering IOVEC_SET_STRING(iovec[n++], syslog_identifier);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering label_len = s->label ? strlen(s->label) : 0;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, s->label, label_len, s->unit_id, priority, 0);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_line(StdoutStream *s, char *p) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (r < 0 || s->priority < 0 || s->priority > 999) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning("Failed to parse log priority line.");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning("Failed to parse level prefix line.");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning("Failed to parse forward to syslog line.");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning("Failed to parse copy to kmsg line.");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning("Failed to parse copy to console line.");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* Try to save the stream, so that journald can be restarted and we can recover */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering assert_not_reached("Unknown stream state");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_scan(StdoutStream *s, bool force_flush) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering else if (remaining >= sizeof(s->buffer) - 1) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning_errno(errno, "Failed to read from stream: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL;
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return log_error_errno(r, "Failed to determine peer credentials: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (r < 0 && r != -EOPNOTSUPP)
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering (void) log_warning_errno(r, "Failed to determine peer security context: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return log_error_errno(r, "Failed to add stream to event loop: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return log_error_errno(r, "Failed to adjust stdout event source priority: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_error("Got invalid event from epoll for stdout server fd: %"PRIx32, revents);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_error_errno(errno, "Failed to accept stdout connection: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning("Too many stdout streams, refusing connection.");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_load(StdoutStream *stream, const char *fname) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering stream->state_file = strappend("/run/systemd/journal/streams/", fname);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = parse_env_file(stream->state_file, NEWLINE,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering "FORWARD_TO_CONSOLE", &forward_to_console,
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return log_error_errno(r, "Failed to read: %s", stream->state_file);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int stdout_stream_restore(Server *s, const char *fname, int fd) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering log_warning("Too many stdout streams, refusing restoring of stream.");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering r = stdout_stream_install(s, fd, &stream);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering /* Ignore all parsing errors */
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering (void) stdout_stream_load(stream, fname);
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poetteringstatic int server_restore_streams(Server *s, FDSet *fds) {
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering d = opendir("/run/systemd/journal/streams");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m");
a1ad376761af16da46c9ad90fd8df41c8c5c0976Lennart Poettering if (sscanf(de->d_name, "%lu:%lu", &st_dev, &st_ino) != 2)
found = true;
if (!found) {
fail:
assert(s);
if (s->stdout_fd < 0) {
if (s->stdout_fd < 0)
r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);