LCOV - code coverage report
Current view: top level - journal - journald-stream.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 370 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 14 0.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2011 Lennart Poettering
       7             : 
       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.
      12             : 
      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.
      17             : 
      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/>.
      20             : ***/
      21             : 
      22             : #include <unistd.h>
      23             : #include <stddef.h>
      24             : 
      25             : #ifdef HAVE_SELINUX
      26             : #include <selinux/selinux.h>
      27             : #endif
      28             : 
      29             : #include "sd-event.h"
      30             : #include "sd-daemon.h"
      31             : #include "socket-util.h"
      32             : #include "selinux-util.h"
      33             : #include "mkdir.h"
      34             : #include "fileio.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"
      41             : 
      42             : #define STDOUT_STREAMS_MAX 4096
      43             : 
      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,
      52             :         STDOUT_STREAM_RUNNING
      53             : } StdoutStreamState;
      54             : 
      55             : struct StdoutStream {
      56             :         Server *server;
      57             :         StdoutStreamState state;
      58             : 
      59             :         int fd;
      60             : 
      61             :         struct ucred ucred;
      62             :         char *label;
      63             :         char *identifier;
      64             :         char *unit_id;
      65             :         int priority;
      66             :         bool level_prefix:1;
      67             :         bool forward_to_syslog:1;
      68             :         bool forward_to_kmsg:1;
      69             :         bool forward_to_console:1;
      70             : 
      71             :         bool fdstore:1;
      72             : 
      73             :         char buffer[LINE_MAX+1];
      74             :         size_t length;
      75             : 
      76             :         sd_event_source *event_source;
      77             : 
      78             :         char *state_file;
      79             : 
      80             :         LIST_FIELDS(StdoutStream, stdout_stream);
      81             : };
      82             : 
      83           0 : void stdout_stream_free(StdoutStream *s) {
      84           0 :         if (!s)
      85           0 :                 return;
      86             : 
      87           0 :         if (s->server) {
      88           0 :                 assert(s->server->n_stdout_streams > 0);
      89           0 :                 s->server->n_stdout_streams --;
      90           0 :                 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
      91             :         }
      92             : 
      93           0 :         if (s->event_source) {
      94           0 :                 sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF);
      95           0 :                 s->event_source = sd_event_source_unref(s->event_source);
      96             :         }
      97             : 
      98           0 :         safe_close(s->fd);
      99           0 :         free(s->label);
     100           0 :         free(s->identifier);
     101           0 :         free(s->unit_id);
     102           0 :         free(s->state_file);
     103             : 
     104           0 :         free(s);
     105             : }
     106             : 
     107           0 : DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free);
     108             : 
     109           0 : static void stdout_stream_destroy(StdoutStream *s) {
     110           0 :         if (!s)
     111           0 :                 return;
     112             : 
     113           0 :         if (s->state_file)
     114           0 :                 unlink(s->state_file);
     115             : 
     116           0 :         stdout_stream_free(s);
     117             : }
     118             : 
     119           0 : static int stdout_stream_save(StdoutStream *s) {
     120           0 :         _cleanup_free_ char *temp_path = NULL;
     121           0 :         _cleanup_fclose_ FILE *f = NULL;
     122             :         int r;
     123             : 
     124           0 :         assert(s);
     125             : 
     126           0 :         if (s->state != STDOUT_STREAM_RUNNING)
     127           0 :                 return 0;
     128             : 
     129           0 :         if (!s->state_file) {
     130             :                 struct stat st;
     131             : 
     132           0 :                 r = fstat(s->fd, &st);
     133           0 :                 if (r < 0)
     134           0 :                         return log_warning_errno(errno, "Failed to stat connected stream: %m");
     135             : 
     136             :                 /* We use device and inode numbers as identifier for the stream */
     137           0 :                 if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
     138           0 :                         return log_oom();
     139             :         }
     140             : 
     141           0 :         mkdir_p("/run/systemd/journal/streams", 0755);
     142             : 
     143           0 :         r = fopen_temporary(s->state_file, &f, &temp_path);
     144           0 :         if (r < 0)
     145           0 :                 goto finish;
     146             : 
     147           0 :         fprintf(f,
     148             :                 "# This is private data. Do not parse\n"
     149             :                 "PRIORITY=%i\n"
     150             :                 "LEVEL_PREFIX=%i\n"
     151             :                 "FORWARD_TO_SYSLOG=%i\n"
     152             :                 "FORWARD_TO_KMSG=%i\n"
     153             :                 "FORWARD_TO_CONSOLE=%i\n",
     154             :                 s->priority,
     155           0 :                 s->level_prefix,
     156           0 :                 s->forward_to_syslog,
     157           0 :                 s->forward_to_kmsg,
     158           0 :                 s->forward_to_console);
     159             : 
     160           0 :         if (!isempty(s->identifier)) {
     161           0 :                 _cleanup_free_ char *escaped;
     162             : 
     163           0 :                 escaped = cescape(s->identifier);
     164           0 :                 if (!escaped) {
     165           0 :                         r = -ENOMEM;
     166           0 :                         goto finish;
     167             :                 }
     168             : 
     169           0 :                 fprintf(f, "IDENTIFIER=%s\n", escaped);
     170             :         }
     171             : 
     172           0 :         if (!isempty(s->unit_id)) {
     173           0 :                 _cleanup_free_ char *escaped;
     174             : 
     175           0 :                 escaped = cescape(s->unit_id);
     176           0 :                 if (!escaped) {
     177           0 :                         r = -ENOMEM;
     178           0 :                         goto finish;
     179             :                 }
     180             : 
     181           0 :                 fprintf(f, "UNIT=%s\n", escaped);
     182             :         }
     183             : 
     184           0 :         r = fflush_and_check(f);
     185           0 :         if (r < 0)
     186           0 :                 goto finish;
     187             : 
     188           0 :         if (rename(temp_path, s->state_file) < 0) {
     189           0 :                 r = -errno;
     190           0 :                 goto finish;
     191             :         }
     192             : 
     193           0 :         free(temp_path);
     194           0 :         temp_path = NULL;
     195             : 
     196             :         /* Store the connection fd in PID 1, so that we get it passed
     197             :          * in again on next start */
     198           0 :         if (!s->fdstore) {
     199           0 :                 sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
     200           0 :                 s->fdstore = true;
     201             :         }
     202             : 
     203             : finish:
     204           0 :         if (temp_path)
     205           0 :                 unlink(temp_path);
     206             : 
     207           0 :         if (r < 0)
     208           0 :                 log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
     209             : 
     210           0 :         return r;
     211             : }
     212             : 
     213           0 : static int stdout_stream_log(StdoutStream *s, const char *p) {
     214             :         struct iovec iovec[N_IOVEC_META_FIELDS + 5];
     215             :         int priority;
     216           0 :         char syslog_priority[] = "PRIORITY=\0";
     217             :         char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
     218           0 :         _cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
     219           0 :         unsigned n = 0;
     220             :         size_t label_len;
     221             : 
     222           0 :         assert(s);
     223           0 :         assert(p);
     224             : 
     225           0 :         if (isempty(p))
     226           0 :                 return 0;
     227             : 
     228           0 :         priority = s->priority;
     229             : 
     230           0 :         if (s->level_prefix)
     231           0 :                 syslog_parse_priority(&p, &priority, false);
     232             : 
     233           0 :         if (s->forward_to_syslog || s->server->forward_to_syslog)
     234           0 :                 server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL);
     235             : 
     236           0 :         if (s->forward_to_kmsg || s->server->forward_to_kmsg)
     237           0 :                 server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred);
     238             : 
     239           0 :         if (s->forward_to_console || s->server->forward_to_console)
     240           0 :                 server_forward_console(s->server, priority, s->identifier, p, &s->ucred);
     241             : 
     242           0 :         if (s->server->forward_to_wall)
     243           0 :                 server_forward_wall(s->server, priority, s->identifier, p, &s->ucred);
     244             : 
     245           0 :         IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
     246             : 
     247           0 :         syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
     248           0 :         IOVEC_SET_STRING(iovec[n++], syslog_priority);
     249             : 
     250           0 :         if (priority & LOG_FACMASK) {
     251           0 :                 xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
     252           0 :                 IOVEC_SET_STRING(iovec[n++], syslog_facility);
     253             :         }
     254             : 
     255           0 :         if (s->identifier) {
     256           0 :                 syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
     257           0 :                 if (syslog_identifier)
     258           0 :                         IOVEC_SET_STRING(iovec[n++], syslog_identifier);
     259             :         }
     260             : 
     261           0 :         message = strappend("MESSAGE=", p);
     262           0 :         if (message)
     263           0 :                 IOVEC_SET_STRING(iovec[n++], message);
     264             : 
     265           0 :         label_len = s->label ? strlen(s->label) : 0;
     266           0 :         server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, s->label, label_len, s->unit_id, priority, 0);
     267           0 :         return 0;
     268             : }
     269             : 
     270           0 : static int stdout_stream_line(StdoutStream *s, char *p) {
     271             :         int r;
     272             : 
     273           0 :         assert(s);
     274           0 :         assert(p);
     275             : 
     276           0 :         p = strstrip(p);
     277             : 
     278           0 :         switch (s->state) {
     279             : 
     280             :         case STDOUT_STREAM_IDENTIFIER:
     281           0 :                 if (isempty(p))
     282           0 :                         s->identifier = NULL;
     283             :                 else  {
     284           0 :                         s->identifier = strdup(p);
     285           0 :                         if (!s->identifier)
     286           0 :                                 return log_oom();
     287             :                 }
     288             : 
     289           0 :                 s->state = STDOUT_STREAM_UNIT_ID;
     290           0 :                 return 0;
     291             : 
     292             :         case STDOUT_STREAM_UNIT_ID:
     293           0 :                 if (s->ucred.uid == 0) {
     294           0 :                         if (isempty(p))
     295           0 :                                 s->unit_id = NULL;
     296             :                         else  {
     297           0 :                                 s->unit_id = strdup(p);
     298           0 :                                 if (!s->unit_id)
     299           0 :                                         return log_oom();
     300             :                         }
     301             :                 }
     302             : 
     303           0 :                 s->state = STDOUT_STREAM_PRIORITY;
     304           0 :                 return 0;
     305             : 
     306             :         case STDOUT_STREAM_PRIORITY:
     307           0 :                 r = safe_atoi(p, &s->priority);
     308           0 :                 if (r < 0 || s->priority < 0 || s->priority > 999) {
     309           0 :                         log_warning("Failed to parse log priority line.");
     310           0 :                         return -EINVAL;
     311             :                 }
     312             : 
     313           0 :                 s->state = STDOUT_STREAM_LEVEL_PREFIX;
     314           0 :                 return 0;
     315             : 
     316             :         case STDOUT_STREAM_LEVEL_PREFIX:
     317           0 :                 r = parse_boolean(p);
     318           0 :                 if (r < 0) {
     319           0 :                         log_warning("Failed to parse level prefix line.");
     320           0 :                         return -EINVAL;
     321             :                 }
     322             : 
     323           0 :                 s->level_prefix = !!r;
     324           0 :                 s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG;
     325           0 :                 return 0;
     326             : 
     327             :         case STDOUT_STREAM_FORWARD_TO_SYSLOG:
     328           0 :                 r = parse_boolean(p);
     329           0 :                 if (r < 0) {
     330           0 :                         log_warning("Failed to parse forward to syslog line.");
     331           0 :                         return -EINVAL;
     332             :                 }
     333             : 
     334           0 :                 s->forward_to_syslog = !!r;
     335           0 :                 s->state = STDOUT_STREAM_FORWARD_TO_KMSG;
     336           0 :                 return 0;
     337             : 
     338             :         case STDOUT_STREAM_FORWARD_TO_KMSG:
     339           0 :                 r = parse_boolean(p);
     340           0 :                 if (r < 0) {
     341           0 :                         log_warning("Failed to parse copy to kmsg line.");
     342           0 :                         return -EINVAL;
     343             :                 }
     344             : 
     345           0 :                 s->forward_to_kmsg = !!r;
     346           0 :                 s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE;
     347           0 :                 return 0;
     348             : 
     349             :         case STDOUT_STREAM_FORWARD_TO_CONSOLE:
     350           0 :                 r = parse_boolean(p);
     351           0 :                 if (r < 0) {
     352           0 :                         log_warning("Failed to parse copy to console line.");
     353           0 :                         return -EINVAL;
     354             :                 }
     355             : 
     356           0 :                 s->forward_to_console = !!r;
     357           0 :                 s->state = STDOUT_STREAM_RUNNING;
     358             : 
     359             :                 /* Try to save the stream, so that journald can be restarted and we can recover */
     360           0 :                 (void) stdout_stream_save(s);
     361           0 :                 return 0;
     362             : 
     363             :         case STDOUT_STREAM_RUNNING:
     364           0 :                 return stdout_stream_log(s, p);
     365             :         }
     366             : 
     367           0 :         assert_not_reached("Unknown stream state");
     368             : }
     369             : 
     370           0 : static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
     371             :         char *p;
     372             :         size_t remaining;
     373             :         int r;
     374             : 
     375           0 :         assert(s);
     376             : 
     377           0 :         p = s->buffer;
     378           0 :         remaining = s->length;
     379             :         for (;;) {
     380             :                 char *end;
     381             :                 size_t skip;
     382             : 
     383           0 :                 end = memchr(p, '\n', remaining);
     384           0 :                 if (end)
     385           0 :                         skip = end - p + 1;
     386           0 :                 else if (remaining >= sizeof(s->buffer) - 1) {
     387           0 :                         end = p + sizeof(s->buffer) - 1;
     388           0 :                         skip = remaining;
     389             :                 } else
     390           0 :                         break;
     391             : 
     392           0 :                 *end = 0;
     393             : 
     394           0 :                 r = stdout_stream_line(s, p);
     395           0 :                 if (r < 0)
     396           0 :                         return r;
     397             : 
     398           0 :                 remaining -= skip;
     399           0 :                 p += skip;
     400           0 :         }
     401             : 
     402           0 :         if (force_flush && remaining > 0) {
     403           0 :                 p[remaining] = 0;
     404           0 :                 r = stdout_stream_line(s, p);
     405           0 :                 if (r < 0)
     406           0 :                         return r;
     407             : 
     408           0 :                 p += remaining;
     409           0 :                 remaining = 0;
     410             :         }
     411             : 
     412           0 :         if (p > s->buffer) {
     413           0 :                 memmove(s->buffer, p, remaining);
     414           0 :                 s->length = remaining;
     415             :         }
     416             : 
     417           0 :         return 0;
     418             : }
     419             : 
     420           0 : static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
     421           0 :         StdoutStream *s = userdata;
     422             :         ssize_t l;
     423             :         int r;
     424             : 
     425           0 :         assert(s);
     426             : 
     427           0 :         if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) {
     428           0 :                 log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents);
     429           0 :                 goto terminate;
     430             :         }
     431             : 
     432           0 :         l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
     433           0 :         if (l < 0) {
     434             : 
     435           0 :                 if (errno == EAGAIN)
     436           0 :                         return 0;
     437             : 
     438           0 :                 log_warning_errno(errno, "Failed to read from stream: %m");
     439           0 :                 goto terminate;
     440             :         }
     441             : 
     442           0 :         if (l == 0) {
     443           0 :                 stdout_stream_scan(s, true);
     444           0 :                 goto terminate;
     445             :         }
     446             : 
     447           0 :         s->length += l;
     448           0 :         r = stdout_stream_scan(s, false);
     449           0 :         if (r < 0)
     450           0 :                 goto terminate;
     451             : 
     452           0 :         return 1;
     453             : 
     454             : terminate:
     455           0 :         stdout_stream_destroy(s);
     456           0 :         return 0;
     457             : }
     458             : 
     459           0 : static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
     460           0 :         _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL;
     461             :         int r;
     462             : 
     463           0 :         assert(s);
     464           0 :         assert(fd >= 0);
     465             : 
     466           0 :         stream = new0(StdoutStream, 1);
     467           0 :         if (!stream)
     468           0 :                 return log_oom();
     469             : 
     470           0 :         stream->fd = -1;
     471           0 :         stream->priority = LOG_INFO;
     472             : 
     473           0 :         r = getpeercred(fd, &stream->ucred);
     474           0 :         if (r < 0)
     475           0 :                 return log_error_errno(r, "Failed to determine peer credentials: %m");
     476             : 
     477           0 :         if (mac_selinux_use()) {
     478           0 :                 r = getpeersec(fd, &stream->label);
     479           0 :                 if (r < 0 && r != -EOPNOTSUPP)
     480           0 :                         (void) log_warning_errno(r, "Failed to determine peer security context: %m");
     481             :         }
     482             : 
     483           0 :         (void) shutdown(fd, SHUT_WR);
     484             : 
     485           0 :         r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
     486           0 :         if (r < 0)
     487           0 :                 return log_error_errno(r, "Failed to add stream to event loop: %m");
     488             : 
     489           0 :         r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
     490           0 :         if (r < 0)
     491           0 :                 return log_error_errno(r, "Failed to adjust stdout event source priority: %m");
     492             : 
     493           0 :         stream->fd = fd;
     494             : 
     495           0 :         stream->server = s;
     496           0 :         LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
     497           0 :         s->n_stdout_streams ++;
     498             : 
     499           0 :         if (ret)
     500           0 :                 *ret = stream;
     501             : 
     502           0 :         stream = NULL;
     503             : 
     504           0 :         return 0;
     505             : }
     506             : 
     507           0 : static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) {
     508           0 :         _cleanup_close_ int fd = -1;
     509           0 :         Server *s = userdata;
     510             :         int r;
     511             : 
     512           0 :         assert(s);
     513             : 
     514           0 :         if (revents != EPOLLIN) {
     515           0 :                 log_error("Got invalid event from epoll for stdout server fd: %"PRIx32, revents);
     516           0 :                 return -EIO;
     517             :         }
     518             : 
     519           0 :         fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
     520           0 :         if (fd < 0) {
     521           0 :                 if (errno == EAGAIN)
     522           0 :                         return 0;
     523             : 
     524           0 :                 log_error_errno(errno, "Failed to accept stdout connection: %m");
     525           0 :                 return -errno;
     526             :         }
     527             : 
     528           0 :         if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
     529           0 :                 log_warning("Too many stdout streams, refusing connection.");
     530           0 :                 return 0;
     531             :         }
     532             : 
     533           0 :         r = stdout_stream_install(s, fd, NULL);
     534           0 :         if (r < 0)
     535           0 :                 return r;
     536             : 
     537           0 :         fd = -1;
     538           0 :         return 0;
     539             : }
     540             : 
     541           0 : static int stdout_stream_load(StdoutStream *stream, const char *fname) {
     542             :         _cleanup_free_ char
     543           0 :                 *priority = NULL,
     544           0 :                 *level_prefix = NULL,
     545           0 :                 *forward_to_syslog = NULL,
     546           0 :                 *forward_to_kmsg = NULL,
     547           0 :                 *forward_to_console = NULL;
     548             :         int r;
     549             : 
     550           0 :         assert(stream);
     551           0 :         assert(fname);
     552             : 
     553           0 :         if (!stream->state_file) {
     554           0 :                 stream->state_file = strappend("/run/systemd/journal/streams/", fname);
     555           0 :                 if (!stream->state_file)
     556           0 :                         return log_oom();
     557             :         }
     558             : 
     559           0 :         r = parse_env_file(stream->state_file, NEWLINE,
     560             :                            "PRIORITY", &priority,
     561             :                            "LEVEL_PREFIX", &level_prefix,
     562             :                            "FORWARD_TO_SYSLOG", &forward_to_syslog,
     563             :                            "FORWARD_TO_KMSG", &forward_to_kmsg,
     564             :                            "FORWARD_TO_CONSOLE", &forward_to_console,
     565             :                            "IDENTIFIER", &stream->identifier,
     566             :                            "UNIT", &stream->unit_id,
     567             :                            NULL);
     568           0 :         if (r < 0)
     569           0 :                 return log_error_errno(r, "Failed to read: %s", stream->state_file);
     570             : 
     571           0 :         if (priority) {
     572             :                 int p;
     573             : 
     574           0 :                 p = log_level_from_string(priority);
     575           0 :                 if (p >= 0)
     576           0 :                         stream->priority = p;
     577             :         }
     578             : 
     579           0 :         if (level_prefix) {
     580           0 :                 r = parse_boolean(level_prefix);
     581           0 :                 if (r >= 0)
     582           0 :                         stream->level_prefix = r;
     583             :         }
     584             : 
     585           0 :         if (forward_to_syslog) {
     586           0 :                 r = parse_boolean(forward_to_syslog);
     587           0 :                 if (r >= 0)
     588           0 :                         stream->forward_to_syslog = r;
     589             :         }
     590             : 
     591           0 :         if (forward_to_kmsg) {
     592           0 :                 r = parse_boolean(forward_to_kmsg);
     593           0 :                 if (r >= 0)
     594           0 :                         stream->forward_to_kmsg = r;
     595             :         }
     596             : 
     597           0 :         if (forward_to_console) {
     598           0 :                 r = parse_boolean(forward_to_console);
     599           0 :                 if (r >= 0)
     600           0 :                         stream->forward_to_console = r;
     601             :         }
     602             : 
     603           0 :         return 0;
     604             : }
     605             : 
     606           0 : static int stdout_stream_restore(Server *s, const char *fname, int fd) {
     607             :         StdoutStream *stream;
     608             :         int r;
     609             : 
     610           0 :         assert(s);
     611           0 :         assert(fname);
     612           0 :         assert(fd >= 0);
     613             : 
     614           0 :         if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
     615           0 :                 log_warning("Too many stdout streams, refusing restoring of stream.");
     616           0 :                 return -ENOBUFS;
     617             :         }
     618             : 
     619           0 :         r = stdout_stream_install(s, fd, &stream);
     620           0 :         if (r < 0)
     621           0 :                 return r;
     622             : 
     623           0 :         stream->state = STDOUT_STREAM_RUNNING;
     624           0 :         stream->fdstore = true;
     625             : 
     626             :         /* Ignore all parsing errors */
     627           0 :         (void) stdout_stream_load(stream, fname);
     628             : 
     629           0 :         return 0;
     630             : }
     631             : 
     632           0 : static int server_restore_streams(Server *s, FDSet *fds) {
     633           0 :         _cleanup_closedir_ DIR *d = NULL;
     634             :         struct dirent *de;
     635             :         int r;
     636             : 
     637           0 :         d = opendir("/run/systemd/journal/streams");
     638           0 :         if (!d) {
     639           0 :                 if (errno == ENOENT)
     640           0 :                         return 0;
     641             : 
     642           0 :                 return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m");
     643             :         }
     644             : 
     645           0 :         FOREACH_DIRENT(de, d, goto fail) {
     646             :                 unsigned long st_dev, st_ino;
     647           0 :                 bool found = false;
     648             :                 Iterator i;
     649             :                 int fd;
     650             : 
     651           0 :                 if (sscanf(de->d_name, "%lu:%lu", &st_dev, &st_ino) != 2)
     652           0 :                         continue;
     653             : 
     654           0 :                 FDSET_FOREACH(fd, fds, i) {
     655             :                         struct stat st;
     656             : 
     657           0 :                         if (fstat(fd, &st) < 0)
     658           0 :                                 return log_error_errno(errno, "Failed to stat %s: %m", de->d_name);
     659             : 
     660           0 :                         if (S_ISSOCK(st.st_mode) && st.st_dev == st_dev && st.st_ino == st_ino) {
     661           0 :                                 found = true;
     662           0 :                                 break;
     663             :                         }
     664             :                 }
     665             : 
     666           0 :                 if (!found) {
     667             :                         /* No file descriptor? Then let's delete the state file */
     668           0 :                         log_debug("Cannot restore stream file %s", de->d_name);
     669           0 :                         unlinkat(dirfd(d), de->d_name, 0);
     670           0 :                         continue;
     671             :                 }
     672             : 
     673           0 :                 fdset_remove(fds, fd);
     674             : 
     675           0 :                 r = stdout_stream_restore(s, de->d_name, fd);
     676           0 :                 if (r < 0)
     677           0 :                         safe_close(fd);
     678           0 :         }
     679             : 
     680           0 :         return 0;
     681             : 
     682             : fail:
     683           0 :         return log_error_errno(errno, "Failed to read streams directory: %m");
     684             : }
     685             : 
     686           0 : int server_open_stdout_socket(Server *s, FDSet *fds) {
     687             :         int r;
     688             : 
     689           0 :         assert(s);
     690             : 
     691           0 :         if (s->stdout_fd < 0) {
     692           0 :                 union sockaddr_union sa = {
     693             :                         .un.sun_family = AF_UNIX,
     694             :                         .un.sun_path = "/run/systemd/journal/stdout",
     695             :                 };
     696             : 
     697           0 :                 s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
     698           0 :                 if (s->stdout_fd < 0)
     699           0 :                         return log_error_errno(errno, "socket() failed: %m");
     700             : 
     701           0 :                 unlink(sa.un.sun_path);
     702             : 
     703           0 :                 r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
     704           0 :                 if (r < 0)
     705           0 :                         return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
     706             : 
     707           0 :                 (void) chmod(sa.un.sun_path, 0666);
     708             : 
     709           0 :                 if (listen(s->stdout_fd, SOMAXCONN) < 0)
     710           0 :                         return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
     711             :         } else
     712           0 :                 fd_nonblock(s->stdout_fd, 1);
     713             : 
     714           0 :         r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
     715           0 :         if (r < 0)
     716           0 :                 return log_error_errno(r, "Failed to add stdout server fd to event source: %m");
     717             : 
     718           0 :         r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10);
     719           0 :         if (r < 0)
     720           0 :                 return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
     721             : 
     722             :         /* Try to restore streams, but don't bother if this fails */
     723           0 :         (void) server_restore_streams(s, fds);
     724             : 
     725           0 :         return 0;
     726             : }

Generated by: LCOV version 1.11