a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering This file is part of systemd.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2011 Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is free software; you can redistribute it and/or modify it
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering under the terms of the GNU Lesser General Public License as published by
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (at your option) any later version.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is distributed in the hope that it will be useful, but
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Lesser General Public License for more details.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering You should have received a copy of the GNU Lesser General Public License
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering LIST_FIELDS(StdoutStream, stdout_stream);
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering LIST_FIELDS(StdoutStream, stdout_stream_notify_queue);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringvoid stdout_stream_free(StdoutStream *s) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
13790add4bf648fed816361794d8277a75253410Lennart Poettering sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF);
13790add4bf648fed816361794d8277a75253410Lennart Poettering s->event_source = sd_event_source_unref(s->event_source);
13790add4bf648fed816361794d8277a75253410Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic void stdout_stream_destroy(StdoutStream *s) {
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int stdout_stream_save(StdoutStream *s) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_warning_errno(errno, "Failed to stat connected stream: %m");
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* We use device and inode numbers as identifier for the stream */
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
13790add4bf648fed816361794d8277a75253410Lennart Poettering mkdir_p("/run/systemd/journal/streams", 0755);
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = fopen_temporary(s->state_file, &f, &temp_path);
13790add4bf648fed816361794d8277a75253410Lennart Poettering "# This is private data. Do not parse\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering "PRIORITY=%i\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering "LEVEL_PREFIX=%i\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering "FORWARD_TO_SYSLOG=%i\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering "FORWARD_TO_KMSG=%i\n"
13790add4bf648fed816361794d8277a75253410Lennart Poettering "FORWARD_TO_CONSOLE=%i\n",
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (rename(temp_path, s->state_file) < 0) {
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering if (!s->fdstore && !s->in_notify_queue) {
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON);
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering log_warning_errno(r, "Failed to enable notify event source: %m");
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int stdout_stream_log(StdoutStream *s, const char *p) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering struct iovec iovec[N_IOVEC_META_FIELDS + 5];
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek char syslog_priority[] = "PRIORITY=\0";
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek syslog_parse_priority(&p, &priority, false);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (s->forward_to_syslog || s->server->forward_to_syslog)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (s->forward_to_kmsg || s->server->forward_to_kmsg)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (s->forward_to_console || s->server->forward_to_console)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen server_forward_wall(s->server, priority, s->identifier, p, &s->ucred);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], syslog_priority);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], syslog_facility);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering IOVEC_SET_STRING(iovec[n++], syslog_identifier);
2de56f70941eaf91a4520bf33de47a87ebd8b2cbZbigniew Jędrzejewski-Szmek label_len = s->label ? strlen(s->label) : 0;
2de56f70941eaf91a4520bf33de47a87ebd8b2cbZbigniew Jędrzejewski-Szmek server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, s->label, label_len, s->unit_id, priority, 0);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int stdout_stream_line(StdoutStream *s, char *p) {
41891700e02daf0cab9e86908c76ac6f411bbd57Lennart Poettering if (r < 0 || s->priority < 0 || s->priority > 999) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_warning("Failed to parse log priority line.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_warning("Failed to parse level prefix line.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_warning("Failed to parse forward to syslog line.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_warning("Failed to parse copy to kmsg line.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_warning("Failed to parse copy to console line.");
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Try to save the stream, so that journald can be restarted and we can recover */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert_not_reached("Unknown stream state");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int stdout_stream_scan(StdoutStream *s, bool force_flush) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else if (remaining >= sizeof(s->buffer) - 1) {
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poetteringstatic int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) {
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_warning_errno(errno, "Failed to read from stream: %m");
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL;
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_error_errno(r, "Failed to determine peer credentials: %m");
2de56f70941eaf91a4520bf33de47a87ebd8b2cbZbigniew Jędrzejewski-Szmek r = getpeersec(fd, &stream->label);
2de56f70941eaf91a4520bf33de47a87ebd8b2cbZbigniew Jędrzejewski-Szmek if (r < 0 && r != -EOPNOTSUPP)
2de56f70941eaf91a4520bf33de47a87ebd8b2cbZbigniew Jędrzejewski-Szmek (void) log_warning_errno(r, "Failed to determine peer security context: %m");
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_error_errno(r, "Failed to add stream to event loop: %m");
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_error_errno(r, "Failed to adjust stdout event source priority: %m");
13790add4bf648fed816361794d8277a75253410Lennart Poettering LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poetteringstatic int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) {
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering log_error("Got invalid event from epoll for stdout server fd: %"PRIx32, revents);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
e1427b138fbf7b7f13bb61187635b882be3ca2b2Michal Schmidt return log_error_errno(errno, "Failed to accept stdout connection: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_warning("Too many stdout streams, refusing connection.");
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int stdout_stream_load(StdoutStream *stream, const char *fname) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering stream->state_file = strappend("/run/systemd/journal/streams/", fname);
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = parse_env_file(stream->state_file, NEWLINE,
13790add4bf648fed816361794d8277a75253410Lennart Poettering "FORWARD_TO_CONSOLE", &forward_to_console,
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_error_errno(r, "Failed to read: %s", stream->state_file);
13790add4bf648fed816361794d8277a75253410Lennart Poetteringstatic int stdout_stream_restore(Server *s, const char *fname, int fd) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_warning("Too many stdout streams, refusing restoring of stream.");
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = stdout_stream_install(s, fd, &stream);
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Ignore all parsing errors */
13790add4bf648fed816361794d8277a75253410Lennart Poettering (void) stdout_stream_load(stream, fname);
15d91bff36c61d38df8edff258d1702a017a0e66Zbigniew Jędrzejewski-Szmekint server_restore_streams(Server *s, FDSet *fds) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering d = opendir("/run/systemd/journal/streams");
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m");
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (sscanf(de->d_name, "%lu:%lu", &st_dev, &st_ino) != 2)
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_error_errno(errno, "Failed to stat %s: %m", de->d_name);
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (S_ISSOCK(st.st_mode) && st.st_dev == st_dev && st.st_ino == st_ino) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* No file descriptor? Then let's delete the state file */
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_debug("Cannot restore stream file %s", de->d_name);
13790add4bf648fed816361794d8277a75253410Lennart Poettering r = stdout_stream_restore(s, de->d_name, fd);
13790add4bf648fed816361794d8277a75253410Lennart Poettering return log_error_errno(errno, "Failed to read streams directory: %m");
15d91bff36c61d38df8edff258d1702a017a0e66Zbigniew Jędrzejewski-Szmekint server_open_stdout_socket(Server *s) {
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek .un.sun_path = "/run/systemd/journal/stdout",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return log_error_errno(errno, "socket() failed: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
4a61c3e51e96a747c30598d78ee3a24e7c569e9fZbigniew Jędrzejewski-Szmek (void) chmod(sa.un.sun_path, 0666);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt return log_error_errno(r, "Failed to add stdout server fd to event source: %m");
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+5);
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poetteringvoid stdout_stream_send_notify(StdoutStream *s) {
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering /* Store the connection fd in PID 1, so that we get it passed
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering * in again on next start */
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering msghdr.msg_controllen = CMSG_SPACE(sizeof(int));
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering msghdr.msg_control = alloca0(msghdr.msg_controllen);
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int));
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL);
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m");
e22aa3d3284709234f086ebebc13a905a295b7a7Lennart Poettering log_debug("Successfully sent stream file descriptor to service manager.");