journald-stream.c revision b5efdb8af40ea759a1ea584c1bc44ecc81dd00ce
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog This file is part of systemd.
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog Copyright 2011 Lennart Poettering
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog systemd is free software; you can redistribute it and/or modify it
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog under the terms of the GNU Lesser General Public License as published by
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog the Free Software Foundation; either version 2.1 of the License, or
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog (at your option) any later version.
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog systemd is distributed in the hope that it will be useful, but
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog WITHOUT ANY WARRANTY; without even the implied warranty of
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog Lesser General Public License for more details.
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog You should have received a copy of the GNU Lesser General Public License
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog along with systemd; If not, see <http://www.gnu.org/licenses/>.
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog LIST_FIELDS(StdoutStream, stdout_stream);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskogvoid stdout_stream_free(StdoutStream *s) {
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog assert(s->server->n_stdout_streams > 0);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog s->event_source = sd_event_source_unref(s->event_source);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar LindskogDEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskogstatic void stdout_stream_destroy(StdoutStream *s) {
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskogstatic int stdout_stream_save(StdoutStream *s) {
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog _cleanup_free_ char *temp_path = NULL;
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog if (s->state != STDOUT_STREAM_RUNNING)
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog return log_warning_errno(errno, "Failed to stat connected stream: %m");
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog /* We use device and inode numbers as identifier for the stream */
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog mkdir_p("/run/systemd/journal/streams", 0755);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog r = fopen_temporary(s->state_file, &f, &temp_path);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog "# This is private data. Do not parse\n"
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog "PRIORITY=%i\n"
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog "LEVEL_PREFIX=%i\n"
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog "FORWARD_TO_SYSLOG=%i\n"
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog "FORWARD_TO_KMSG=%i\n"
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog "FORWARD_TO_CONSOLE=%i\n",
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog fprintf(f, "IDENTIFIER=%s\n", escaped);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog if (rename(temp_path, s->state_file) < 0) {
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog /* Store the connection fd in PID 1, so that we get it passed
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog * in again on next start */
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskogstatic int stdout_stream_log(StdoutStream *s, const char *p) {
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog struct iovec iovec[N_IOVEC_META_FIELDS + 5];
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog char syslog_priority[] = "PRIORITY=\0";
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
d9bf4f8c6c47b8620ffa1a056208eb15118b78d5Umut Tezduyar Lindskog _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
assert(s);
assert(p);
if (isempty(p))
if (s->level_prefix)
server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
if (s->identifier) {
if (syslog_identifier)
if (message)
server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, s->label, label_len, s->unit_id, priority, 0);
assert(s);
assert(p);
p = strstrip(p);
switch (s->state) {
case STDOUT_STREAM_IDENTIFIER:
if (isempty(p))
if (!s->identifier)
return log_oom();
case STDOUT_STREAM_UNIT_ID:
if (isempty(p))
if (!s->unit_id)
return log_oom();
case STDOUT_STREAM_PRIORITY:
return -EINVAL;
r = parse_boolean(p);
return -EINVAL;
s->level_prefix = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_syslog = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_kmsg = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_console = !!r;
(void) stdout_stream_save(s);
case STDOUT_STREAM_RUNNING:
return stdout_stream_log(s, p);
assert(s);
p = s->buffer;
char *end;
if (end)
*end = 0;
r = stdout_stream_line(s, p);
p += skip;
p[remaining] = 0;
r = stdout_stream_line(s, p);
p += remaining;
remaining = 0;
if (p > s->buffer) {
ssize_t l;
assert(s);
goto terminate;
goto terminate;
stdout_stream_scan(s, true);
goto terminate;
s->length += l;
r = stdout_stream_scan(s, false);
goto terminate;
assert(s);
if (!stream)
return log_oom();
if (mac_selinux_use()) {
if (r < 0 && r != -EOPNOTSUPP)
s->n_stdout_streams ++;
if (ret)
static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) {
assert(s);
return -EIO;
if (fd < 0) {
return -errno;
_cleanup_free_ char
return log_oom();
NULL);
if (priority) {
if (level_prefix) {
if (forward_to_syslog) {
if (forward_to_kmsg) {
if (forward_to_console) {
assert(s);
return -ENOBUFS;
bool found = false;
Iterator i;
int fd;
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);