LCOV - code coverage report
Current view: top level - journal-remote - journal-remote-main.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 35 554 6.3 %
Date: 2019-08-22 15:41:25 Functions: 9 28 32.1 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <getopt.h>
       4             : #include <unistd.h>
       5             : 
       6             : #include "sd-daemon.h"
       7             : 
       8             : #include "conf-parser.h"
       9             : #include "daemon-util.h"
      10             : #include "def.h"
      11             : #include "fd-util.h"
      12             : #include "fileio.h"
      13             : #include "journal-remote-write.h"
      14             : #include "journal-remote.h"
      15             : #include "main-func.h"
      16             : #include "pretty-print.h"
      17             : #include "process-util.h"
      18             : #include "rlimit-util.h"
      19             : #include "signal-util.h"
      20             : #include "socket-util.h"
      21             : #include "stat-util.h"
      22             : #include "string-table.h"
      23             : #include "strv.h"
      24             : 
      25             : #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
      26             : #define CERT_FILE     CERTIFICATE_ROOT "/certs/journal-remote.pem"
      27             : #define TRUST_FILE    CERTIFICATE_ROOT "/ca/trusted.pem"
      28             : 
      29             : static const char* arg_url = NULL;
      30             : static const char* arg_getter = NULL;
      31             : static const char* arg_listen_raw = NULL;
      32             : static const char* arg_listen_http = NULL;
      33             : static const char* arg_listen_https = NULL;
      34             : static char** arg_files = NULL; /* Do not free this. */
      35             : static int arg_compress = true;
      36             : static int arg_seal = false;
      37             : static int http_socket = -1, https_socket = -1;
      38             : static char** arg_gnutls_log = NULL;
      39             : 
      40             : static JournalWriteSplitMode arg_split_mode = _JOURNAL_WRITE_SPLIT_INVALID;
      41             : static const char* arg_output = NULL;
      42             : 
      43             : static char *arg_key = NULL;
      44             : static char *arg_cert = NULL;
      45             : static char *arg_trust = NULL;
      46             : static bool arg_trust_all = false;
      47             : 
      48           4 : STATIC_DESTRUCTOR_REGISTER(arg_gnutls_log, strv_freep);
      49           4 : STATIC_DESTRUCTOR_REGISTER(arg_key, freep);
      50           4 : STATIC_DESTRUCTOR_REGISTER(arg_cert, freep);
      51           4 : STATIC_DESTRUCTOR_REGISTER(arg_trust, freep);
      52             : 
      53             : static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
      54             :         [JOURNAL_WRITE_SPLIT_NONE] = "none",
      55             :         [JOURNAL_WRITE_SPLIT_HOST] = "host",
      56             : };
      57             : 
      58           0 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
      59           0 : static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
      60             :                                 journal_write_split_mode,
      61             :                                 JournalWriteSplitMode,
      62             :                                 "Failed to parse split mode setting");
      63             : 
      64             : /**********************************************************************
      65             :  **********************************************************************
      66             :  **********************************************************************/
      67             : 
      68           0 : static int spawn_child(const char* child, char** argv) {
      69             :         pid_t child_pid;
      70             :         int fd[2], r;
      71             : 
      72           0 :         if (pipe(fd) < 0)
      73           0 :                 return log_error_errno(errno, "Failed to create pager pipe: %m");
      74             : 
      75           0 :         r = safe_fork("(remote)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &child_pid);
      76           0 :         if (r < 0) {
      77           0 :                 safe_close_pair(fd);
      78           0 :                 return r;
      79             :         }
      80             : 
      81             :         /* In the child */
      82           0 :         if (r == 0) {
      83           0 :                 safe_close(fd[0]);
      84             : 
      85           0 :                 r = rearrange_stdio(STDIN_FILENO, fd[1], STDERR_FILENO);
      86           0 :                 if (r < 0) {
      87           0 :                         log_error_errno(r, "Failed to dup pipe to stdout: %m");
      88           0 :                         _exit(EXIT_FAILURE);
      89             :                 }
      90             : 
      91           0 :                 (void) rlimit_nofile_safe();
      92             : 
      93           0 :                 execvp(child, argv);
      94           0 :                 log_error_errno(errno, "Failed to exec child %s: %m", child);
      95           0 :                 _exit(EXIT_FAILURE);
      96             :         }
      97             : 
      98           0 :         safe_close(fd[1]);
      99             : 
     100           0 :         r = fd_nonblock(fd[0], true);
     101           0 :         if (r < 0)
     102           0 :                 log_warning_errno(errno, "Failed to set child pipe to non-blocking: %m");
     103             : 
     104           0 :         return fd[0];
     105             : }
     106             : 
     107           0 : static int spawn_curl(const char* url) {
     108           0 :         char **argv = STRV_MAKE("curl",
     109             :                                 "-HAccept: application/vnd.fdo.journal",
     110             :                                 "--silent",
     111             :                                 "--show-error",
     112             :                                 url);
     113             :         int r;
     114             : 
     115           0 :         r = spawn_child("curl", argv);
     116           0 :         if (r < 0)
     117           0 :                 log_error_errno(r, "Failed to spawn curl: %m");
     118           0 :         return r;
     119             : }
     120             : 
     121           0 : static int spawn_getter(const char *getter) {
     122             :         int r;
     123           0 :         _cleanup_strv_free_ char **words = NULL;
     124             : 
     125           0 :         assert(getter);
     126           0 :         r = strv_split_extract(&words, getter, WHITESPACE, EXTRACT_UNQUOTE);
     127           0 :         if (r < 0)
     128           0 :                 return log_error_errno(r, "Failed to split getter option: %m");
     129             : 
     130           0 :         r = spawn_child(words[0], words);
     131           0 :         if (r < 0)
     132           0 :                 log_error_errno(r, "Failed to spawn getter %s: %m", getter);
     133             : 
     134           0 :         return r;
     135             : }
     136             : 
     137             : /**********************************************************************
     138             :  **********************************************************************
     139             :  **********************************************************************/
     140             : 
     141             : static int null_timer_event_handler(sd_event_source *s,
     142             :                                 uint64_t usec,
     143             :                                 void *userdata);
     144             : static int dispatch_http_event(sd_event_source *event,
     145             :                                int fd,
     146             :                                uint32_t revents,
     147             :                                void *userdata);
     148             : 
     149           0 : static int request_meta(void **connection_cls, int fd, char *hostname) {
     150             :         RemoteSource *source;
     151             :         Writer *writer;
     152             :         int r;
     153             : 
     154           0 :         assert(connection_cls);
     155           0 :         if (*connection_cls)
     156           0 :                 return 0;
     157             : 
     158           0 :         r = journal_remote_get_writer(journal_remote_server_global, hostname, &writer);
     159           0 :         if (r < 0)
     160           0 :                 return log_warning_errno(r, "Failed to get writer for source %s: %m",
     161             :                                          hostname);
     162             : 
     163           0 :         source = source_new(fd, true, hostname, writer);
     164           0 :         if (!source) {
     165           0 :                 writer_unref(writer);
     166           0 :                 return log_oom();
     167             :         }
     168             : 
     169           0 :         log_debug("Added RemoteSource as connection metadata %p", source);
     170             : 
     171           0 :         *connection_cls = source;
     172           0 :         return 0;
     173             : }
     174             : 
     175           0 : static void request_meta_free(void *cls,
     176             :                               struct MHD_Connection *connection,
     177             :                               void **connection_cls,
     178             :                               enum MHD_RequestTerminationCode toe) {
     179             :         RemoteSource *s;
     180             : 
     181           0 :         assert(connection_cls);
     182           0 :         s = *connection_cls;
     183             : 
     184           0 :         if (s) {
     185           0 :                 log_debug("Cleaning up connection metadata %p", s);
     186           0 :                 source_free(s);
     187           0 :                 *connection_cls = NULL;
     188             :         }
     189           0 : }
     190             : 
     191           0 : static int process_http_upload(
     192             :                 struct MHD_Connection *connection,
     193             :                 const char *upload_data,
     194             :                 size_t *upload_data_size,
     195             :                 RemoteSource *source) {
     196             : 
     197           0 :         bool finished = false;
     198             :         size_t remaining;
     199             :         int r;
     200             : 
     201           0 :         assert(source);
     202             : 
     203           0 :         log_trace("%s: connection %p, %zu bytes",
     204             :                   __func__, connection, *upload_data_size);
     205             : 
     206           0 :         if (*upload_data_size) {
     207           0 :                 log_trace("Received %zu bytes", *upload_data_size);
     208             : 
     209           0 :                 r = journal_importer_push_data(&source->importer,
     210             :                                                upload_data, *upload_data_size);
     211           0 :                 if (r < 0)
     212           0 :                         return mhd_respond_oom(connection);
     213             : 
     214           0 :                 *upload_data_size = 0;
     215             :         } else
     216           0 :                 finished = true;
     217             : 
     218             :         for (;;) {
     219           0 :                 r = process_source(source,
     220           0 :                                    journal_remote_server_global->compress,
     221           0 :                                    journal_remote_server_global->seal);
     222           0 :                 if (r == -EAGAIN)
     223           0 :                         break;
     224           0 :                 if (r < 0) {
     225           0 :                         if (r == -ENOBUFS)
     226           0 :                                 log_warning_errno(r, "Entry is above the maximum of %u, aborting connection %p.",
     227             :                                                   DATA_SIZE_MAX, connection);
     228           0 :                         else if (r == -E2BIG)
     229           0 :                                 log_warning_errno(r, "Entry with more fields than the maximum of %u, aborting connection %p.",
     230             :                                                   ENTRY_FIELD_COUNT_MAX, connection);
     231             :                         else
     232           0 :                                 log_warning_errno(r, "Failed to process data, aborting connection %p: %m",
     233             :                                                   connection);
     234           0 :                         return MHD_NO;
     235             :                 }
     236             :         }
     237             : 
     238           0 :         if (!finished)
     239           0 :                 return MHD_YES;
     240             : 
     241             :         /* The upload is finished */
     242             : 
     243           0 :         remaining = journal_importer_bytes_remaining(&source->importer);
     244           0 :         if (remaining > 0) {
     245           0 :                 log_warning("Premature EOF byte. %zu bytes lost.", remaining);
     246           0 :                 return mhd_respondf(connection,
     247             :                                     0, MHD_HTTP_EXPECTATION_FAILED,
     248             :                                     "Premature EOF. %zu bytes of trailing data not processed.",
     249             :                                     remaining);
     250             :         }
     251             : 
     252           0 :         return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.");
     253             : };
     254             : 
     255           0 : static int request_handler(
     256             :                 void *cls,
     257             :                 struct MHD_Connection *connection,
     258             :                 const char *url,
     259             :                 const char *method,
     260             :                 const char *version,
     261             :                 const char *upload_data,
     262             :                 size_t *upload_data_size,
     263             :                 void **connection_cls) {
     264             : 
     265             :         const char *header;
     266             :         int r, code, fd;
     267           0 :         _cleanup_free_ char *hostname = NULL;
     268           0 :         bool chunked = false;
     269             :         size_t len;
     270             : 
     271           0 :         assert(connection);
     272           0 :         assert(connection_cls);
     273           0 :         assert(url);
     274           0 :         assert(method);
     275             : 
     276           0 :         log_trace("Handling a connection %s %s %s", method, url, version);
     277             : 
     278           0 :         if (*connection_cls)
     279           0 :                 return process_http_upload(connection,
     280             :                                            upload_data, upload_data_size,
     281             :                                            *connection_cls);
     282             : 
     283           0 :         if (!streq(method, "POST"))
     284           0 :                 return mhd_respond(connection, MHD_HTTP_NOT_ACCEPTABLE, "Unsupported method.");
     285             : 
     286           0 :         if (!streq(url, "/upload"))
     287           0 :                 return mhd_respond(connection, MHD_HTTP_NOT_FOUND, "Not found.");
     288             : 
     289           0 :         header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Type");
     290           0 :         if (!header || !streq(header, "application/vnd.fdo.journal"))
     291           0 :                 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
     292             :                                    "Content-Type: application/vnd.fdo.journal is required.");
     293             : 
     294           0 :         header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Transfer-Encoding");
     295           0 :         if (header) {
     296           0 :                 if (!strcaseeq(header, "chunked"))
     297           0 :                         return mhd_respondf(connection, 0, MHD_HTTP_BAD_REQUEST,
     298             :                                             "Unsupported Transfer-Encoding type: %s", header);
     299             : 
     300           0 :                 chunked = true;
     301             :         }
     302             : 
     303           0 :         header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length");
     304           0 :         if (header) {
     305           0 :                 if (chunked)
     306           0 :                         return mhd_respond(connection, MHD_HTTP_BAD_REQUEST,
     307             :                                            "Content-Length must not specified when Transfer-Encoding type is 'chuncked'");
     308             : 
     309           0 :                 r = safe_atozu(header, &len);
     310           0 :                 if (r < 0)
     311           0 :                         return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED,
     312             :                                             "Content-Length: %s cannot be parsed: %m", header);
     313             : 
     314           0 :                 if (len > ENTRY_SIZE_MAX)
     315             :                         /* When serialized, an entry of maximum size might be slightly larger,
     316             :                          * so this does not correspond exactly to the limit in journald. Oh well.
     317             :                          */
     318           0 :                         return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE,
     319             :                                             "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX);
     320             :         }
     321             : 
     322             :         {
     323             :                 const union MHD_ConnectionInfo *ci;
     324             : 
     325           0 :                 ci = MHD_get_connection_info(connection,
     326             :                                              MHD_CONNECTION_INFO_CONNECTION_FD);
     327           0 :                 if (!ci) {
     328           0 :                         log_error("MHD_get_connection_info failed: cannot get remote fd");
     329           0 :                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
     330             :                                            "Cannot check remote address.");
     331             :                 }
     332             : 
     333           0 :                 fd = ci->connect_fd;
     334           0 :                 assert(fd >= 0);
     335             :         }
     336             : 
     337           0 :         if (journal_remote_server_global->check_trust) {
     338           0 :                 r = check_permissions(connection, &code, &hostname);
     339           0 :                 if (r < 0)
     340           0 :                         return code;
     341             :         } else {
     342           0 :                 r = getpeername_pretty(fd, false, &hostname);
     343           0 :                 if (r < 0)
     344           0 :                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
     345             :                                            "Cannot check remote hostname.");
     346             :         }
     347             : 
     348           0 :         assert(hostname);
     349             : 
     350           0 :         r = request_meta(connection_cls, fd, hostname);
     351           0 :         if (r == -ENOMEM)
     352           0 :                 return respond_oom(connection);
     353           0 :         else if (r < 0)
     354           0 :                 return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "%m");
     355             : 
     356           0 :         hostname = NULL;
     357           0 :         return MHD_YES;
     358             : }
     359             : 
     360           0 : static int setup_microhttpd_server(RemoteServer *s,
     361             :                                    int fd,
     362             :                                    const char *key,
     363             :                                    const char *cert,
     364             :                                    const char *trust) {
     365           0 :         struct MHD_OptionItem opts[] = {
     366           0 :                 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
     367           0 :                 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
     368             :                 { MHD_OPTION_LISTEN_SOCKET, fd},
     369             :                 { MHD_OPTION_CONNECTION_MEMORY_LIMIT, 128*1024},
     370             :                 { MHD_OPTION_END},
     371             :                 { MHD_OPTION_END},
     372             :                 { MHD_OPTION_END},
     373             :                 { MHD_OPTION_END},
     374             :                 { MHD_OPTION_END}};
     375           0 :         int opts_pos = 4;
     376           0 :         int flags =
     377             :                 MHD_USE_DEBUG |
     378             :                 MHD_USE_DUAL_STACK |
     379             :                 MHD_USE_EPOLL |
     380             :                 MHD_USE_ITC;
     381             : 
     382             :         const union MHD_DaemonInfo *info;
     383             :         int r, epoll_fd;
     384             :         MHDDaemonWrapper *d;
     385             : 
     386           0 :         assert(fd >= 0);
     387             : 
     388           0 :         r = fd_nonblock(fd, true);
     389           0 :         if (r < 0)
     390           0 :                 return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
     391             : 
     392             : /* MHD_OPTION_STRICT_FOR_CLIENT is introduced in microhttpd 0.9.54,
     393             :  * and MHD_USE_PEDANTIC_CHECKS will be deprecated in future.
     394             :  * If MHD_USE_PEDANTIC_CHECKS is '#define'd, then it is deprecated
     395             :  * and we should use MHD_OPTION_STRICT_FOR_CLIENT. On the other hand,
     396             :  * if MHD_USE_PEDANTIC_CHECKS is not '#define'd, then it is not
     397             :  * deprecated yet and there exists an enum element with the same name.
     398             :  * So we can safely use it. */
     399             : #ifdef MHD_USE_PEDANTIC_CHECKS
     400             :         opts[opts_pos++] = (struct MHD_OptionItem)
     401             :                 {MHD_OPTION_STRICT_FOR_CLIENT, 1};
     402             : #else
     403           0 :         flags |= MHD_USE_PEDANTIC_CHECKS;
     404             : #endif
     405             : 
     406           0 :         if (key) {
     407           0 :                 assert(cert);
     408             : 
     409           0 :                 opts[opts_pos++] = (struct MHD_OptionItem)
     410             :                         {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
     411           0 :                 opts[opts_pos++] = (struct MHD_OptionItem)
     412             :                         {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
     413             : 
     414           0 :                 flags |= MHD_USE_TLS;
     415             : 
     416           0 :                 if (trust)
     417           0 :                         opts[opts_pos++] = (struct MHD_OptionItem)
     418             :                                 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
     419             :         }
     420             : 
     421           0 :         d = new(MHDDaemonWrapper, 1);
     422           0 :         if (!d)
     423           0 :                 return log_oom();
     424             : 
     425           0 :         d->fd = (uint64_t) fd;
     426             : 
     427           0 :         d->daemon = MHD_start_daemon(flags, 0,
     428             :                                      NULL, NULL,
     429             :                                      request_handler, NULL,
     430             :                                      MHD_OPTION_ARRAY, opts,
     431             :                                      MHD_OPTION_END);
     432           0 :         if (!d->daemon) {
     433           0 :                 log_error("Failed to start µhttp daemon");
     434           0 :                 r = -EINVAL;
     435           0 :                 goto error;
     436             :         }
     437             : 
     438           0 :         log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
     439             :                   key ? "HTTPS" : "HTTP", fd, d);
     440             : 
     441           0 :         info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
     442           0 :         if (!info) {
     443           0 :                 log_error("µhttp returned NULL daemon info");
     444           0 :                 r = -EOPNOTSUPP;
     445           0 :                 goto error;
     446             :         }
     447             : 
     448           0 :         epoll_fd = info->listen_fd;
     449           0 :         if (epoll_fd < 0) {
     450           0 :                 log_error("µhttp epoll fd is invalid");
     451           0 :                 r = -EUCLEAN;
     452           0 :                 goto error;
     453             :         }
     454             : 
     455           0 :         r = sd_event_add_io(s->events, &d->io_event,
     456             :                             epoll_fd, EPOLLIN,
     457             :                             dispatch_http_event, d);
     458           0 :         if (r < 0) {
     459           0 :                 log_error_errno(r, "Failed to add event callback: %m");
     460           0 :                 goto error;
     461             :         }
     462             : 
     463           0 :         r = sd_event_source_set_description(d->io_event, "io_event");
     464           0 :         if (r < 0) {
     465           0 :                 log_error_errno(r, "Failed to set source name: %m");
     466           0 :                 goto error;
     467             :         }
     468             : 
     469           0 :         r = sd_event_add_time(s->events, &d->timer_event,
     470             :                               CLOCK_MONOTONIC, (uint64_t) -1, 0,
     471             :                               null_timer_event_handler, d);
     472           0 :         if (r < 0) {
     473           0 :                 log_error_errno(r, "Failed to add timer_event: %m");
     474           0 :                 goto error;
     475             :         }
     476             : 
     477           0 :         r = sd_event_source_set_description(d->timer_event, "timer_event");
     478           0 :         if (r < 0) {
     479           0 :                 log_error_errno(r, "Failed to set source name: %m");
     480           0 :                 goto error;
     481             :         }
     482             : 
     483           0 :         r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
     484           0 :         if (r < 0) {
     485           0 :                 log_oom();
     486           0 :                 goto error;
     487             :         }
     488             : 
     489           0 :         r = hashmap_put(s->daemons, &d->fd, d);
     490           0 :         if (r < 0) {
     491           0 :                 log_error_errno(r, "Failed to add daemon to hashmap: %m");
     492           0 :                 goto error;
     493             :         }
     494             : 
     495           0 :         s->active++;
     496           0 :         return 0;
     497             : 
     498           0 : error:
     499           0 :         MHD_stop_daemon(d->daemon);
     500           0 :         free(d->daemon);
     501           0 :         free(d);
     502           0 :         return r;
     503             : }
     504             : 
     505           0 : static int setup_microhttpd_socket(RemoteServer *s,
     506             :                                    const char *address,
     507             :                                    const char *key,
     508             :                                    const char *cert,
     509             :                                    const char *trust) {
     510             :         int fd;
     511             : 
     512           0 :         fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM, SOCK_CLOEXEC);
     513           0 :         if (fd < 0)
     514           0 :                 return fd;
     515             : 
     516           0 :         return setup_microhttpd_server(s, fd, key, cert, trust);
     517             : }
     518             : 
     519           0 : static int null_timer_event_handler(sd_event_source *timer_event,
     520             :                                     uint64_t usec,
     521             :                                     void *userdata) {
     522           0 :         return dispatch_http_event(timer_event, 0, 0, userdata);
     523             : }
     524             : 
     525           0 : static int dispatch_http_event(sd_event_source *event,
     526             :                                int fd,
     527             :                                uint32_t revents,
     528             :                                void *userdata) {
     529           0 :         MHDDaemonWrapper *d = userdata;
     530             :         int r;
     531           0 :         MHD_UNSIGNED_LONG_LONG timeout = ULLONG_MAX;
     532             : 
     533           0 :         assert(d);
     534             : 
     535           0 :         r = MHD_run(d->daemon);
     536           0 :         if (r == MHD_NO)
     537             :                 // FIXME: unregister daemon
     538           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     539             :                                        "MHD_run failed!");
     540           0 :         if (MHD_get_timeout(d->daemon, &timeout) == MHD_NO)
     541           0 :                 timeout = ULLONG_MAX;
     542             : 
     543           0 :         r = sd_event_source_set_time(d->timer_event, timeout);
     544           0 :         if (r < 0) {
     545           0 :                 log_warning_errno(r, "Unable to set event loop timeout: %m, this may result in indefinite blocking!");
     546           0 :                 return 1;
     547             :         }
     548             : 
     549           0 :         r = sd_event_source_set_enabled(d->timer_event, SD_EVENT_ON);
     550           0 :         if (r < 0)
     551           0 :                 log_warning_errno(r, "Unable to enable timer_event: %m, this may result in indefinite blocking!");
     552             : 
     553           0 :         return 1; /* work to do */
     554             : }
     555             : 
     556             : /**********************************************************************
     557             :  **********************************************************************
     558             :  **********************************************************************/
     559             : 
     560           0 : static int setup_signals(RemoteServer *s) {
     561             :         int r;
     562             : 
     563           0 :         assert(s);
     564             : 
     565           0 :         assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, -1) >= 0);
     566             : 
     567           0 :         r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
     568           0 :         if (r < 0)
     569           0 :                 return r;
     570             : 
     571           0 :         r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
     572           0 :         if (r < 0)
     573           0 :                 return r;
     574             : 
     575           0 :         return 0;
     576             : }
     577             : 
     578           0 : static int setup_raw_socket(RemoteServer *s, const char *address) {
     579             :         int fd;
     580             : 
     581           0 :         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM, SOCK_CLOEXEC);
     582           0 :         if (fd < 0)
     583           0 :                 return fd;
     584             : 
     585           0 :         return journal_remote_add_raw_socket(s, fd);
     586             : }
     587             : 
     588           0 : static int create_remoteserver(
     589             :                 RemoteServer *s,
     590             :                 const char* key,
     591             :                 const char* cert,
     592             :                 const char* trust) {
     593             : 
     594             :         int r, n, fd;
     595             :         char **file;
     596             : 
     597           0 :         r = journal_remote_server_init(s, arg_output, arg_split_mode, arg_compress, arg_seal);
     598           0 :         if (r < 0)
     599           0 :                 return r;
     600             : 
     601           0 :         r = setup_signals(s);
     602           0 :         if (r < 0)
     603           0 :                 return log_error_errno(r, "Failed to set up signals: %m");
     604             : 
     605           0 :         n = sd_listen_fds(true);
     606           0 :         if (n < 0)
     607           0 :                 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
     608             :         else
     609           0 :                 log_debug("Received %d descriptors", n);
     610             : 
     611           0 :         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n)
     612           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EBADFD),
     613             :                                        "Received fewer sockets than expected");
     614             : 
     615           0 :         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
     616           0 :                 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
     617           0 :                         log_debug("Received a listening socket (fd:%d)", fd);
     618             : 
     619           0 :                         if (fd == http_socket)
     620           0 :                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
     621           0 :                         else if (fd == https_socket)
     622           0 :                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
     623             :                         else
     624           0 :                                 r = journal_remote_add_raw_socket(s, fd);
     625           0 :                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
     626             :                         char *hostname;
     627             : 
     628           0 :                         r = getpeername_pretty(fd, false, &hostname);
     629           0 :                         if (r < 0)
     630           0 :                                 return log_error_errno(r, "Failed to retrieve remote name: %m");
     631             : 
     632           0 :                         log_debug("Received a connection socket (fd:%d) from %s", fd, hostname);
     633             : 
     634           0 :                         r = journal_remote_add_source(s, fd, hostname, true);
     635             :                 } else
     636           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     637             :                                                "Unknown socket passed on fd:%d", fd);
     638             : 
     639           0 :                 if (r < 0)
     640           0 :                         return log_error_errno(r, "Failed to register socket (fd:%d): %m", fd);
     641             :         }
     642             : 
     643           0 :         if (arg_getter) {
     644           0 :                 log_info("Spawning getter %s...", arg_getter);
     645           0 :                 fd = spawn_getter(arg_getter);
     646           0 :                 if (fd < 0)
     647           0 :                         return fd;
     648             : 
     649           0 :                 r = journal_remote_add_source(s, fd, (char*) arg_output, false);
     650           0 :                 if (r < 0)
     651           0 :                         return r;
     652             :         }
     653             : 
     654           0 :         if (arg_url) {
     655             :                 const char *url, *hostname;
     656             : 
     657           0 :                 if (!strstr(arg_url, "/entries")) {
     658           0 :                         if (endswith(arg_url, "/"))
     659           0 :                                 url = strjoina(arg_url, "entries");
     660             :                         else
     661           0 :                                 url = strjoina(arg_url, "/entries");
     662             :                 } else
     663           0 :                         url = strdupa(arg_url);
     664             : 
     665           0 :                 log_info("Spawning curl %s...", url);
     666           0 :                 fd = spawn_curl(url);
     667           0 :                 if (fd < 0)
     668           0 :                         return fd;
     669             : 
     670           0 :                 hostname = STARTSWITH_SET(arg_url, "https://", "http://");
     671           0 :                 if (!hostname)
     672           0 :                         hostname = arg_url;
     673             : 
     674           0 :                 hostname = strndupa(hostname, strcspn(hostname, "/:"));
     675             : 
     676           0 :                 r = journal_remote_add_source(s, fd, (char *) hostname, false);
     677           0 :                 if (r < 0)
     678           0 :                         return r;
     679             :         }
     680             : 
     681           0 :         if (arg_listen_raw) {
     682           0 :                 log_debug("Listening on a socket...");
     683           0 :                 r = setup_raw_socket(s, arg_listen_raw);
     684           0 :                 if (r < 0)
     685           0 :                         return r;
     686             :         }
     687             : 
     688           0 :         if (arg_listen_http) {
     689           0 :                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
     690           0 :                 if (r < 0)
     691           0 :                         return r;
     692             :         }
     693             : 
     694           0 :         if (arg_listen_https) {
     695           0 :                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
     696           0 :                 if (r < 0)
     697           0 :                         return r;
     698             :         }
     699             : 
     700           0 :         STRV_FOREACH(file, arg_files) {
     701             :                 const char *output_name;
     702             : 
     703           0 :                 if (streq(*file, "-")) {
     704           0 :                         log_debug("Using standard input as source.");
     705             : 
     706           0 :                         fd = STDIN_FILENO;
     707           0 :                         output_name = "stdin";
     708             :                 } else {
     709           0 :                         log_debug("Reading file %s...", *file);
     710             : 
     711           0 :                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
     712           0 :                         if (fd < 0)
     713           0 :                                 return log_error_errno(errno, "Failed to open %s: %m", *file);
     714           0 :                         output_name = *file;
     715             :                 }
     716             : 
     717           0 :                 r = journal_remote_add_source(s, fd, (char*) output_name, false);
     718           0 :                 if (r < 0)
     719           0 :                         return r;
     720             :         }
     721             : 
     722           0 :         if (s->active == 0)
     723           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     724             :                                        "Zero sources specified");
     725             : 
     726           0 :         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
     727             :                 /* In this case we know what the writer will be
     728             :                    called, so we can create it and verify that we can
     729             :                    create output as expected. */
     730           0 :                 r = journal_remote_get_writer(s, NULL, &s->_single_writer);
     731           0 :                 if (r < 0)
     732           0 :                         return r;
     733             :         }
     734             : 
     735           0 :         return 0;
     736             : }
     737             : 
     738           0 : static int negative_fd(const char *spec) {
     739             :         /* Return a non-positive number as its inverse, -EINVAL otherwise. */
     740             : 
     741             :         int fd, r;
     742             : 
     743           0 :         r = safe_atoi(spec, &fd);
     744           0 :         if (r < 0)
     745           0 :                 return r;
     746             : 
     747           0 :         if (fd > 0)
     748           0 :                 return -EINVAL;
     749             :         else
     750           0 :                 return -fd;
     751             : }
     752             : 
     753           4 : static int parse_config(void) {
     754           4 :         const ConfigTableItem items[] = {
     755             :                 { "Remote",  "Seal",                   config_parse_bool,             0, &arg_seal       },
     756             :                 { "Remote",  "SplitMode",              config_parse_write_split_mode, 0, &arg_split_mode },
     757             :                 { "Remote",  "ServerKeyFile",          config_parse_path,             0, &arg_key        },
     758             :                 { "Remote",  "ServerCertificateFile",  config_parse_path,             0, &arg_cert       },
     759             :                 { "Remote",  "TrustedCertificateFile", config_parse_path,             0, &arg_trust      },
     760             :                 {}
     761             :         };
     762             : 
     763           4 :         return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf",
     764             :                                         CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
     765             :                                         "Remote\0", config_item_table_lookup, items,
     766             :                                         CONFIG_PARSE_WARN, NULL);
     767             : }
     768             : 
     769           3 : static int help(void) {
     770           3 :         _cleanup_free_ char *link = NULL;
     771             :         int r;
     772             : 
     773           3 :         r = terminal_urlify_man("systemd-journal-remote.service", "8", &link);
     774           3 :         if (r < 0)
     775           0 :                 return log_oom();
     776             : 
     777           3 :         printf("%s [OPTIONS...] {FILE|-}...\n\n"
     778             :                "Write external journal events to journal file(s).\n\n"
     779             :                "  -h --help                 Show this help\n"
     780             :                "     --version              Show package version\n"
     781             :                "     --url=URL              Read events from systemd-journal-gatewayd at URL\n"
     782             :                "     --getter=COMMAND       Read events from the output of COMMAND\n"
     783             :                "     --listen-raw=ADDR      Listen for connections at ADDR\n"
     784             :                "     --listen-http=ADDR     Listen for HTTP connections at ADDR\n"
     785             :                "     --listen-https=ADDR    Listen for HTTPS connections at ADDR\n"
     786             :                "  -o --output=FILE|DIR      Write output to FILE or DIR/external-*.journal\n"
     787             :                "     --compress[=BOOL]      XZ-compress the output journal (default: yes)\n"
     788             :                "     --seal[=BOOL]          Use event sealing (default: no)\n"
     789             :                "     --key=FILENAME         SSL key in PEM format (default:\n"
     790             :                "                            \"" PRIV_KEY_FILE "\")\n"
     791             :                "     --cert=FILENAME        SSL certificate in PEM format (default:\n"
     792             :                "                            \"" CERT_FILE "\")\n"
     793             :                "     --trust=FILENAME|all   SSL CA certificate or disable checking (default:\n"
     794             :                "                            \"" TRUST_FILE "\")\n"
     795             :                "     --gnutls-log=CATEGORY...\n"
     796             :                "                            Specify a list of gnutls logging categories\n"
     797             :                "     --split-mode=none|host How many output files to create\n"
     798             :                "\nNote: file descriptors from sd_listen_fds() will be consumed, too.\n"
     799             :                "\nSee the %s for details.\n"
     800             :                , program_invocation_short_name
     801             :                , link
     802             :         );
     803             : 
     804           3 :         return 0;
     805             : }
     806             : 
     807           4 : static int parse_argv(int argc, char *argv[]) {
     808             :         enum {
     809             :                 ARG_VERSION = 0x100,
     810             :                 ARG_URL,
     811             :                 ARG_LISTEN_RAW,
     812             :                 ARG_LISTEN_HTTP,
     813             :                 ARG_LISTEN_HTTPS,
     814             :                 ARG_GETTER,
     815             :                 ARG_SPLIT_MODE,
     816             :                 ARG_COMPRESS,
     817             :                 ARG_SEAL,
     818             :                 ARG_KEY,
     819             :                 ARG_CERT,
     820             :                 ARG_TRUST,
     821             :                 ARG_GNUTLS_LOG,
     822             :         };
     823             : 
     824             :         static const struct option options[] = {
     825             :                 { "help",         no_argument,       NULL, 'h'              },
     826             :                 { "version",      no_argument,       NULL, ARG_VERSION      },
     827             :                 { "url",          required_argument, NULL, ARG_URL          },
     828             :                 { "getter",       required_argument, NULL, ARG_GETTER       },
     829             :                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
     830             :                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
     831             :                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
     832             :                 { "output",       required_argument, NULL, 'o'              },
     833             :                 { "split-mode",   required_argument, NULL, ARG_SPLIT_MODE   },
     834             :                 { "compress",     optional_argument, NULL, ARG_COMPRESS     },
     835             :                 { "seal",         optional_argument, NULL, ARG_SEAL         },
     836             :                 { "key",          required_argument, NULL, ARG_KEY          },
     837             :                 { "cert",         required_argument, NULL, ARG_CERT         },
     838             :                 { "trust",        required_argument, NULL, ARG_TRUST        },
     839             :                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
     840             :                 {}
     841             :         };
     842             : 
     843             :         int c, r;
     844             :         bool type_a, type_b;
     845             : 
     846           4 :         assert(argc >= 0);
     847           4 :         assert(argv);
     848             : 
     849           4 :         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
     850           4 :                 switch(c) {
     851             : 
     852           3 :                 case 'h':
     853           3 :                         return help();
     854             : 
     855           0 :                 case ARG_VERSION:
     856           0 :                         return version();
     857             : 
     858           0 :                 case ARG_URL:
     859           0 :                         if (arg_url)
     860           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     861             :                                                        "cannot currently set more than one --url");
     862             : 
     863           0 :                         arg_url = optarg;
     864           0 :                         break;
     865             : 
     866           0 :                 case ARG_GETTER:
     867           0 :                         if (arg_getter)
     868           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     869             :                                                        "cannot currently use --getter more than once");
     870             : 
     871           0 :                         arg_getter = optarg;
     872           0 :                         break;
     873             : 
     874           0 :                 case ARG_LISTEN_RAW:
     875           0 :                         if (arg_listen_raw)
     876           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     877             :                                                        "cannot currently use --listen-raw more than once");
     878             : 
     879           0 :                         arg_listen_raw = optarg;
     880           0 :                         break;
     881             : 
     882           0 :                 case ARG_LISTEN_HTTP:
     883           0 :                         if (arg_listen_http || http_socket >= 0)
     884           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     885             :                                                        "cannot currently use --listen-http more than once");
     886             : 
     887           0 :                         r = negative_fd(optarg);
     888           0 :                         if (r >= 0)
     889           0 :                                 http_socket = r;
     890             :                         else
     891           0 :                                 arg_listen_http = optarg;
     892           0 :                         break;
     893             : 
     894           0 :                 case ARG_LISTEN_HTTPS:
     895           0 :                         if (arg_listen_https || https_socket >= 0)
     896           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     897             :                                                        "cannot currently use --listen-https more than once");
     898             : 
     899           0 :                         r = negative_fd(optarg);
     900           0 :                         if (r >= 0)
     901           0 :                                 https_socket = r;
     902             :                         else
     903           0 :                                 arg_listen_https = optarg;
     904             : 
     905           0 :                         break;
     906             : 
     907           0 :                 case ARG_KEY:
     908           0 :                         if (arg_key)
     909           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     910             :                                                        "Key file specified twice");
     911             : 
     912           0 :                         arg_key = strdup(optarg);
     913           0 :                         if (!arg_key)
     914           0 :                                 return log_oom();
     915             : 
     916           0 :                         break;
     917             : 
     918           0 :                 case ARG_CERT:
     919           0 :                         if (arg_cert)
     920           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     921             :                                                        "Certificate file specified twice");
     922             : 
     923           0 :                         arg_cert = strdup(optarg);
     924           0 :                         if (!arg_cert)
     925           0 :                                 return log_oom();
     926             : 
     927           0 :                         break;
     928             : 
     929           0 :                 case ARG_TRUST:
     930           0 :                         if (arg_trust || arg_trust_all)
     931           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     932             :                                                        "Confusing trusted CA configuration");
     933             : 
     934           0 :                         if (streq(optarg, "all"))
     935           0 :                                 arg_trust_all = true;
     936             :                         else {
     937             : #if HAVE_GNUTLS
     938           0 :                                 arg_trust = strdup(optarg);
     939           0 :                                 if (!arg_trust)
     940           0 :                                         return log_oom();
     941             : #else
     942             :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     943             :                                                        "Option --trust is not available.");
     944             : #endif
     945             :                         }
     946             : 
     947           0 :                         break;
     948             : 
     949           0 :                 case 'o':
     950           0 :                         if (arg_output)
     951           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     952             :                                                        "cannot use --output/-o more than once");
     953             : 
     954           0 :                         arg_output = optarg;
     955           0 :                         break;
     956             : 
     957           0 :                 case ARG_SPLIT_MODE:
     958           0 :                         arg_split_mode = journal_write_split_mode_from_string(optarg);
     959           0 :                         if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID)
     960           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     961             :                                                        "Invalid split mode: %s", optarg);
     962           0 :                         break;
     963             : 
     964           0 :                 case ARG_COMPRESS:
     965           0 :                         if (optarg) {
     966           0 :                                 r = parse_boolean(optarg);
     967           0 :                                 if (r < 0)
     968           0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     969             :                                                                "Failed to parse --compress= parameter.");
     970             : 
     971           0 :                                 arg_compress = !!r;
     972             :                         } else
     973           0 :                                 arg_compress = true;
     974             : 
     975           0 :                         break;
     976             : 
     977           0 :                 case ARG_SEAL:
     978           0 :                         if (optarg) {
     979           0 :                                 r = parse_boolean(optarg);
     980           0 :                                 if (r < 0)
     981           0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     982             :                                                                "Failed to parse --seal= parameter.");
     983             : 
     984           0 :                                 arg_seal = !!r;
     985             :                         } else
     986           0 :                                 arg_seal = true;
     987             : 
     988           0 :                         break;
     989             : 
     990           0 :                 case ARG_GNUTLS_LOG: {
     991             : #if HAVE_GNUTLS
     992           0 :                         const char* p = optarg;
     993           0 :                         for (;;) {
     994           0 :                                 _cleanup_free_ char *word = NULL;
     995             : 
     996           0 :                                 r = extract_first_word(&p, &word, ",", 0);
     997           0 :                                 if (r < 0)
     998           0 :                                         return log_error_errno(r, "Failed to parse --gnutls-log= argument: %m");
     999           0 :                                 if (r == 0)
    1000           0 :                                         break;
    1001             : 
    1002           0 :                                 if (strv_push(&arg_gnutls_log, word) < 0)
    1003           0 :                                         return log_oom();
    1004             : 
    1005           0 :                                 word = NULL;
    1006             :                         }
    1007           0 :                         break;
    1008             : #else
    1009             :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1010             :                                                "Option --gnutls-log is not available.");
    1011             : #endif
    1012             :                 }
    1013             : 
    1014           1 :                 case '?':
    1015           1 :                         return -EINVAL;
    1016             : 
    1017           0 :                 default:
    1018           0 :                         assert_not_reached("Unknown option code.");
    1019             :                 }
    1020             : 
    1021           0 :         if (optind < argc)
    1022           0 :                 arg_files = argv + optind;
    1023             : 
    1024           0 :         type_a = arg_getter || !strv_isempty(arg_files);
    1025           0 :         type_b = arg_url
    1026           0 :                 || arg_listen_raw
    1027           0 :                 || arg_listen_http || arg_listen_https
    1028           0 :                 || sd_listen_fds(false) > 0;
    1029           0 :         if (type_a && type_b)
    1030           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1031             :                                        "Cannot use file input or --getter with "
    1032             :                                        "--arg-listen-... or socket activation.");
    1033           0 :         if (type_a) {
    1034           0 :                 if (!arg_output)
    1035           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1036             :                                                "Option --output must be specified with file input or --getter.");
    1037             : 
    1038           0 :                 if (!IN_SET(arg_split_mode, JOURNAL_WRITE_SPLIT_NONE, _JOURNAL_WRITE_SPLIT_INVALID))
    1039           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1040             :                                                "For active sources, only --split-mode=none is allowed.");
    1041             : 
    1042           0 :                 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
    1043             :         }
    1044             : 
    1045           0 :         if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID)
    1046           0 :                 arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
    1047             : 
    1048           0 :         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE && arg_output) {
    1049           0 :                 if (is_dir(arg_output, true) > 0)
    1050           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1051             :                                                "For SplitMode=none, output must be a file.");
    1052           0 :                 if (!endswith(arg_output, ".journal"))
    1053           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1054             :                                                "For SplitMode=none, output file name must end with .journal.");
    1055             :         }
    1056             : 
    1057           0 :         if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
    1058           0 :             && arg_output && is_dir(arg_output, true) <= 0)
    1059           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1060             :                                        "For SplitMode=host, output must be a directory.");
    1061             : 
    1062           0 :         log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
    1063             :                   journal_write_split_mode_to_string(arg_split_mode),
    1064             :                   strna(arg_key),
    1065             :                   strna(arg_cert),
    1066             :                   strna(arg_trust));
    1067             : 
    1068           0 :         return 1 /* work to do */;
    1069             : }
    1070             : 
    1071           0 : static int load_certificates(char **key, char **cert, char **trust) {
    1072             :         int r;
    1073             : 
    1074           0 :         r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
    1075           0 :         if (r < 0)
    1076           0 :                 return log_error_errno(r, "Failed to read key from file '%s': %m",
    1077             :                                        arg_key ?: PRIV_KEY_FILE);
    1078             : 
    1079           0 :         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
    1080           0 :         if (r < 0)
    1081           0 :                 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
    1082             :                                        arg_cert ?: CERT_FILE);
    1083             : 
    1084           0 :         if (arg_trust_all)
    1085           0 :                 log_info("Certificate checking disabled.");
    1086             :         else {
    1087           0 :                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
    1088           0 :                 if (r < 0)
    1089           0 :                         return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
    1090             :                                                arg_trust ?: TRUST_FILE);
    1091             :         }
    1092             : 
    1093           0 :         if ((arg_listen_raw || arg_listen_http) && *trust)
    1094           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1095             :                                        "Option --trust makes all non-HTTPS connections untrusted.");
    1096             : 
    1097           0 :         return 0;
    1098             : }
    1099             : 
    1100           4 : static int run(int argc, char **argv) {
    1101           4 :         _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
    1102           4 :         _cleanup_(journal_remote_server_destroy) RemoteServer s = {};
    1103           4 :         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
    1104             :         int r;
    1105             : 
    1106           4 :         log_show_color(true);
    1107           4 :         log_parse_environment();
    1108             : 
    1109             :         /* The journal merging logic potentially needs a lot of fds. */
    1110           4 :         (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
    1111             : 
    1112           4 :         r = parse_config();
    1113           4 :         if (r < 0)
    1114           0 :                 return r;
    1115             : 
    1116           4 :         r = parse_argv(argc, argv);
    1117           4 :         if (r <= 0)
    1118           4 :                 return r;
    1119             : 
    1120           0 :         if (arg_listen_http || arg_listen_https) {
    1121           0 :                 r = setup_gnutls_logger(arg_gnutls_log);
    1122           0 :                 if (r < 0)
    1123           0 :                         return r;
    1124             :         }
    1125             : 
    1126           0 :         if (arg_listen_https || https_socket >= 0) {
    1127           0 :                 r = load_certificates(&key, &cert, &trust);
    1128           0 :                 if (r < 0)
    1129           0 :                         return r;
    1130             : 
    1131           0 :                 s.check_trust = !arg_trust_all;
    1132             :         }
    1133             : 
    1134           0 :         r = create_remoteserver(&s, key, cert, trust);
    1135           0 :         if (r < 0)
    1136           0 :                 return r;
    1137             : 
    1138           0 :         r = sd_event_set_watchdog(s.events, true);
    1139           0 :         if (r < 0)
    1140           0 :                 return log_error_errno(r, "Failed to enable watchdog: %m");
    1141             : 
    1142           0 :         log_debug("Watchdog is %sd.", enable_disable(r > 0));
    1143             : 
    1144           0 :         log_debug("%s running as pid "PID_FMT,
    1145             :                   program_invocation_short_name, getpid_cached());
    1146             : 
    1147           0 :         notify_message = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
    1148             : 
    1149           0 :         while (s.active) {
    1150           0 :                 r = sd_event_get_state(s.events);
    1151           0 :                 if (r < 0)
    1152           0 :                         return r;
    1153           0 :                 if (r == SD_EVENT_FINISHED)
    1154           0 :                         break;
    1155             : 
    1156           0 :                 r = sd_event_run(s.events, -1);
    1157           0 :                 if (r < 0)
    1158           0 :                         return log_error_errno(r, "Failed to run event loop: %m");
    1159             :         }
    1160             : 
    1161           0 :         notify_message = NULL;
    1162           0 :         (void) sd_notifyf(false,
    1163             :                           "STOPPING=1\n"
    1164             :                           "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
    1165             : 
    1166           0 :         log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
    1167             : 
    1168           0 :         return 0;
    1169             : }
    1170             : 
    1171           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14